comparing with http://code.python.org/hg/branches/py3k/ searching for changes changeset: 9728:10e61b00a0c6 branch: py3k user: Brett Cannon date: Tue Jan 25 10:35:18 2011 -0800 summary: Detect when a test suite changes the trace function. diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -827,7 +827,7 @@ resources = ('sys.argv', 'cwd', 'sys.stdin', 'sys.stdout', 'sys.stderr', 'os.environ', 'sys.path', 'sys.path_hooks', '__import__', 'warnings.filters', 'asyncore.socket_map', - 'logging._handlers', 'logging._handlerList') + 'logging._handlers', 'logging._handlerList', 'sys.gettrace') def get_sys_argv(self): return id(sys.argv), sys.argv, sys.argv[:] @@ -874,6 +874,11 @@ sys.path_hooks = saved_hooks[1] sys.path_hooks[:] = saved_hooks[2] + def get_sys_gettrace(self): + return sys.gettrace() + def restore_sys_gettrace(self, trace_fxn): + sys.settrace(trace_fxn) + def get___import__(self): return builtins.__import__ def restore___import__(self, import_): changeset: 9729:358f5cdec796 branch: py3k user: Brett Cannon date: Tue Jan 25 10:35:54 2011 -0800 summary: Make test_scope not blindly reset the trace function (and in the process make some tests CPython-only). diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py --- a/Lib/test/test_scope.py +++ b/Lib/test/test_scope.py @@ -1,5 +1,5 @@ import unittest -from test.support import check_syntax_error, run_unittest +from test.support import check_syntax_error, cpython_only, run_unittest class ScopeTests(unittest.TestCase): @@ -496,23 +496,22 @@ self.assertNotIn("x", varnames) self.assertIn("y", varnames) + @cpython_only def testLocalsClass_WithTrace(self): # Issue23728: after the trace function returns, the locals() # dictionary is used to update all variables, this used to # include free variables. But in class statements, free # variables are not inserted... import sys + self.addCleanup(sys.settrace, sys.gettrace()) sys.settrace(lambda a,b,c:None) - try: - x = 12 + x = 12 - class C: - def f(self): - return x + class C: + def f(self): + return x - self.assertEqual(x, 12) # Used to raise UnboundLocalError - finally: - sys.settrace(None) + self.assertEqual(x, 12) # Used to raise UnboundLocalError def testBoundAndFree(self): # var is bound and free in class @@ -527,6 +526,7 @@ inst = f(3)() self.assertEqual(inst.a, inst.m()) + @cpython_only def testInteractionWithTraceFunc(self): import sys @@ -543,6 +543,7 @@ class TestClass: pass + self.addCleanup(sys.settrace, sys.gettrace()) sys.settrace(tracer) adaptgetter("foo", TestClass, (1, "")) sys.settrace(None) changeset: 9739:ef221c01d97a branch: py3k parent: 9729:358f5cdec796 user: Brett Cannon date: Tue Jan 25 10:37:11 2011 -0800 summary: Incomplete attempt at fixing test_sys_settrace for coverage. diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -251,6 +251,7 @@ def setUp(self): self.using_gc = gc.isenabled() gc.disable() + self.addCleanup(sys.settrace, sys.gettrace()) def tearDown(self): if self.using_gc: @@ -389,6 +390,9 @@ class RaisingTraceFuncTestCase(unittest.TestCase): + def setUp(self): + self.addCleanup(sys.settrace, sys.gettrace()) + def trace(self, frame, event, arg): """A trace function that raises an exception in response to a specific trace event.""" @@ -688,6 +692,9 @@ class JumpTestCase(unittest.TestCase): + def setUp(self): + self.addCleanup(sys.settrace, sys.gettrace()) + def compare_jump_output(self, expected, received): if received != expected: self.fail( "Outputs don't match:\n" + changeset: 9740:99b4d183cb20 branch: py3k parent: 9739:ef221c01d97a parent: 9738:66a16eb9e167 user: Brett Cannon date: Tue Jan 25 10:37:49 2011 -0800 summary: Merge diff --git a/Doc/library/select.rst b/Doc/library/select.rst --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -94,11 +94,13 @@ library, and does not handle file descriptors that don't originate from WinSock. -.. attribute:: select.PIPE_BUF +.. attribute:: PIPE_BUF - Files reported as ready for writing by :func:`select`, :func:`poll` or - similar interfaces in this module are guaranteed to not block on a write - of up to :const:`PIPE_BUF` bytes. + The minimum number of bytes which can be written without blocking to a pipe + when the pipe has been reported as ready for writing by :func:`select`, + :func:`poll` or another interface in this module. This doesn't apply + to other kind of file-like objects such as sockets. + This value is guaranteed by POSIX to be at least 512. Availability: Unix. .. versionadded:: 3.2 diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -972,6 +972,50 @@ (Contributed by Alexander Belopolsky and Victor Stinner.) +math +---- + +The :mod:`math` module has been updated with six new functions inspired by the +C99 standard. + +The :func:`~math.isfinite` function provides a reliable and fast way to detect +special values. It returns *True* for regular numbers and *False* for *Nan* or +*Infinity*: + +>>> [isfinite(x) for x in (123, 4.56, float('Nan'), float('Inf'))] +[True, True, False, False] + +The :func:`~math.expm1` function computes ``e**x-1`` for small values of *x* +without incuring the loss of precision that usually accompanies the subtraction +of nearly equal quantities: + +>>> expm1(0.013671875) # more accurate way to compute e**x-1 for a small x +0.013765762467652909 + +The :func:`~math.erf` function computes a probability integral or `Gaussian +error function `_. The +complementary error function, :func:`~math.erfc`, is ``1 - erf(x)``: + +>>> erf(1.0/sqrt(2.0)) # portion of normal distribution within 1 standard deviation +0.682689492137086 +>>> erfc(1.0/sqrt(2.0)) # portion of normal distribution outside 1 standard deviation +0.31731050786291404 +>>> erf(1.0/sqrt(2.0)) + erfc(1.0/sqrt(2.0)) +1.0 + +The :func:`~math.gamma` function is a continuous extension of the factorial +function. See http://en.wikipedia.org/wiki/Gamma_function for details. Because +the function is related to factorials, it grows large even for small values of +*x*, so there is also a :func:`~math.lgamma` function for computing the natural +logarithm of the gamma function: + +>>> gamma(7.0) # six factorial +720.0 +>>> lgamma(801.0) # log(800 factorial) +4551.950730698041 + +(Contributed by Mark Dickinson.) + abc --- @@ -1215,6 +1259,20 @@ The :func:`os.popen` and :func:`subprocess.Popen` functions now support :keyword:`with` statements for auto-closing of the file descriptors. +select +------ + +The :mod:`select` module now exposes a new, constant attribute, +:attr:`~select.PIPE_BUF`, which gives the minimum number of bytes which are +guaranteed not to block when :func:`select.select` says a pipe is ready +for writing. + +>>> import select +>>> select.PIPE_BUF +512 + +(Available on Unix systems.) + gzip and zipfile ---------------- @@ -1713,6 +1771,39 @@ A new type, :class:`ctypes.c_ssize_t` represents the C :c:type:`ssize_t` datatype. +site +---- + +The :mod:`site` module has three new functions useful for reporting on the +details of a given Python installation. + +* :func:`~site.getsitepackages` lists all global site-packages directories. + +* :func:`~site.getuserbase` reports on the user's base directory where data can + be stored. + +* :func:`~site.getusersitepackages` reveals the user-specific site-packages + directory path. + +:: + + >>> site.getsitepackages() + ['/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages', + '/Library/Frameworks/Python.framework/Versions/3.2/lib/site-python', + '/Library/Python/3.2/site-packages'] + >>> site.getuserbase() + '/Users/raymondhettinger/Library/Python/3.2' + >>> site.getusersitepackages() + '/Users/raymondhettinger/Library/Python/3.2/lib/python/site-packages' + +Conveniently, some of site's functionality is accessible directly from the +command-line:: + + $ python -m site --user-base + /Users/raymondhettinger/.local + $ python -m site --user-site + /Users/raymondhettinger/.local/lib/python3.2/site-packages + sysconfig --------- @@ -1928,6 +2019,16 @@ (Work by Nick Coghlan, Dan Mahn, and Senthil Kumaran in :issue:`2987`, :issue:`5468`, and :issue:`9873`.) +turtledemo +---------- + +The demonstration code for the :mod:`turtle` module was moved from the *Demo* +directory to main library. It includes over a dozen sample scripts with +lively displays. Being on :attr:`sys.path`, it can now be run directly +from the command-line:: + + $ python -m turtledemo + Multi-threading =============== @@ -2127,7 +2228,7 @@ :pep:`385` for details. To learn to use the new version control system, see the `tutorial by Joel -Spolsky `_ or the `guide to Mercurial workflows +Spolsky `_ or the `Guide to Mercurial Workflows `_. diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -215,8 +215,8 @@ self.assertEqual(sys.getrecursionlimit(), 10000) sys.setrecursionlimit(oldlimit) - @unittest.skipIf(sys.gettrace(), 'fatal error if run with a trace function') - @test.support.cpython_only + @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(), + 'fatal error if run with a trace function') def test_recursionlimit_recovery(self): # NOTE: this test is slightly fragile in that it depends on the current # recursion count when executing the test being low enough so as to changeset: 9741:a17caf6cf96b branch: py3k user: Brett Cannon date: Tue Jan 25 13:07:52 2011 -0800 summary: Get test_trace to put any pre-existing trace function back. diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py --- a/Lib/test/test_trace.py +++ b/Lib/test/test_trace.py @@ -102,6 +102,7 @@ class TestLineCounts(unittest.TestCase): """White-box testing of line-counting, via runfunc""" def setUp(self): + self.addCleanup(sys.settrace, sys.gettrace()) self.tracer = Trace(count=1, trace=0, countfuncs=0, countcallers=0) self.my_py_filename = fix_ext_py(__file__) @@ -192,6 +193,7 @@ """A simple sanity test of line-counting, via runctx (exec)""" def setUp(self): self.my_py_filename = fix_ext_py(__file__) + self.addCleanup(sys.settrace, sys.gettrace()) def test_exec_counts(self): self.tracer = Trace(count=1, trace=0, countfuncs=0, countcallers=0) @@ -218,6 +220,7 @@ class TestFuncs(unittest.TestCase): """White-box testing of funcs tracing""" def setUp(self): + self.addCleanup(sys.settrace, sys.gettrace()) self.tracer = Trace(count=0, trace=0, countfuncs=1) self.filemod = my_file_and_modname() @@ -257,6 +260,7 @@ class TestCallers(unittest.TestCase): """White-box testing of callers tracing""" def setUp(self): + self.addCleanup(self.settrace, sys.gettrace()) self.tracer = Trace(count=0, trace=0, countcallers=1) self.filemod = my_file_and_modname() @@ -280,6 +284,9 @@ # Created separately for issue #3821 class TestCoverage(unittest.TestCase): + def setUp(self): + self.addCleanup(sys.settrace, sys.gettrace()) + def tearDown(self): rmtree(TESTFN) unlink(TESTFN) changeset: 9742:a0aeadf7369a branch: py3k user: Brett Cannon date: Tue Jan 25 13:14:06 2011 -0800 summary: Make test_pdb put the trace function back. diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -20,9 +20,12 @@ def __enter__(self): self.real_stdin = sys.stdin sys.stdin = _FakeInput(self.input) + self.orig_trace = sys.gettrace() if hasattr(sys, 'gettrace') else None def __exit__(self, *exc): sys.stdin = self.real_stdin + if self.orig_trace: + sys.settrace(self.orig_trace) def test_pdb_displayhook(): changeset: 9743:8b41bc53a6aa branch: py3k user: Brett Cannon date: Tue Jan 25 13:34:53 2011 -0800 summary: Make the test for doctest set the trace function back. diff --git a/Lib/doctest.py b/Lib/doctest.py --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -1373,6 +1373,7 @@ # Note that the interactive output will go to *our* # save_stdout, even if that's not the real sys.stdout; this # allows us to write test cases for the set_trace behavior. + save_trace = sys.gettrace() save_set_trace = pdb.set_trace self.debugger = _OutputRedirectingPdb(save_stdout) self.debugger.reset() @@ -1392,6 +1393,7 @@ finally: sys.stdout = save_stdout pdb.set_trace = save_set_trace + sys.settrace(save_trace) linecache.getlines = self.save_linecache_getlines sys.displayhook = save_displayhook if clear_globs: diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -5,6 +5,7 @@ from test import support import doctest import os +import sys # NOTE: There are some additional tests relating to interaction with @@ -373,7 +374,7 @@ >>> tests = finder.find(sample_func) >>> print(tests) # doctest: +ELLIPSIS - [] + [] The exact name depends on how test_doctest was invoked, so allow for leading path components. @@ -1686,226 +1687,227 @@ """ -def test_pdb_set_trace(): - """Using pdb.set_trace from a doctest. +if not hasattr(sys, 'gettrace') or not sys.gettrace(): + def test_pdb_set_trace(): + """Using pdb.set_trace from a doctest. - You can use pdb.set_trace from a doctest. To do so, you must - retrieve the set_trace function from the pdb module at the time - you use it. The doctest module changes sys.stdout so that it can - capture program output. It also temporarily replaces pdb.set_trace - with a version that restores stdout. This is necessary for you to - see debugger output. + You can use pdb.set_trace from a doctest. To do so, you must + retrieve the set_trace function from the pdb module at the time + you use it. The doctest module changes sys.stdout so that it can + capture program output. It also temporarily replaces pdb.set_trace + with a version that restores stdout. This is necessary for you to + see debugger output. - >>> doc = ''' - ... >>> x = 42 - ... >>> raise Exception('clé') - ... Traceback (most recent call last): - ... Exception: clé - ... >>> import pdb; pdb.set_trace() - ... ''' - >>> parser = doctest.DocTestParser() - >>> test = parser.get_doctest(doc, {}, "foo-bar@baz", "foo-bar@baz.py", 0) - >>> runner = doctest.DocTestRunner(verbose=False) + >>> doc = ''' + ... >>> x = 42 + ... >>> raise Exception('clé') + ... Traceback (most recent call last): + ... Exception: clé + ... >>> import pdb; pdb.set_trace() + ... ''' + >>> parser = doctest.DocTestParser() + >>> test = parser.get_doctest(doc, {}, "foo-bar@baz", "foo-bar@baz.py", 0) + >>> runner = doctest.DocTestRunner(verbose=False) - To demonstrate this, we'll create a fake standard input that - captures our debugger input: + To demonstrate this, we'll create a fake standard input that + captures our debugger input: - >>> import tempfile - >>> real_stdin = sys.stdin - >>> sys.stdin = _FakeInput([ - ... 'print(x)', # print data defined by the example - ... 'continue', # stop debugging - ... '']) + >>> import tempfile + >>> real_stdin = sys.stdin + >>> sys.stdin = _FakeInput([ + ... 'print(x)', # print data defined by the example + ... 'continue', # stop debugging + ... '']) - >>> try: runner.run(test) - ... finally: sys.stdin = real_stdin - --Return-- - > (1)()->None - -> import pdb; pdb.set_trace() - (Pdb) print(x) - 42 - (Pdb) continue - TestResults(failed=0, attempted=3) + >>> try: runner.run(test) + ... finally: sys.stdin = real_stdin + --Return-- + > (1)()->None + -> import pdb; pdb.set_trace() + (Pdb) print(x) + 42 + (Pdb) continue + TestResults(failed=0, attempted=3) - You can also put pdb.set_trace in a function called from a test: + You can also put pdb.set_trace in a function called from a test: - >>> def calls_set_trace(): - ... y=2 - ... import pdb; pdb.set_trace() + >>> def calls_set_trace(): + ... y=2 + ... import pdb; pdb.set_trace() - >>> doc = ''' - ... >>> x=1 - ... >>> calls_set_trace() - ... ''' - >>> test = parser.get_doctest(doc, globals(), "foo-bar@baz", "foo-bar@baz.py", 0) - >>> real_stdin = sys.stdin - >>> sys.stdin = _FakeInput([ - ... 'print(y)', # print data defined in the function - ... 'up', # out of function - ... 'print(x)', # print data defined by the example - ... 'continue', # stop debugging - ... '']) + >>> doc = ''' + ... >>> x=1 + ... >>> calls_set_trace() + ... ''' + >>> test = parser.get_doctest(doc, globals(), "foo-bar@baz", "foo-bar@baz.py", 0) + >>> real_stdin = sys.stdin + >>> sys.stdin = _FakeInput([ + ... 'print(y)', # print data defined in the function + ... 'up', # out of function + ... 'print(x)', # print data defined by the example + ... 'continue', # stop debugging + ... '']) - >>> try: - ... runner.run(test) - ... finally: - ... sys.stdin = real_stdin - --Return-- - > (3)calls_set_trace()->None - -> import pdb; pdb.set_trace() - (Pdb) print(y) - 2 - (Pdb) up - > (1)() - -> calls_set_trace() - (Pdb) print(x) - 1 - (Pdb) continue - TestResults(failed=0, attempted=2) + >>> try: + ... runner.run(test) + ... finally: + ... sys.stdin = real_stdin + --Return-- + > (3)calls_set_trace()->None + -> import pdb; pdb.set_trace() + (Pdb) print(y) + 2 + (Pdb) up + > (1)() + -> calls_set_trace() + (Pdb) print(x) + 1 + (Pdb) continue + TestResults(failed=0, attempted=2) - During interactive debugging, source code is shown, even for - doctest examples: + During interactive debugging, source code is shown, even for + doctest examples: - >>> doc = ''' - ... >>> def f(x): - ... ... g(x*2) - ... >>> def g(x): - ... ... print(x+3) - ... ... import pdb; pdb.set_trace() - ... >>> f(3) - ... ''' - >>> test = parser.get_doctest(doc, globals(), "foo-bar@baz", "foo-bar@baz.py", 0) - >>> real_stdin = sys.stdin - >>> sys.stdin = _FakeInput([ - ... 'list', # list source from example 2 - ... 'next', # return from g() - ... 'list', # list source from example 1 - ... 'next', # return from f() - ... 'list', # list source from example 3 - ... 'continue', # stop debugging - ... '']) - >>> try: runner.run(test) - ... finally: sys.stdin = real_stdin - ... # doctest: +NORMALIZE_WHITESPACE - --Return-- - > (3)g()->None - -> import pdb; pdb.set_trace() - (Pdb) list - 1 def g(x): - 2 print(x+3) - 3 -> import pdb; pdb.set_trace() - [EOF] - (Pdb) next - --Return-- - > (2)f()->None - -> g(x*2) - (Pdb) list - 1 def f(x): - 2 -> g(x*2) - [EOF] - (Pdb) next - --Return-- - > (1)()->None - -> f(3) - (Pdb) list - 1 -> f(3) - [EOF] - (Pdb) continue - ********************************************************************** - File "foo-bar@baz.py", line 7, in foo-bar@baz - Failed example: - f(3) - Expected nothing - Got: - 9 - TestResults(failed=1, attempted=3) - """ + >>> doc = ''' + ... >>> def f(x): + ... ... g(x*2) + ... >>> def g(x): + ... ... print(x+3) + ... ... import pdb; pdb.set_trace() + ... >>> f(3) + ... ''' + >>> test = parser.get_doctest(doc, globals(), "foo-bar@baz", "foo-bar@baz.py", 0) + >>> real_stdin = sys.stdin + >>> sys.stdin = _FakeInput([ + ... 'list', # list source from example 2 + ... 'next', # return from g() + ... 'list', # list source from example 1 + ... 'next', # return from f() + ... 'list', # list source from example 3 + ... 'continue', # stop debugging + ... '']) + >>> try: runner.run(test) + ... finally: sys.stdin = real_stdin + ... # doctest: +NORMALIZE_WHITESPACE + --Return-- + > (3)g()->None + -> import pdb; pdb.set_trace() + (Pdb) list + 1 def g(x): + 2 print(x+3) + 3 -> import pdb; pdb.set_trace() + [EOF] + (Pdb) next + --Return-- + > (2)f()->None + -> g(x*2) + (Pdb) list + 1 def f(x): + 2 -> g(x*2) + [EOF] + (Pdb) next + --Return-- + > (1)()->None + -> f(3) + (Pdb) list + 1 -> f(3) + [EOF] + (Pdb) continue + ********************************************************************** + File "foo-bar@baz.py", line 7, in foo-bar@baz + Failed example: + f(3) + Expected nothing + Got: + 9 + TestResults(failed=1, attempted=3) + """ -def test_pdb_set_trace_nested(): - """This illustrates more-demanding use of set_trace with nested functions. + def test_pdb_set_trace_nested(): + """This illustrates more-demanding use of set_trace with nested functions. - >>> class C(object): - ... def calls_set_trace(self): - ... y = 1 - ... import pdb; pdb.set_trace() - ... self.f1() - ... y = 2 - ... def f1(self): - ... x = 1 - ... self.f2() - ... x = 2 - ... def f2(self): - ... z = 1 - ... z = 2 + >>> class C(object): + ... def calls_set_trace(self): + ... y = 1 + ... import pdb; pdb.set_trace() + ... self.f1() + ... y = 2 + ... def f1(self): + ... x = 1 + ... self.f2() + ... x = 2 + ... def f2(self): + ... z = 1 + ... z = 2 - >>> calls_set_trace = C().calls_set_trace + >>> calls_set_trace = C().calls_set_trace - >>> doc = ''' - ... >>> a = 1 - ... >>> calls_set_trace() - ... ''' - >>> parser = doctest.DocTestParser() - >>> runner = doctest.DocTestRunner(verbose=False) - >>> test = parser.get_doctest(doc, globals(), "foo-bar@baz", "foo-bar@baz.py", 0) - >>> real_stdin = sys.stdin - >>> sys.stdin = _FakeInput([ - ... 'print(y)', # print data defined in the function - ... 'step', 'step', 'step', 'step', 'step', 'step', 'print(z)', - ... 'up', 'print(x)', - ... 'up', 'print(y)', - ... 'up', 'print(foo)', - ... 'continue', # stop debugging - ... '']) + >>> doc = ''' + ... >>> a = 1 + ... >>> calls_set_trace() + ... ''' + >>> parser = doctest.DocTestParser() + >>> runner = doctest.DocTestRunner(verbose=False) + >>> test = parser.get_doctest(doc, globals(), "foo-bar@baz", "foo-bar@baz.py", 0) + >>> real_stdin = sys.stdin + >>> sys.stdin = _FakeInput([ + ... 'print(y)', # print data defined in the function + ... 'step', 'step', 'step', 'step', 'step', 'step', 'print(z)', + ... 'up', 'print(x)', + ... 'up', 'print(y)', + ... 'up', 'print(foo)', + ... 'continue', # stop debugging + ... '']) - >>> try: - ... runner.run(test) - ... finally: - ... sys.stdin = real_stdin - ... # doctest: +REPORT_NDIFF - > (5)calls_set_trace() - -> self.f1() - (Pdb) print(y) - 1 - (Pdb) step - --Call-- - > (7)f1() - -> def f1(self): - (Pdb) step - > (8)f1() - -> x = 1 - (Pdb) step - > (9)f1() - -> self.f2() - (Pdb) step - --Call-- - > (11)f2() - -> def f2(self): - (Pdb) step - > (12)f2() - -> z = 1 - (Pdb) step - > (13)f2() - -> z = 2 - (Pdb) print(z) - 1 - (Pdb) up - > (9)f1() - -> self.f2() - (Pdb) print(x) - 1 - (Pdb) up - > (5)calls_set_trace() - -> self.f1() - (Pdb) print(y) - 1 - (Pdb) up - > (1)() - -> calls_set_trace() - (Pdb) print(foo) - *** NameError: name 'foo' is not defined - (Pdb) continue - TestResults(failed=0, attempted=2) -""" + >>> try: + ... runner.run(test) + ... finally: + ... sys.stdin = real_stdin + ... # doctest: +REPORT_NDIFF + > (5)calls_set_trace() + -> self.f1() + (Pdb) print(y) + 1 + (Pdb) step + --Call-- + > (7)f1() + -> def f1(self): + (Pdb) step + > (8)f1() + -> x = 1 + (Pdb) step + > (9)f1() + -> self.f2() + (Pdb) step + --Call-- + > (11)f2() + -> def f2(self): + (Pdb) step + > (12)f2() + -> z = 1 + (Pdb) step + > (13)f2() + -> z = 2 + (Pdb) print(z) + 1 + (Pdb) up + > (9)f1() + -> self.f2() + (Pdb) print(x) + 1 + (Pdb) up + > (5)calls_set_trace() + -> self.f1() + (Pdb) print(y) + 1 + (Pdb) up + > (1)() + -> calls_set_trace() + (Pdb) print(foo) + *** NameError: name 'foo' is not defined + (Pdb) continue + TestResults(failed=0, attempted=2) + """ def test_DocTestSuite(): """DocTestSuite creates a unittest test suite from a doctest. changeset: 9744:a762a0249689 branch: py3k user: Brett Cannon date: Tue Jan 25 13:38:25 2011 -0800 summary: Update test_zipimport_support to reflect the conditional tests in test_doctest. diff --git a/Lib/test/test_zipimport_support.py b/Lib/test/test_zipimport_support.py --- a/Lib/test/test_zipimport_support.py +++ b/Lib/test/test_zipimport_support.py @@ -159,8 +159,6 @@ test_zipped_doctest.test_DocTestRunner.verbose_flag, test_zipped_doctest.test_Example, test_zipped_doctest.test_debug, - test_zipped_doctest.test_pdb_set_trace, - test_zipped_doctest.test_pdb_set_trace_nested, test_zipped_doctest.test_testsource, test_zipped_doctest.test_trailing_space_in_test, test_zipped_doctest.test_DocTestSuite, @@ -173,6 +171,10 @@ test_zipped_doctest.test_testfile, test_zipped_doctest.test_unittest_reportflags, ] + # Skip test_zipped_doctest.test_pdb_set_trace and + # test_zipped_doctest.test_pdb_set_trace_nested as they are + # conditional on no trace function being set. + for obj in known_good_tests: _run_object_doctest(obj, test_zipped_doctest) changeset: 9746:50f2cc2a5d3d branch: py3k parent: 9744:a762a0249689 user: Brett Cannon date: Tue Jan 25 15:06:38 2011 -0800 summary: Add a recursion_test decorator which unsets any trace function. diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -5,7 +5,7 @@ import copyreg from http.cookies import SimpleCookie -from test.support import TestFailed, TESTFN, run_with_locale +from test.support import TestFailed, TESTFN, run_with_locale, recursion_test from pickle import bytes_types @@ -1002,6 +1002,7 @@ y = self.loads(s) self.assertEqual(y._reduce_called, 1) + @recursion_test def test_bad_getattr(self): x = BadGetattr() for proto in 0, 1: diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -1108,6 +1108,25 @@ return guards.get(platform.python_implementation().lower(), default) +def recursion_test(test): + """Decorator for test which are doing recursion depth testing. + + To prevent unexpected loss of depth, unset any trace function. This also + prevents the trace function from being reset from the RuntimeError being + raised in the trace function. + """ + if check_impl_detail(cpython=False): + return test + @contextlib.wraps(test) + def wrapper(*args, **kwargs): + original_trace = sys.gettrace() + sys.settrace(None) + try: + return test(*args, **kwargs) + finally: + sys.settrace(original_trace) + return wrapper + def _run_suite(suite): """Run tests from a unittest.TestSuite-derived class.""" diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -7,7 +7,7 @@ import weakref from test.support import (TESTFN, unlink, run_unittest, captured_output, - gc_collect, cpython_only) + gc_collect, cpython_only, recursion_test) # XXX This is not really enough, each *operation* should be tested! @@ -388,6 +388,7 @@ x = DerivedException(fancy_arg=42) self.assertEqual(x.fancy_arg, 42) + @recursion_test def testInfiniteRecursion(self): def f(): return f() @@ -631,6 +632,7 @@ u.start = 1000 self.assertEqual(str(u), "can't translate characters in position 1000-4: 965230951443685724997") + @recursion_test def test_badisinstance(self): # Bug #2542: if issubclass(e, MyException) raises an exception, # it should be ignored @@ -741,6 +743,7 @@ self.fail("MemoryError not raised") self.assertEqual(wr(), None) + @recursion_test def test_recursion_error_cleanup(self): # Same test as above, but with "recursion exceeded" errors class C: diff --git a/Lib/test/test_richcmp.py b/Lib/test/test_richcmp.py --- a/Lib/test/test_richcmp.py +++ b/Lib/test/test_richcmp.py @@ -220,6 +220,7 @@ for func in (do, operator.not_): self.assertRaises(Exc, func, Bad()) + @support.recursion_test def test_recursion(self): # Check that comparison for recursive objects fails gracefully from collections import UserList diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -6,7 +6,8 @@ import re import tempfile import py_compile -from test.support import forget, make_legacy_pyc, run_unittest, unload, verbose +from test.support import ( + forget, make_legacy_pyc, run_unittest, unload, verbose, recursion_test) from test.script_helper import ( make_pkg, make_script, make_zip_pkg, make_zip_script, temp_dir) @@ -395,6 +396,7 @@ msg = "can't find '__main__' module in %r" % zip_name self._check_import_error(zip_name, msg) + @recursion_test def test_main_recursion_error(self): with temp_dir() as script_dir, temp_dir() as dummy_dir: mod_name = '__main__' changeset: 9747:95cd623b23b8 branch: py3k parent: 9746:50f2cc2a5d3d parent: 9745:37570405000b user: Brett Cannon date: Tue Jan 25 15:06:47 2011 -0800 summary: Merge diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -138,6 +138,15 @@ m.d = d self.assertRaises(RuntimeError, d.count, 3) + # test issue11004 + # block advance failed after rotation aligned elements on right side of block + d = deque([None]*16) + for i in range(len(d)): + d.rotate(-1) + d.rotate(1) + self.assertEqual(d.count(1), 0) + self.assertEqual(d.count(None), 16) + def test_comparisons(self): d = deque('xabc'); d.popleft() for e in [d, deque('abc'), deque('ab'), deque(), list(d)]: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -16,6 +16,8 @@ Library ------- +- Issue #11004: Repaired edge case in deque.count(). + - Issue #10974: IDLE no longer crashes if its recent files list includes files with non-ASCII characters in their path names. diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -485,7 +485,8 @@ /* Advance left block/index pair */ leftindex++; if (leftindex == BLOCKLEN) { - assert (leftblock->rightlink != NULL); + if (leftblock->rightlink == NULL) + break; leftblock = leftblock->rightlink; leftindex = 0; } @@ -493,7 +494,8 @@ /* Step backwards with the right block/index pair */ rightindex--; if (rightindex == -1) { - assert (rightblock->leftlink != NULL); + if (rightblock->leftlink == NULL) + break; rightblock = rightblock->leftlink; rightindex = BLOCKLEN - 1; } @@ -509,7 +511,7 @@ { block *leftblock = deque->leftblock; Py_ssize_t leftindex = deque->leftindex; - Py_ssize_t n = (deque->len); + Py_ssize_t n = deque->len; Py_ssize_t i; Py_ssize_t count = 0; PyObject *item; @@ -533,7 +535,8 @@ /* Advance left block/index pair */ leftindex++; if (leftindex == BLOCKLEN) { - assert (leftblock->rightlink != NULL); + if (leftblock->rightlink == NULL) /* can occur when i==n-1 */ + break; leftblock = leftblock->rightlink; leftindex = 0; } changeset: 9748:9a583980a341 branch: py3k user: Brett Cannon date: Tue Jan 25 16:25:07 2011 -0800 summary: Move away from a recursion-specific decorator and create a no tracing decorator/context manager. diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -5,7 +5,7 @@ import copyreg from http.cookies import SimpleCookie -from test.support import TestFailed, TESTFN, run_with_locale, recursion_test +from test.support import TestFailed, TESTFN, run_with_locale, no_tracing from pickle import bytes_types @@ -1002,7 +1002,7 @@ y = self.loads(s) self.assertEqual(y._reduce_called, 1) - @recursion_test + @no_tracing() def test_bad_getattr(self): x = BadGetattr() for proto in 0, 1: diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -1108,24 +1108,27 @@ return guards.get(platform.python_implementation().lower(), default) -def recursion_test(test): - """Decorator for test which are doing recursion depth testing. - - To prevent unexpected loss of depth, unset any trace function. This also - prevents the trace function from being reset from the RuntimeError being - raised in the trace function. - """ - if check_impl_detail(cpython=False): - return test - @contextlib.wraps(test) - def wrapper(*args, **kwargs): +@contextlib.contextmanager +def no_tracing(): + """Temporarily turn off tracing.""" + if not hasattr(sys, 'gettrace'): + yield + else: original_trace = sys.gettrace() sys.settrace(None) - try: - return test(*args, **kwargs) - finally: - sys.settrace(original_trace) - return wrapper + yield + sys.settrace(original_trace) + + +def refcount_test(test): + """Decorator for tests which involve reference counting. + + To start, the decorator does not run the test if is not run by CPython. + After that, any trace function is unset during the test to prevent + unexpected refcounts caused by the trace function. + + """ + return no_tracing()(cpython_only(test)) def _run_suite(suite): diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -7,7 +7,7 @@ import weakref from test.support import (TESTFN, unlink, run_unittest, captured_output, - gc_collect, cpython_only, recursion_test) + gc_collect, cpython_only, no_tracing) # XXX This is not really enough, each *operation* should be tested! @@ -388,7 +388,7 @@ x = DerivedException(fancy_arg=42) self.assertEqual(x.fancy_arg, 42) - @recursion_test + @no_tracing() def testInfiniteRecursion(self): def f(): return f() @@ -632,7 +632,7 @@ u.start = 1000 self.assertEqual(str(u), "can't translate characters in position 1000-4: 965230951443685724997") - @recursion_test + @no_tracing() def test_badisinstance(self): # Bug #2542: if issubclass(e, MyException) raises an exception, # it should be ignored @@ -743,7 +743,7 @@ self.fail("MemoryError not raised") self.assertEqual(wr(), None) - @recursion_test + @no_tracing def test_recursion_error_cleanup(self): # Same test as above, but with "recursion exceeded" errors class C: diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2214,6 +2214,7 @@ with self.open(support.TESTFN, "w", errors="replace") as f: self.assertEqual(f.errors, "replace") + @support.no_tracing() @unittest.skipUnless(threading, 'Threading required for this test.') def test_threads_write(self): # Issue6750: concurrent writes could duplicate data @@ -2677,23 +2678,24 @@ signal.signal(signal.SIGALRM, on_alarm) r, w = os.pipe() wio = self.io.open(w, **fdopen_kwargs) - try: - signal.alarm(1) - # Either the reentrant call to wio.write() fails with RuntimeError, - # or the signal handler raises ZeroDivisionError. - with self.assertRaises((ZeroDivisionError, RuntimeError)) as cm: - while 1: - for i in range(100): - wio.write(data) - wio.flush() - # Make sure the buffer doesn't fill up and block further writes - os.read(r, len(data) * 100) - exc = cm.exception - if isinstance(exc, RuntimeError): - self.assertTrue(str(exc).startswith("reentrant call"), str(exc)) - finally: - wio.close() - os.close(r) + with support.no_tracing(): + try: + signal.alarm(1) + # Either the reentrant call to wio.write() fails with RuntimeError, + # or the signal handler raises ZeroDivisionError. + with self.assertRaises((ZeroDivisionError, RuntimeError)) as cm: + while 1: + for i in range(100): + wio.write(data) + wio.flush() + # Make sure the buffer doesn't fill up and block further writes + os.read(r, len(data) * 100) + exc = cm.exception + if isinstance(exc, RuntimeError): + self.assertTrue(str(exc).startswith("reentrant call"), str(exc)) + finally: + wio.close() + os.close(r) def test_reentrant_write_buffered(self): self.check_reentrant_write(b"xy", mode="wb") diff --git a/Lib/test/test_richcmp.py b/Lib/test/test_richcmp.py --- a/Lib/test/test_richcmp.py +++ b/Lib/test/test_richcmp.py @@ -220,7 +220,7 @@ for func in (do, operator.not_): self.assertRaises(Exc, func, Bad()) - @support.recursion_test + @support.no_tracing() def test_recursion(self): # Check that comparison for recursive objects fails gracefully from collections import UserList diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -7,7 +7,7 @@ import tempfile import py_compile from test.support import ( - forget, make_legacy_pyc, run_unittest, unload, verbose, recursion_test) + forget, make_legacy_pyc, run_unittest, unload, verbose, no_tracing) from test.script_helper import ( make_pkg, make_script, make_zip_pkg, make_zip_script, temp_dir) @@ -396,7 +396,7 @@ msg = "can't find '__main__' module in %r" % zip_name self._check_import_error(zip_name, msg) - @recursion_test + @no_tracing() def test_main_recursion_error(self): with temp_dir() as script_dir, temp_dir() as dummy_dir: mod_name = '__main__' changeset: 9749:4dd3fd075c6a branch: py3k user: Brett Cannon date: Tue Jan 25 18:08:34 2011 -0800 summary: Stop trying to use contextmanager's fancy decorator/context manager dual use and just make it a simple decorator. diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1002,7 +1002,7 @@ y = self.loads(s) self.assertEqual(y._reduce_called, 1) - @no_tracing() + @no_tracing def test_bad_getattr(self): x = BadGetattr() for proto in 0, 1: diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -1108,16 +1108,20 @@ return guards.get(platform.python_implementation().lower(), default) -@contextlib.contextmanager -def no_tracing(): - """Temporarily turn off tracing.""" +def no_tracing(func): + """Decorator to temporarily turn off tracing for the duration of a test.""" if not hasattr(sys, 'gettrace'): - yield + return func else: - original_trace = sys.gettrace() - sys.settrace(None) - yield - sys.settrace(original_trace) + @functools.wraps(func) + def wrapper(*args, **kwargs): + original_trace = sys.gettrace() + try: + sys.settrace(None) + return func(*args, **kwargs) + finally: + sys.settrace(original_trace) + return wrapper def refcount_test(test): @@ -1128,7 +1132,7 @@ unexpected refcounts caused by the trace function. """ - return no_tracing()(cpython_only(test)) + return no_tracing(cpython_only(test)) def _run_suite(suite): diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -388,7 +388,7 @@ x = DerivedException(fancy_arg=42) self.assertEqual(x.fancy_arg, 42) - @no_tracing() + @no_tracing def testInfiniteRecursion(self): def f(): return f() @@ -632,7 +632,7 @@ u.start = 1000 self.assertEqual(str(u), "can't translate characters in position 1000-4: 965230951443685724997") - @no_tracing() + @no_tracing def test_badisinstance(self): # Bug #2542: if issubclass(e, MyException) raises an exception, # it should be ignored diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2214,7 +2214,7 @@ with self.open(support.TESTFN, "w", errors="replace") as f: self.assertEqual(f.errors, "replace") - @support.no_tracing() + @support.no_tracing @unittest.skipUnless(threading, 'Threading required for this test.') def test_threads_write(self): # Issue6750: concurrent writes could duplicate data @@ -2670,6 +2670,7 @@ def test_interrupted_write_text(self): self.check_interrupted_write("xy", b"xy", mode="w", encoding="ascii") + @support.no_tracing def check_reentrant_write(self, data, **fdopen_kwargs): def on_alarm(*args): # Will be called reentrantly from the same thread @@ -2678,24 +2679,23 @@ signal.signal(signal.SIGALRM, on_alarm) r, w = os.pipe() wio = self.io.open(w, **fdopen_kwargs) - with support.no_tracing(): - try: - signal.alarm(1) - # Either the reentrant call to wio.write() fails with RuntimeError, - # or the signal handler raises ZeroDivisionError. - with self.assertRaises((ZeroDivisionError, RuntimeError)) as cm: - while 1: - for i in range(100): - wio.write(data) - wio.flush() - # Make sure the buffer doesn't fill up and block further writes - os.read(r, len(data) * 100) - exc = cm.exception - if isinstance(exc, RuntimeError): - self.assertTrue(str(exc).startswith("reentrant call"), str(exc)) - finally: - wio.close() - os.close(r) + try: + signal.alarm(1) + # Either the reentrant call to wio.write() fails with RuntimeError, + # or the signal handler raises ZeroDivisionError. + with self.assertRaises((ZeroDivisionError, RuntimeError)) as cm: + while 1: + for i in range(100): + wio.write(data) + wio.flush() + # Make sure the buffer doesn't fill up and block further writes + os.read(r, len(data) * 100) + exc = cm.exception + if isinstance(exc, RuntimeError): + self.assertTrue(str(exc).startswith("reentrant call"), str(exc)) + finally: + wio.close() + os.close(r) def test_reentrant_write_buffered(self): self.check_reentrant_write(b"xy", mode="wb") diff --git a/Lib/test/test_richcmp.py b/Lib/test/test_richcmp.py --- a/Lib/test/test_richcmp.py +++ b/Lib/test/test_richcmp.py @@ -220,7 +220,7 @@ for func in (do, operator.not_): self.assertRaises(Exc, func, Bad()) - @support.no_tracing() + @support.no_tracing def test_recursion(self): # Check that comparison for recursive objects fails gracefully from collections import UserList diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -396,7 +396,7 @@ msg = "can't find '__main__' module in %r" % zip_name self._check_import_error(zip_name, msg) - @no_tracing() + @no_tracing def test_main_recursion_error(self): with temp_dir() as script_dir, temp_dir() as dummy_dir: mod_name = '__main__' changeset: 9750:368b5c6b0af4 branch: py3k tag: tip user: Brett Cannon date: Tue Jan 25 18:23:26 2011 -0800 summary: Manually set sys.settrace(None) for a very touchy test_sys_settrace. diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -694,6 +694,7 @@ class JumpTestCase(unittest.TestCase): def setUp(self): self.addCleanup(sys.settrace, sys.gettrace()) + sys.settrace(None) def compare_jump_output(self, expected, received): if received != expected: @@ -746,6 +747,8 @@ def test_18_no_jump_to_non_integers(self): self.run_test(no_jump_to_non_integers) def test_19_no_jump_without_trace_function(self): + # Must set sys.settrace(None) in setUp(), else condition is not + # triggered. no_jump_without_trace_function() def test_20_large_function(self):