[Checkins] SVN: zope.exceptions/trunk/ Merge tseaver-no_2to3 branch.
Tres Seaver
cvs-admin at zope.org
Tue Apr 17 15:45:10 UTC 2012
Log message for revision 125160:
Merge tseaver-no_2to3 branch.
Changed:
_U zope.exceptions/trunk/
U zope.exceptions/trunk/.bzrignore
U zope.exceptions/trunk/CHANGES.txt
A zope.exceptions/trunk/docs/
U zope.exceptions/trunk/docs/Makefile
U zope.exceptions/trunk/docs/api.rst
U zope.exceptions/trunk/docs/conf.py
U zope.exceptions/trunk/docs/index.rst
U zope.exceptions/trunk/docs/make.bat
U zope.exceptions/trunk/docs/narr.rst
A zope.exceptions/trunk/setup.cfg
U zope.exceptions/trunk/setup.py
U zope.exceptions/trunk/src/zope/exceptions/__init__.py
U zope.exceptions/trunk/src/zope/exceptions/exceptionformatter.py
U zope.exceptions/trunk/src/zope/exceptions/interfaces.py
U zope.exceptions/trunk/src/zope/exceptions/log.py
U zope.exceptions/trunk/src/zope/exceptions/tests/test_exceptionformatter.py
A zope.exceptions/trunk/src/zope/exceptions/tests/test_log.py
A zope.exceptions/trunk/tox.ini
-=-
Property changes on: zope.exceptions/trunk
___________________________________________________________________
Added: svn:mergeinfo
+ /zope.exceptions/branches/tseaver-no_2to3:125005,125012-125039
Added: svk:merge
+ 62d5b8a3-27da-0310-9561-8e5933582275:/zope.exceptions/branches/tseaver-no_2to3:125039
Modified: zope.exceptions/trunk/.bzrignore
===================================================================
--- zope.exceptions/trunk/.bzrignore 2012-04-17 15:39:44 UTC (rev 125159)
+++ zope.exceptions/trunk/.bzrignore 2012-04-17 15:45:06 UTC (rev 125160)
@@ -4,3 +4,6 @@
./eggs
./parts
*.egg-info
+.coverage
+__pycache__
+docs/_build
Modified: zope.exceptions/trunk/CHANGES.txt
===================================================================
--- zope.exceptions/trunk/CHANGES.txt 2012-04-17 15:39:44 UTC (rev 125159)
+++ zope.exceptions/trunk/CHANGES.txt 2012-04-17 15:45:06 UTC (rev 125160)
@@ -2,12 +2,28 @@
Changes
=======
-3.7.2 (unreleased)
+4.0.0 (unreleased)
------------------
-- Nothing changed yet.
+- Added Sphinx documentation.
+- Added support for continuous integration using ``tox`` and ``jenkins``.
+- Removed use of '2to3' and associated fixers when installing under Py3k.
+ The code is now in a "compatible subset" which supports Python 2.6, 2.7,
+ and 3.2, including PyPy 1.8 (the version compatible with the 2.7 language
+ spec).
+
+- 100% unit test coverage.
+
+- Dropped explicit support for Python 2.4 / 2.5 / 3.1.
+
+- Added 'setup.py dev' alias (runs ``setup.py develop`` plus installs
+ ``nose`` and ``coverage``).
+
+- Added 'setup.py docs' alias (installs ``Sphinx`` and dependencies).
+
+
3.7.1 (2012-03-28)
------------------
Copied: zope.exceptions/trunk/setup.cfg (from rev 125039, zope.exceptions/branches/tseaver-no_2to3/setup.cfg)
===================================================================
--- zope.exceptions/trunk/setup.cfg (rev 0)
+++ zope.exceptions/trunk/setup.cfg 2012-04-17 15:45:06 UTC (rev 125160)
@@ -0,0 +1,10 @@
+[nosetests]
+nocapture=1
+cover-package=zope.exceptions
+cover-erase=1
+with-doctest=0
+where=src
+
+[aliases]
+dev = develop easy_install zope.exceptions[testing]
+docs = easy_install zope.exceptions[docs]
Modified: zope.exceptions/trunk/setup.py
===================================================================
--- zope.exceptions/trunk/setup.py 2012-04-17 15:39:44 UTC (rev 125159)
+++ zope.exceptions/trunk/setup.py 2012-04-17 15:45:06 UTC (rev 125160)
@@ -21,23 +21,20 @@
import os
from setuptools import setup, find_packages
import sys
-if sys.version_info < (3, ):
- extra = {}
-else:
- # Python 3 support:
- extra = dict(
- use_2to3=True,
- setup_requires=['zope.fixers'],
- use_2to3_fixers = ['zope.fixers'],
- )
+extra = {
+ 'extras_require': {'docs': ['Sphinx', 'repoze.sphinx.autointerface'],
+ 'testing': ['nose', 'coverage'],
+ }
+}
+
def read(*rnames):
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
setup(name='zope.exceptions',
- version='3.7.2.dev0',
+ version='4.0dev',
author='Zope Foundation and Contributors',
author_email='zope-dev at zope.org',
description='Zope Exceptions',
@@ -50,13 +47,12 @@
'Intended Audience :: Developers',
'License :: OSI Approved :: Zope Public License',
'Programming Language :: Python',
- 'Programming Language :: Python :: 2.4',
- 'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.1',
'Programming Language :: Python :: 3.2',
+ "Programming Language :: Python :: Implementation :: CPython",
+ "Programming Language :: Python :: Implementation :: PyPy",
'Natural Language :: English',
'Operating System :: OS Independent',
'Topic :: Internet :: WWW/HTTP',
Modified: zope.exceptions/trunk/src/zope/exceptions/__init__.py
===================================================================
--- zope.exceptions/trunk/src/zope/exceptions/__init__.py 2012-04-17 15:39:44 UTC (rev 125159)
+++ zope.exceptions/trunk/src/zope/exceptions/__init__.py 2012-04-17 15:45:06 UTC (rev 125160)
@@ -16,17 +16,26 @@
These exceptions are so general purpose that they don't belong in Zope
application-specific packages.
"""
-from zope.exceptions.interfaces import DuplicationError, IDuplicationError
-from zope.exceptions.interfaces import UserError, IUserError
+from zope.exceptions.interfaces import DuplicationError
+from zope.exceptions.interfaces import IDuplicationError
+from zope.exceptions.interfaces import UserError
+from zope.exceptions.interfaces import IUserError
+from zope.exceptions.exceptionformatter import format_exception
+from zope.exceptions.exceptionformatter import print_exception
+from zope.exceptions.exceptionformatter import extract_stack
+
# avoid dependency on zope.security:
try:
import zope.security
-except ImportError, v:
+except ImportError as v: #pragma NO COVER
# "ImportError: No module named security"
if not str(v).endswith('security'):
raise
-else:
- from zope.security.interfaces import IUnauthorized, Unauthorized
- from zope.security.interfaces import IForbidden, IForbiddenAttribute
- from zope.security.interfaces import Forbidden, ForbiddenAttribute
+else: #pragma NO COVER
+ from zope.security.interfaces import IUnauthorized
+ from zope.security.interfaces import Unauthorized
+ from zope.security.interfaces import IForbidden
+ from zope.security.interfaces import IForbiddenAttribute
+ from zope.security.interfaces import Forbidden
+ from zope.security.interfaces import ForbiddenAttribute
Modified: zope.exceptions/trunk/src/zope/exceptions/exceptionformatter.py
===================================================================
--- zope.exceptions/trunk/src/zope/exceptions/exceptionformatter.py 2012-04-17 15:39:44 UTC (rev 125159)
+++ zope.exceptions/trunk/src/zope/exceptions/exceptionformatter.py 2012-04-17 15:45:06 UTC (rev 125160)
@@ -25,7 +25,6 @@
class TextExceptionFormatter(object):
line_sep = '\n'
- show_revisions = 0
def __init__(self, limit=None, with_filenames=False):
self.limit = limit
@@ -84,17 +83,16 @@
try:
extra = getInfo()
if extra:
- extra = self.escape(extra)
- if self.line_sep != "\n":
- extra = extra.replace(" ", " ")
- extra = extra.replace("\n", self.line_sep)
- result.append(extra)
- except:
+ result.append(self.formatSupplementInfo(extra))
+ except: #pragma NO COVER
if DEBUG_EXCEPTION_FORMATTER:
traceback.print_exc()
# else just swallow the exception.
return result
+ def formatSupplementInfo(self, info):
+ return self.escape(info)
+
def formatTracebackInfo(self, tbi):
return self.formatSupplementLine('__traceback_info__: %s' % (tbi, ))
@@ -105,13 +103,14 @@
elif not tb and f:
lineno = f.f_lineno
else:
- raise ValueError("tb or f needs to be passed")
+ raise ValueError("Pass exactly one of tb or f")
co = f.f_code
filename = co.co_filename
name = co.co_name
- locals = f.f_locals
- globals = f.f_globals
+ locals = f.f_locals # XXX shadowing normal builtins deliberately?
+ globals = f.f_globals # XXX shadowing normal builtins deliberately?
+
if self.with_filenames:
s = ' File "%s", line %d' % (filename, lineno)
else:
@@ -144,7 +143,7 @@
try:
supp = factory(*args)
result.extend(self.formatSupplement(supp, tb))
- except:
+ except: #pragma NO COVER
if DEBUG_EXCEPTION_FORMATTER:
traceback.print_exc()
# else just swallow the exception.
@@ -153,7 +152,7 @@
tbi = locals.get('__traceback_info__', None)
if tbi is not None:
result.append(self.formatTracebackInfo(tbi))
- except:
+ except: #pragma NO COVER
if DEBUG_EXCEPTION_FORMATTER:
traceback.print_exc()
# else just swallow the exception.
@@ -176,7 +175,8 @@
while tb is not None and (limit is None or n < limit):
if tb.tb_frame.f_locals.get('__exception_formatter__'):
# Stop recursion.
- result.append('(Recursive formatException() stopped, trying traceback.format_tb)\n')
+ result.append('(Recursive formatException() stopped, '
+ 'trying traceback.format_tb)\n')
result.extend(traceback.format_tb(tb))
break
line = self.formatLine(tb=tb)
@@ -216,11 +216,17 @@
return cgi.escape(s)
def getPrefix(self):
- return '<p>Traceback (most recent call last):\r\n<ul>'
+ return '<p>Traceback (most recent call last):</p>\r\n<ul>'
def formatSupplementLine(self, line):
return '<b>%s</b>' % self.escape(str(line))
+ def formatSupplementInfo(self, info):
+ info = self.escape(info)
+ info = info.replace(" ", " ")
+ info = info.replace("\n", self.line_sep)
+ return info
+
def formatTracebackInfo(self, tbi):
s = self.escape(str(tbi))
s = s.replace('\n', self.line_sep)
@@ -231,7 +237,7 @@
return '<li>%s</li>' % line
def formatLastLine(self, exc_line):
- return '</ul>%s</p>' % self.escape(exc_line)
+ return '</ul><p>%s</p>' % self.escape(exc_line)
def format_exception(t, v, tb, limit=None, as_html=False,
@@ -257,7 +263,7 @@
information to the traceback and accepts two options, 'as_html'
and 'with_filenames'.
"""
- if file is None:
+ if file is None: #pragma NO COVER
file = sys.stderr
lines = format_exception(t, v, tb, limit, as_html, with_filenames)
for line in lines:
Modified: zope.exceptions/trunk/src/zope/exceptions/interfaces.py
===================================================================
--- zope.exceptions/trunk/src/zope/exceptions/interfaces.py 2012-04-17 15:39:44 UTC (rev 125159)
+++ zope.exceptions/trunk/src/zope/exceptions/interfaces.py 2012-04-17 15:45:06 UTC (rev 125160)
@@ -28,16 +28,18 @@
effort to clearly present the information provided by the
ITracebackSupplement.
"""
-from zope.interface import Interface, Attribute, implements
+from zope.interface import Interface
+from zope.interface import Attribute
+from zope.interface import implementer
class IDuplicationError(Interface):
pass
+ at implementer(IDuplicationError)
class DuplicationError(Exception):
"""A duplicate registration was attempted"""
- implements(IDuplicationError)
class IUserError(Interface):
@@ -45,13 +47,13 @@
"""
+ at implementer(IUserError)
class UserError(Exception):
"""User errors
These exceptions should generally be displayed to users unless
they are handled.
"""
- implements(IUserError)
class ITracebackSupplement(Interface):
@@ -102,10 +104,6 @@
itself provides enough information.
""")
- def getInfo(as_html=0):
+ def getInfo():
"""Optional. Returns a string containing any other useful info.
-
- If as_html is set, the implementation must HTML-quote the result
- (normally using cgi.escape()). Returns None to provide no
- extra info.
"""
Modified: zope.exceptions/trunk/src/zope/exceptions/log.py
===================================================================
--- zope.exceptions/trunk/src/zope/exceptions/log.py 2012-04-17 15:39:44 UTC (rev 125159)
+++ zope.exceptions/trunk/src/zope/exceptions/log.py 2012-04-17 15:45:06 UTC (rev 125160)
@@ -15,7 +15,10 @@
"""
import logging
-import cStringIO
+try:
+ from StringIO import StringIO
+except ImportError:
+ from io import StringIO
from zope.exceptions.exceptionformatter import print_exception
@@ -27,7 +30,7 @@
Uses zope.exceptions.exceptionformatter to generate the traceback.
"""
- sio = cStringIO.StringIO()
+ sio = StringIO()
print_exception(ei[0], ei[1], ei[2], file=sio, with_filenames=True)
s = sio.getvalue()
if s.endswith("\n"):
Modified: zope.exceptions/trunk/src/zope/exceptions/tests/test_exceptionformatter.py
===================================================================
--- zope.exceptions/trunk/src/zope/exceptions/tests/test_exceptionformatter.py 2012-04-17 15:39:44 UTC (rev 125159)
+++ zope.exceptions/trunk/src/zope/exceptions/tests/test_exceptionformatter.py 2012-04-17 15:45:06 UTC (rev 125160)
@@ -13,166 +13,539 @@
##############################################################################
"""ExceptionFormatter tests.
"""
+import unittest
-import sys
-from unittest import TestCase, makeSuite
-from zope.exceptions.exceptionformatter import format_exception
-from zope.exceptions.exceptionformatter import extract_stack
+class TextExceptionFormatterTests(unittest.TestCase):
+ def _getTargetClass(self):
+ from zope.exceptions.exceptionformatter import TextExceptionFormatter
+ return TextExceptionFormatter
-def tb(as_html=0):
- t, v, b = sys.exc_info()
- try:
- return ''.join(format_exception(t, v, b, as_html=as_html))
- finally:
- del b
+ def _makeOne(self, *args, **kw):
+ return self._getTargetClass()(*args, **kw)
-def st(as_html=0):
- f = sys.exc_info()[2].tb_frame
- try:
- return ''.join(extract_stack(f, as_html=as_html))
- finally:
- del f
+ def test_ctor_defaults(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.line_sep, '\n')
+ self.assertEqual(fmt.limit, None)
+ self.assertEqual(fmt.with_filenames, False)
-class ExceptionForTesting (Exception):
- pass
+ def test_ctor_explicit(self):
+ fmt = self._makeOne(limit=20, with_filenames=True)
+ self.assertEqual(fmt.line_sep, '\n')
+ self.assertEqual(fmt.limit, 20)
+ self.assertEqual(fmt.with_filenames, True)
+ def test_escape(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.escape('XXX'), 'XXX')
-class TestingTracebackSupplement(object):
+ def test_getPrefix(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.getPrefix(),
+ 'Traceback (most recent call last):')
- source_url = '/somepath'
- line = 634
- column = 57
- warnings = ['Repent, for the end is nigh']
+ def test_getLimit_default(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.getLimit(), 200)
- def __init__(self, expression):
- self.expression = expression
+ def test_getLimit_sys_has_limit(self):
+ import sys
+ fmt = self._makeOne()
+ with _Monkey(sys, tracebacklimit=15):
+ self.assertEqual(fmt.getLimit(), 15)
+ def test_getLimit_explicit(self):
+ fmt = self._makeOne(limit=10)
+ self.assertEqual(fmt.getLimit(), 10)
-class Test(TestCase):
+ def test_formatSupplementLine(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.formatSupplementLine('XXX'), ' - XXX')
- def testBasicNamesText(self, as_html=0):
+ def test_formatSourceURL(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.formatSourceURL('http://example.com/'),
+ [' - http://example.com/'])
+
+ def test_formatSupplement_no_info(self):
+ fmt = self._makeOne()
+ supplement = DummySupplement()
+ self.assertEqual(fmt.formatSupplement(supplement, tb=None), [])
+
+ def test_formatSupplement_w_source_url(self):
+ fmt = self._makeOne()
+ supplement = DummySupplement()
+ supplement.source_url = 'http://example.com/'
+ self.assertEqual(fmt.formatSupplement(supplement, tb=None),
+ [' - http://example.com/'])
+
+ def test_formatSupplement_w_line_as_marker(self):
+ fmt = self._makeOne()
+ supplement = DummySupplement()
+ supplement.line = -1
+ tb = DummyTB()
+ self.assertEqual(fmt.formatSupplement(supplement, tb=tb),
+ [' - Line 14'])
+
+ def test_formatSupplement_w_line_no_column(self):
+ fmt = self._makeOne()
+ supplement = DummySupplement()
+ supplement.line = 23
+ self.assertEqual(fmt.formatSupplement(supplement, tb=None),
+ [' - Line 23'])
+
+ def test_formatSupplement_w_column_no_line(self):
+ fmt = self._makeOne()
+ supplement = DummySupplement()
+ supplement.column = 47
+ self.assertEqual(fmt.formatSupplement(supplement, tb=None),
+ [' - Column 47'])
+
+ def test_formatSupplement_w_line_and_column(self):
+ fmt = self._makeOne()
+ supplement = DummySupplement()
+ supplement.line = 23
+ supplement.column = 47
+ self.assertEqual(fmt.formatSupplement(supplement, tb=None),
+ [' - Line 23, Column 47'])
+
+ def test_formatSupplement_w_expression(self):
+ fmt = self._makeOne()
+ supplement = DummySupplement()
+ supplement.expression = 'a*x^2 + b*x + c'
+ self.assertEqual(fmt.formatSupplement(supplement, tb=None),
+ [' - Expression: a*x^2 + b*x + c'])
+
+ def test_formatSupplement_w_warnings(self):
+ fmt = self._makeOne()
+ supplement = DummySupplement()
+ supplement.warnings = ['Beware the ides of March!',
+ 'You\'re gonna get wasted.',
+ ]
+ self.assertEqual(fmt.formatSupplement(supplement, tb=None),
+ [' - Warning: Beware the ides of March!',
+ ' - Warning: You\'re gonna get wasted.',
+ ])
+
+ def test_formatSupplement_w_getInfo_empty(self):
+ fmt = self._makeOne()
+ supplement = DummySupplement()
+ self.assertEqual(fmt.formatSupplement(supplement, tb=None), [])
+
+ def test_formatSupplement_w_getInfo_text(self):
+ INFO = 'Some days\nI wish I had stayed in bed.'
+ fmt = self._makeOne()
+ supplement = DummySupplement(INFO)
+ self.assertEqual(fmt.formatSupplement(supplement, tb=None), [INFO])
+
+ def test_formatSupplementInfo(self):
+ INFO = 'Some days\nI wish I had stayed in bed.'
+ fmt = self._makeOne()
+ self.assertEqual(fmt.formatSupplementInfo(INFO), INFO)
+
+ def test_formatTracebackInfo(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.formatTracebackInfo('XYZZY'),
+ ' - __traceback_info__: XYZZY')
+
+ def test_formatLine_no_tb_no_f(self):
+ fmt = self._makeOne()
+ self.assertRaises(ValueError, fmt.formatLine, None, None)
+
+ def test_formatLine_w_tb_and_f(self):
+ fmt = self._makeOne()
+ tb = DummyTB()
+ f = DummyFrame()
+ self.assertRaises(ValueError, fmt.formatLine, tb, f)
+
+ def test_formatLine_w_tb_bogus_linecache_w_filenames(self):
+ fmt = self._makeOne(with_filenames=True)
+ tb = DummyTB()
+ tb.tb_frame = f = DummyFrame()
+ lines = fmt.formatLine(tb).splitlines()
+ self.assertEqual(len(lines), 1)
+ self.assertEqual(lines[0],
+ ' File "%s", line %d, in %s'
+ % (f.f_code.co_filename,
+ tb.tb_lineno,
+ f.f_code.co_name,
+ ))
+
+ def test_formatLine_w_f_bogus_linecache_w_filenames(self):
+ fmt = self._makeOne(with_filenames=True)
+ f = DummyFrame()
+ lines = fmt.formatLine(f=f).splitlines()
+ self.assertEqual(len(lines), 1)
+ self.assertEqual(lines[0],
+ ' File "%s", line %d, in %s'
+ % (f.f_code.co_filename,
+ f.f_lineno,
+ f.f_code.co_name,
+ ))
+
+ def test_formatLine_w_tb_bogus_linecache_wo_filenames(self):
+ fmt = self._makeOne(with_filenames=False)
+ tb = DummyTB()
+ tb.tb_frame = f = DummyFrame()
+ f.f_globals['__name__'] = 'dummy.filename'
+ lines = fmt.formatLine(tb).splitlines()
+ self.assertEqual(len(lines), 1)
+ self.assertEqual(lines[0],
+ ' Module dummy.filename, line %d, in %s'
+ % (tb.tb_lineno,
+ f.f_code.co_name,
+ ))
+
+ def test_formatLine_w_f_real_linecache_w_filenames(self):
+ import sys
+ fmt = self._makeOne(with_filenames=True)
+ f = sys._getframe(); lineno = f.f_lineno
+ result = fmt.formatLine(f=f)
+ lines = result.splitlines()
+ self.assertEqual(len(lines), 2)
+ self.assertEqual(lines[0],
+ ' File "%s", line %d, in %s'
+ % (f.f_code.co_filename,
+ lineno + 1,
+ f.f_code.co_name,
+ ))
+ self.assertEqual(lines[1],
+ ' result = fmt.formatLine(f=f)')
+
+ def test_formatLine_w_supplement_in_locals(self):
+ INFO_L = 'I wish I had stayed in bed.'
+ INFO_G = 'I would rather soak my head.'
+ fmt = self._makeOne(with_filenames=False)
+ tb = DummyTB()
+ tb.tb_frame = f = DummyFrame()
+ f.f_globals['__name__'] = 'dummy.filename'
+ f.f_locals['__traceback_supplement__'] = (DummySupplement, INFO_L)
+ f.f_globals['__traceback_supplement__'] = (DummySupplement, INFO_G)
+ lines = fmt.formatLine(tb).splitlines()
+ self.assertEqual(len(lines), 2)
+ self.assertEqual(lines[1], INFO_L)
+
+ def test_formatLine_w_supplement_in_globals(self):
+ INFO_G = 'I would rather soak my head.'
+ fmt = self._makeOne(with_filenames=False)
+ tb = DummyTB()
+ tb.tb_frame = f = DummyFrame()
+ f.f_globals['__name__'] = 'dummy.filename'
+ f.f_globals['__traceback_supplement__'] = (DummySupplement, INFO_G)
+ lines = fmt.formatLine(tb).splitlines()
+ self.assertEqual(len(lines), 2)
+ self.assertEqual(lines[1], INFO_G)
+
+ def test_formatLine_w_traceback_info(self):
+ INFO_T = 'I would rather soak my head.'
+ fmt = self._makeOne(with_filenames=False)
+ tb = DummyTB()
+ tb.tb_frame = f = DummyFrame()
+ f.f_globals['__name__'] = 'dummy.filename'
+ f.f_locals['__traceback_info__'] = INFO_T
+ lines = fmt.formatLine(tb).splitlines()
+ self.assertEqual(len(lines), 2)
+ self.assertEqual(lines[1], ' - __traceback_info__: %s' % INFO_T)
+
+ def test_formatExceptionOnly(self):
+ import traceback
+ fmt = self._makeOne()
+ err = ValueError('testing')
+ self.assertEqual(fmt.formatExceptionOnly(ValueError, err),
+ ''.join(
+ traceback.format_exception_only(ValueError, err)))
+
+ def test_formatLastLine(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.formatLastLine('XXX'), 'XXX')
+
+ def test_formatException_empty_tb_stack(self):
+ import traceback
+ fmt = self._makeOne()
+ err = ValueError('testing')
+ lines = fmt.formatException(ValueError, err, None)
+ self.assertEqual(len(lines), 2)
+ self.assertEqual(lines[0], 'Traceback (most recent call last):\n')
+ self.assertEqual(lines[1],
+ ''.join(
+ traceback.format_exception_only(ValueError, err)))
+
+ def test_formatException_non_empty_tb_stack(self):
+ import traceback
+ fmt = self._makeOne()
+ err = ValueError('testing')
+ tb = DummyTB()
+ tb.tb_frame = DummyFrame()
+ lines = fmt.formatException(ValueError, err, tb)
+ self.assertEqual(len(lines), 3)
+ self.assertEqual(lines[0], 'Traceback (most recent call last):\n')
+ self.assertEqual(lines[1], ' Module dummy/filename.py, line 14, '
+ 'in dummy_function\n')
+ self.assertEqual(lines[2],
+ ''.join(
+ traceback.format_exception_only(ValueError, err)))
+
+ def test_formatException_deep_tb_stack_with_limit(self):
+ import traceback
+ fmt = self._makeOne(limit=1)
+ err = ValueError('testing')
+ tb0 = DummyTB()
+ tb0.tb_lineno = 27
+ tb0.tb_frame = DummyFrame()
+ tb = DummyTB()
+ tb.tb_frame = DummyFrame()
+ tb.tb_next = tb0
+ lines = fmt.formatException(ValueError, err, tb)
+ self.assertEqual(len(lines), 3)
+ self.assertEqual(lines[0], 'Traceback (most recent call last):\n')
+ self.assertEqual(lines[1], ' Module dummy/filename.py, line 14, '
+ 'in dummy_function\n')
+ self.assertEqual(lines[2],
+ ''.join(
+ traceback.format_exception_only(ValueError, err)))
+
+ def test_formatException_recursion_in_tb_stack(self):
+ import traceback
+ fmt = self._makeOne()
+ err = ValueError('testing')
+ tb_recurse = DummyTB()
+ tb_recurse.tb_lineno = 27
+ r_f = tb_recurse.tb_frame = DummyFrame()
+ r_f.f_lineno = 27
+ r_f.f_locals['__exception_formatter__'] = 1
+ tb = DummyTB()
+ tb.tb_frame = DummyFrame()
+ tb.tb_next = tb_recurse
+ lines = fmt.formatException(ValueError, err, tb)
+ self.assertEqual(len(lines), 5)
+ self.assertEqual(lines[0], 'Traceback (most recent call last):\n')
+ self.assertEqual(lines[1], ' Module dummy/filename.py, line 14, '
+ 'in dummy_function\n')
+ self.assertEqual(lines[2], '(Recursive formatException() stopped, '
+ 'trying traceback.format_tb)\n')
+ self.assertEqual(lines[3], ' File "dummy/filename.py", line 27, '
+ 'in dummy_function\n')
+ self.assertEqual(lines[4],
+ ''.join(
+ traceback.format_exception_only(ValueError, err)))
+
+ def test_extractStack_wo_frame(self):
+ import sys
+ fmt = self._makeOne(limit=1)
+ f = sys._getframe(); lineno = f.f_lineno
+ lines = fmt.extractStack()
+ self.assertEqual(len(lines), 1)
+ self.assertEqual(lines[0], ' Module '
+ 'zope.exceptions.tests.test_exceptionformatter, '
+ 'line %d, in test_extractStack_wo_frame\n'
+ ' lines = fmt.extractStack()\n' % (lineno + 1))
+
+ def test_extractStack_w_single_frame(self):
+ fmt = self._makeOne()
+ f = DummyFrame()
+ lines = fmt.extractStack(f)
+ self.assertEqual(len(lines), 1)
+ self.assertEqual(lines[0], ' Module dummy/filename.py, line 137, '
+ 'in dummy_function\n')
+
+ def test_extractStack_w_multiple_frames_and_limit(self):
+ fmt = self._makeOne(limit=1)
+ f0 = DummyFrame()
+ f0.f_lineno = 213
+ f = DummyFrame()
+ f.f_back = f0
+ lines = fmt.extractStack(f)
+ self.assertEqual(len(lines), 1)
+ self.assertEqual(lines[0], ' Module dummy/filename.py, line 137, '
+ 'in dummy_function\n')
+
+ def test_extractStack_w_recursive_frames_and_limit(self):
+ fmt = self._makeOne(limit=1)
+ f = DummyFrame()
+ f.f_back = f
+ lines = fmt.extractStack(f)
+ self.assertEqual(len(lines), 1)
+ self.assertEqual(lines[0], ' Module dummy/filename.py, line 137, '
+ 'in dummy_function\n')
+
+
+class HTMLExceptionFormatterTests(unittest.TestCase):
+
+ def _getTargetClass(self):
+ from zope.exceptions.exceptionformatter import HTMLExceptionFormatter
+ return HTMLExceptionFormatter
+
+ def _makeOne(self, *args, **kw):
+ return self._getTargetClass()(*args, **kw)
+
+ def test_ctor_defaults(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.line_sep, '<br />\r\n')
+ self.assertEqual(fmt.limit, None)
+ self.assertEqual(fmt.with_filenames, False)
+
+ def test_ctor_explicit(self):
+ fmt = self._makeOne(limit=20, with_filenames=True)
+ self.assertEqual(fmt.line_sep, '<br />\r\n')
+ self.assertEqual(fmt.limit, 20)
+ self.assertEqual(fmt.with_filenames, True)
+
+ def test_escape_simple(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.escape('XXX'), 'XXX')
+
+ def test_escape_w_markup(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.escape('<span>XXX & YYY<span>'),
+ '<span>XXX & YYY<span>')
+
+ def test_getPrefix(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.getPrefix(),
+ '<p>Traceback (most recent call last):</p>\r\n<ul>')
+
+ def test_formatSupplementLine(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.formatSupplementLine('XXX'), '<b>XXX</b>')
+
+ def test_formatSupplementLine_w_markup(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.formatSupplementLine('XXX & YYY'),
+ '<b>XXX & YYY</b>')
+
+ def test_formatSupplementInfo_simple(self):
+ INFO = 'Some days\nI wonder.'
+ fmt = self._makeOne()
+ self.assertEqual(fmt.formatSupplementInfo(INFO),
+ 'Some days<br />\r\nI wonder.')
+
+ def test_formatSupplementInfo_w_markup(self):
+ INFO = 'Some days\nI wonder, <b>Why?</b>.'
+ fmt = self._makeOne()
+ self.assertEqual(fmt.formatSupplementInfo(INFO),
+ 'Some days<br />\r\nI wonder, '
+ '<b>Why?</b>.')
+
+ def test_formatTracebackInfo(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.formatTracebackInfo('XXX & YYY\nZZZ'),
+ '__traceback_info__: XXX & YYY<br />\r\nZZZ')
+
+ def test_formatLine_simple(self):
+ fmt = self._makeOne(with_filenames=True)
+ tb = DummyTB()
+ tb.tb_frame = f = DummyFrame()
+ result = fmt.formatLine(tb)
+ self.assertEqual(result,
+ '<li> File "%s", line %d, in %s</li>'
+ % (f.f_code.co_filename,
+ tb.tb_lineno,
+ f.f_code.co_name,
+ ))
+
+ def test_formatLastLine(self):
+ fmt = self._makeOne()
+ self.assertEqual(fmt.formatLastLine('XXX'), '</ul><p>XXX</p>')
+
+
+class Test_format_exception(unittest.TestCase):
+
+ def _callFUT(self, as_html=False):
+ import sys
+ from zope.exceptions.exceptionformatter import format_exception
+ t, v, b = sys.exc_info()
try:
+ return ''.join(format_exception(t, v, b, as_html=as_html))
+ finally:
+ del b
+
+ def test_basic_names_text(self):
+ try:
raise ExceptionForTesting
except ExceptionForTesting:
- s = tb(as_html)
- # The traceback should include the name of this function.
- self.assertTrue(s.find('testBasicNamesText') >= 0)
- # The traceback should include the name of the exception.
- self.assertTrue(s.find('ExceptionForTesting') >= 0)
- else:
- self.fail('no exception occurred')
+ s = self._callFUT(False)
+ # The traceback should include the name of this function.
+ self.assertTrue(s.find('test_basic_names_text') >= 0)
+ # The traceback should include the name of the exception.
+ self.assertTrue(s.find('ExceptionForTesting') >= 0)
- def testBasicNamesHTML(self):
- self.testBasicNamesText(1)
-
- def testBasicNamesText_stack(self, as_html=0):
+ def test_basic_names_html(self):
try:
raise ExceptionForTesting
except ExceptionForTesting:
- s = st(as_html)
- # The stack trace should include the name of this function.
- self.assertTrue(s.find('testBasicNamesText_stack') >= 0)
- else:
- self.fail('no exception occurred')
+ s = self._callFUT(True)
+ # The traceback should include the name of this function.
+ self.assertTrue(s.find('test_basic_names_html') >= 0)
+ # The traceback should include the name of the exception.
+ self.assertTrue(s.find('ExceptionForTesting') >= 0)
- def testBasicNamesHTML_stack(self):
- self.testBasicNamesText_stack(1)
-
- def testSupplement(self, as_html=0):
+ def test_traceback_info_text(self):
try:
- __traceback_supplement__ = (TestingTracebackSupplement,
- "You're one in a million")
+ __traceback_info__ = "Adam & Eve"
raise ExceptionForTesting
except ExceptionForTesting:
- s = tb(as_html)
- # The source URL
- self.assertTrue(s.find('/somepath') >= 0, s)
- # The line number
- self.assertTrue(s.find('634') >= 0, s)
- # The column number
- self.assertTrue(s.find('57') >= 0, s)
- # The expression
- self.assertTrue(s.find("You're one in a million") >= 0, s)
- # The warning
- self.assertTrue(s.find("Repent, for the end is nigh") >= 0, s)
- else:
- self.fail('no exception occurred')
+ s = self._callFUT(False)
+ self.assertTrue(s.find('Adam & Eve') >= 0, s)
- def testSupplementHTML(self):
- self.testSupplement(1)
-
- def testSupplement_stack(self, as_html=0):
+ def test_traceback_info_html(self):
try:
- __traceback_supplement__ = (TestingTracebackSupplement,
- "You're one in a million")
+ __traceback_info__ = "Adam & Eve"
raise ExceptionForTesting
except ExceptionForTesting:
- s = st(as_html)
- # The source URL
- self.assertTrue(s.find('/somepath') >= 0, s)
- # The line number
- self.assertTrue(s.find('634') >= 0, s)
- # The column number
- self.assertTrue(s.find('57') >= 0, s)
- # The expression
- self.assertTrue(s.find("You're one in a million") >= 0, s)
- # The warning
- self.assertTrue(s.find("Repent, for the end is nigh") >= 0, s)
- else:
- self.fail('no exception occurred')
+ s = self._callFUT(True)
+ # Be sure quoting is happening.
+ self.assertTrue(s.find('Adam & Eve') >= 0, s)
- def testSupplementHTML_stack(self):
- self.testSupplement_stack(1)
-
- def testTracebackInfo(self, as_html=0):
+ def test_traceback_info_is_tuple(self):
try:
- __traceback_info__ = "Adam & Eve"
+ __traceback_info__ = ("Adam", "Eve")
raise ExceptionForTesting
except ExceptionForTesting:
- s = tb(as_html)
- if as_html:
- # Be sure quoting is happening.
- self.assertTrue(s.find('Adam & Eve') >= 0, s)
- else:
- self.assertTrue(s.find('Adam & Eve') >= 0, s)
- else:
- self.fail('no exception occurred')
+ s = self._callFUT(False)
+ self.assertTrue(s.find('Adam') >= 0, s)
+ self.assertTrue(s.find('Eve') >= 0, s)
- def testTracebackInfoHTML(self):
- self.testTracebackInfo(1)
-
- def testTracebackInfo_stack(self, as_html=0):
+ def test_supplement_text(self, as_html=0):
try:
- __traceback_info__ = "Adam & Eve"
+ __traceback_supplement__ = (TestingTracebackSupplement,
+ "You're one in a million")
raise ExceptionForTesting
except ExceptionForTesting:
- s = st(as_html)
- if as_html:
- # Be sure quoting is happening.
- self.assertTrue(s.find('Adam & Eve') >= 0, s)
- else:
- self.assertTrue(s.find('Adam & Eve') >= 0, s)
- else:
- self.fail('no exception occurred')
+ s = self._callFUT(as_html)
+ # The source URL
+ self.assertTrue(s.find('/somepath') >= 0, s)
+ # The line number
+ self.assertTrue(s.find('634') >= 0, s)
+ # The column number
+ self.assertTrue(s.find('57') >= 0, s)
+ # The expression
+ self.assertTrue(s.find("You're one in a million") >= 0, s)
+ # The warning
+ self.assertTrue(s.find("Repent, for the end is nigh") >= 0, s)
- def testTracebackInfoHTML_stack(self):
- self.testTracebackInfo_stack(1)
-
- def testTracebackInfoTuple(self):
+ def test_supplement_html(self):
try:
- __traceback_info__ = ("Adam", "Eve")
+ __traceback_supplement__ = (TestingTracebackSupplement,
+ "You're one in a million")
raise ExceptionForTesting
except ExceptionForTesting:
- s = tb()
- self.assertTrue(s.find('Adam') >= 0, s)
- self.assertTrue(s.find('Eve') >= 0, s)
- else:
- self.fail('no exception occurred')
+ s = self._callFUT(True)
+ # The source URL
+ self.assertTrue(s.find('/somepath') >= 0, s)
+ # The line number
+ self.assertTrue(s.find('634') >= 0, s)
+ # The column number
+ self.assertTrue(s.find('57') >= 0, s)
+ # The expression
+ self.assertTrue(s.find("You're one in a million") >= 0, s)
+ # The warning
+ self.assertTrue(s.find("Repent, for the end is nigh") >= 0, s)
- def testMultipleLevels(self):
- # Makes sure many levels are shown in a traceback.
+ def test_multiple_levels(self):
+ # Ensure many levels are shown in a traceback.
+ HOW_MANY = 10
def f(n):
"""Produces a (n + 1)-level traceback."""
__traceback_info__ = 'level%d' % n
@@ -180,39 +553,35 @@
f(n - 1)
else:
raise ExceptionForTesting
-
try:
- f(10)
+ f(HOW_MANY)
except ExceptionForTesting:
- s = tb()
- for n in range(11):
- self.assertTrue(s.find('level%d' % n) >= 0, s)
- else:
- self.fail('no exception occurred')
+ s = self._callFUT(False)
+ for n in range(HOW_MANY+1):
+ self.assertTrue(s.find('level%d' % n) >= 0, s)
- def testQuoteLastLine(self):
+ def test_quote_last_line(self):
class C(object):
pass
try:
raise TypeError(C())
except:
- s = tb(1)
- else:
- self.fail('no exception occurred')
+ s = self._callFUT(True)
self.assertTrue(s.find('<') >= 0, s)
self.assertTrue(s.find('>') >= 0, s)
- def testMultilineException(self):
+ def test_multiline_exception(self):
try:
- exec 'syntax error\n'
+ exec('syntax error\n')
except Exception:
- s = tb()
- self.assertEqual(s.splitlines()[-3:],
- [' syntax error',
- ' ^',
- 'SyntaxError: invalid syntax'])
+ s = self._callFUT(False)
+ lines = s.splitlines()[-3:]
+ self.assertEqual(lines[0], ' syntax error')
+ self.assertTrue(lines[1].endswith(' ^')) #PyPy has a shorter prefix
+ self.assertEqual(lines[2], 'SyntaxError: invalid syntax')
- def testRecursionFailure(self):
+ def test_recursion_failure(self):
+ import sys
from zope.exceptions.exceptionformatter import TextExceptionFormatter
class FormatterException(Exception):
@@ -229,13 +598,197 @@
try:
fmt.formatException(*sys.exc_info())
except FormatterException:
- s = tb()
+ s = self._callFUT(False)
# Recursion was detected
- self.assertTrue('(Recursive formatException() stopped, trying traceback.format_tb)' in s, s)
+ self.assertTrue('(Recursive formatException() stopped, '
+ 'trying traceback.format_tb)' in s, s)
# and we fellback to the stdlib rather than hid the real error
- self.assertEqual(s.splitlines()[-2], ' raise FormatterException("Formatter failed")')
- self.assertTrue('FormatterException: Formatter failed' in s.splitlines()[-1])
+ self.assertEqual(s.splitlines()[-2],
+ ' raise FormatterException("Formatter failed")')
+ self.assertTrue('FormatterException: Formatter failed'
+ in s.splitlines()[-1])
+class Test_print_exception(unittest.TestCase):
+
+ def _callFUT(self, as_html=False):
+ try:
+ from StringIO import StringIO
+ except ImportError:
+ from io import StringIO
+ buf = StringIO()
+ import sys
+ from zope.exceptions.exceptionformatter import print_exception
+ t, v, b = sys.exc_info()
+ try:
+ print_exception(t, v, b, file=buf, as_html=as_html)
+ return buf.getvalue()
+ finally:
+ del b
+
+ def test_basic_names_text(self):
+ try:
+ raise ExceptionForTesting
+ except ExceptionForTesting:
+ s = self._callFUT(False)
+ # The traceback should include the name of this function.
+ self.assertTrue(s.find('test_basic_names_text') >= 0)
+ # The traceback should include the name of the exception.
+ self.assertTrue(s.find('ExceptionForTesting') >= 0)
+
+ def test_basic_names_html(self):
+ try:
+ raise ExceptionForTesting
+ except ExceptionForTesting:
+ s = self._callFUT(True)
+ # The traceback should include the name of this function.
+ self.assertTrue(s.find('test_basic_names_html') >= 0)
+ # The traceback should include the name of the exception.
+ self.assertTrue(s.find('ExceptionForTesting') >= 0)
+
+
+class Test_extract_stack(unittest.TestCase):
+
+ def _callFUT(self, as_html=False):
+ import sys
+ from zope.exceptions.exceptionformatter import extract_stack
+ f = sys.exc_info()[2].tb_frame
+ try:
+ return ''.join(extract_stack(f, as_html=as_html))
+ finally:
+ del f
+
+ def test_basic_names_as_text(self, as_html=0):
+ try:
+ raise ExceptionForTesting
+ except ExceptionForTesting:
+ s = self._callFUT(False)
+ # The stack trace should include the name of this function.
+ self.assertTrue(s.find('test_basic_names_as_text') >= 0)
+
+ def test_basic_names_as_html(self):
+ try:
+ raise ExceptionForTesting
+ except ExceptionForTesting:
+ s = self._callFUT(True)
+ # The stack trace should include the name of this function.
+ self.assertTrue(s.find('test_basic_names_as_html') >= 0)
+
+ def test_traceback_info_text(self):
+ try:
+ __traceback_info__ = "Adam & Eve"
+ raise ExceptionForTesting
+ except ExceptionForTesting:
+ s = self._callFUT(False)
+ self.assertTrue(s.find('Adam & Eve') >= 0, s)
+
+ def test_traceback_info_html(self):
+ try:
+ __traceback_info__ = "Adam & Eve"
+ raise ExceptionForTesting
+ except ExceptionForTesting:
+ s = self._callFUT(True)
+ self.assertTrue(s.find('Adam & Eve') >= 0, s)
+
+ def test_traceback_supplement_text(self):
+ try:
+ __traceback_supplement__ = (TestingTracebackSupplement,
+ "You're one in a million")
+ raise ExceptionForTesting
+ except ExceptionForTesting:
+ s = self._callFUT(False)
+ # The source URL
+ self.assertTrue(s.find('/somepath') >= 0, s)
+ # The line number
+ self.assertTrue(s.find('634') >= 0, s)
+ # The column number
+ self.assertTrue(s.find('57') >= 0, s)
+ # The expression
+ self.assertTrue(s.find("You're one in a million") >= 0, s)
+ # The warning
+ self.assertTrue(s.find("Repent, for the end is nigh") >= 0, s)
+
+ def test_traceback_supplement_html(self):
+ try:
+ __traceback_supplement__ = (TestingTracebackSupplement,
+ "You're one in a million")
+ raise ExceptionForTesting
+ except ExceptionForTesting:
+ s = self._callFUT(True)
+ # The source URL
+ self.assertTrue(s.find('/somepath') >= 0, s)
+ # The line number
+ self.assertTrue(s.find('634') >= 0, s)
+ # The column number
+ self.assertTrue(s.find('57') >= 0, s)
+ # The expression
+ self.assertTrue(s.find("You're one in a million") >= 0, s)
+ # The warning
+ self.assertTrue(s.find("Repent, for the end is nigh") >= 0, s)
+
+
+class ExceptionForTesting (Exception):
+ pass
+
+
+class TestingTracebackSupplement(object):
+ source_url = '/somepath'
+ line = 634
+ column = 57
+ warnings = ['Repent, for the end is nigh']
+ def __init__(self, expression):
+ self.expression = expression
+
+
+class DummySupplement(object):
+ def __init__(self, info=''):
+ self._info = info
+ def getInfo(self):
+ return self._info
+
+
+class DummyTB(object):
+ tb_lineno = 14
+ tb_next = None
+
+
+class DummyFrame(object):
+ f_lineno = 137
+ f_back = None
+ def __init__(self):
+ self.f_locals = {}
+ self.f_globals = {}
+ self.f_code = DummyCode()
+
+class DummyCode(object):
+ co_filename = 'dummy/filename.py'
+ co_name = 'dummy_function'
+
+class _Monkey(object):
+ # context-manager for replacing module names in the scope of a test.
+ def __init__(self, module, **kw):
+ self.module = module
+ self.to_restore = dict([(key, getattr(module, key, self))
+ for key in kw])
+ for key, value in kw.items():
+ setattr(module, key, value)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ for key, value in self.to_restore.items():
+ if value is not self:
+ setattr(self.module, key, value)
+ else:
+ delattr(self.module, key)
+
+
def test_suite():
- return makeSuite(Test)
+ return unittest.TestSuite((
+ unittest.makeSuite(TextExceptionFormatterTests),
+ unittest.makeSuite(HTMLExceptionFormatterTests),
+ unittest.makeSuite(Test_format_exception),
+ unittest.makeSuite(Test_print_exception),
+ unittest.makeSuite(Test_extract_stack),
+ ))
Copied: zope.exceptions/trunk/src/zope/exceptions/tests/test_log.py (from rev 125039, zope.exceptions/branches/tseaver-no_2to3/src/zope/exceptions/tests/test_log.py)
===================================================================
--- zope.exceptions/trunk/src/zope/exceptions/tests/test_log.py (rev 0)
+++ zope.exceptions/trunk/src/zope/exceptions/tests/test_log.py 2012-04-17 15:45:06 UTC (rev 125160)
@@ -0,0 +1,60 @@
+##############################################################################
+#
+# Copyright (c) 2012 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""log.Formatter tests.
+"""
+import unittest
+
+
+class FormatterTests(unittest.TestCase):
+
+ def _getTargetClass(self):
+ from zope.exceptions.log import Formatter
+ return Formatter
+
+ def _makeOne(self, *args, **kw):
+ return self._getTargetClass()(*args, **kw)
+
+ def test_simple_exception(self):
+ import traceback
+ tb = DummyTB()
+ tb.tb_frame = DummyFrame()
+ exc = ValueError('testing')
+ fmt = self._makeOne()
+ result = fmt.formatException((ValueError, exc, tb))
+ lines = result.splitlines()
+ self.assertEqual(len(lines), 3)
+ self.assertEqual(lines[0], 'Traceback (most recent call last):')
+ self.assertEqual(lines[1], ' File "dummy/filename.py", line 14, '
+ 'in dummy_function')
+ self.assertEqual(lines[2],
+ traceback.format_exception_only(
+ ValueError, exc)[0][:-1]) #trailing \n
+
+
+class DummyTB(object):
+ tb_lineno = 14
+ tb_next = None
+
+
+class DummyFrame(object):
+ f_lineno = 137
+ f_back = None
+ def __init__(self):
+ self.f_locals = {}
+ self.f_globals = {}
+ self.f_code = DummyCode()
+
+class DummyCode(object):
+ co_filename = 'dummy/filename.py'
+ co_name = 'dummy_function'
Copied: zope.exceptions/trunk/tox.ini (from rev 125039, zope.exceptions/branches/tseaver-no_2to3/tox.ini)
===================================================================
--- zope.exceptions/trunk/tox.ini (rev 0)
+++ zope.exceptions/trunk/tox.ini 2012-04-17 15:45:06 UTC (rev 125160)
@@ -0,0 +1,31 @@
+[tox]
+envlist =
+# Jython support pending 2.7 support, due 2012-07-15 or so. See:
+# http://fwierzbicki.blogspot.com/2012/03/adconion-to-fund-jython-27.html
+# py26,py27,py32,jython,pypy,coverage
+ py26,py27,py32,pypy,coverage
+
+[testenv]
+commands =
+ python setup.py test -q
+deps = zope.interface
+
+[testenv:jython]
+commands =
+ jython setup.py test -q
+
+[testenv:coverage]
+basepython =
+ python2.6
+commands =
+# The installed version messes up nose's test discovery / coverage reporting
+# So, we uninstall that from the environment, and then install the editable
+# version, before running nosetests.
+ pip uninstall -y zope.exceptions
+ pip install -e .
+ nosetests --with-xunit --with-xcoverage
+deps =
+ zope.interface
+ nose
+ coverage
+ nosexcover
More information about the checkins
mailing list