This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: test_locale leaves locale changed
Type: Stage:
Components: Tests Versions: Python 3.1, Python 3.2
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: giampaolo.rodola, lemburg, michael.foord, ocean-city, pitrou
Priority: normal Keywords:

Created on 2010-09-16 03:21 by ocean-city, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (8)
msg116506 - (view) Author: Hirokazu Yamamoto (ocean-city) * (Python committer) Date: 2010-09-16 03:21
I noticed test_locale leaves locale changed.

# test_boo is simple test just to print windows error.

E:\python-dev\py3k\Lib\test>py3k -m test.regrtest test_locale test_boo
[1/2] test_locale
[2/2] test_boo
test test_boo failed -- Traceback (most recent call last):
  File "e:\python-dev\py3k\lib\test\test_boo.py", line 11, in test
    os.rmdir(TMPDIR)
WindowsError: [Error 2] ?w’e?3?e???t?@?C???a?c?A?c?e?U?1?n?B: 'e:\\python-dev\\
py3k\\lib\\test\\__boo__'
Traceback (most recent call last):
  File "e:\python-dev\py3k\lib\test\regrtest.py", line 941, in runtest_inner
    indirect_test()
  File "e:\python-dev\py3k\lib\test\test_boo.py", line 14, in test_main
    support.run_unittest(TestCase)
  File "e:\python-dev\py3k\lib\test\support.py", line 1128, in run_unittest
    _run_suite(suite)
  File "e:\python-dev\py3k\lib\test\support.py", line 1111, in _run_suite
    raise TestFailed(err)
test.support.TestFailed: Traceback (most recent call last):
  File "e:\python-dev\py3k\lib\test\test_boo.py", line 11, in test
    os.rmdir(TMPDIR)
WindowsError: [Error 2] ?w’e?3?e???t?@?C???a?c?A?c?e?U?1?n?B: 'e:\\python-dev\\
py3k\\lib\\test\\__boo__'
test.support.TestFailed: Traceback (most recent call last):
  File "e:\python-dev\py3k\lib\test\test_boo.py", line 11, in test
    os.rmdir(TMPDIR)
WindowsError: [Error 2] ?w’e?3?e???t?@?C???a?c?A?c?e?U?1?n?B: 'e:\\python-dev\\
py3k\\lib\\test\\__boo__'

During handling of the above exception, another exception occurred:

test test_boo failed -- Traceback (most recent call last):
  File "e:\python-dev\py3k\lib\test\test_boo.py", line 11, in test
    os.rmdir(TMPDIR)
WindowsError: [Error 2] ?w’e?3?e???t?@?C???a?c?A?c?e?U?1?n?B: 'e:\\python-dev\\
py3k\\lib\\test\\__boo__'
test.support.TestFailed: Traceback (most recent call last):
  File "e:\python-dev\py3k\lib\test\test_boo.py", line 11, in test
    os.rmdir(TMPDIR)
WindowsError: [Error 2] ?w’e?3?e???t?@?C???a?c?A?c?e?U?1?n?B: 'e:\\python-dev\\
py3k\\lib\\test\\__boo__'

During handling of the above exception, another exception occurred:

Exception IOError: 'raw write() returned invalid length 253 (should have been be
tween 0 and 252)' in <_io.TextIOWrapper name='<stdout>' encoding='cp932'> ignore
d
test.support.TestFailed: Traceback (most recent call last):
  File "e:\python-dev\py3k\lib\test\test_boo.py", line 11, in test
    os.rmdir(TMPDIR)
WindowsError: [Error 2] ?w’e?3?e???t?@?C???a?c?A?c?e?U?1?n?B: 'e:\\python-dev\\
py3k\\lib\\test\\__boo__'

During handling of the above exception, another exception occurred:

Exception IOError: 'raw write() returned invalid length 253 (should have been be
tween 0 and 252)' in <_io.TextIOWrapper name='<stdout>' encoding='cp932'> ignore
d
[79459 refs]

/////////////////////////////////////////////////
// test_boo.py

from test import support
import unittest
import os

TMPDIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "__notexist__")

class TestCase(unittest.TestCase):
    def test(self):
        os.rmdir(TMPDIR)

def test_main():
    support.run_unittest(TestCase)

if __name__ == '__main__':
    test_main()
msg116507 - (view) Author: Hirokazu Yamamoto (ocean-city) * (Python committer) Date: 2010-09-16 04:11
This happens because in Lib/test/test_locale.py,
TestEnUSCollation#setUp raises exception after
BaseLocalizedTest.setUp(self) changed locale.
tearDown never be called when setUp failedsetUp failed.

It's easy to fix this as is, but I think more general
solution would be better.

How about the mechanism like this? It calls setUp() and
tearDown() in according to MRO, if setUp() fails somewhere
in the chain, calls tearDown() for the class whose setUp()
is successfully called. (Be care, you shouldn't call
parent's setUp() or tearDown() directly)

////////////////////
// mockup

import unittest

class TestCase2(unittest.TestCase):
    def setUp(self):
        klasses = []
        try:
            for klass in reversed(self.__class__.__mro__):
                func = getattr(klass, "setUp2", None)
                if func is not None:
                    func(self)
                    klasses.append(klass)
        except:
            for klass in reversed(klasses):
                func = getattr(klass, "tearDown2", None)
                if func is not None:
                    func(self)
            raise
    def tearDown(self):
        for klass in self.__class__.__mro__:
            func = getattr(klass, "tearDown2", None)
            if func is not None:
                func(self)

class A(TestCase2):
    def setUp2(self):
        print("A#setUp2")
    def tearDown2(self):
        print("A#tearDown2")

class B(A):
    def setUp2(self):
        print("B#setUp2")
        raise RuntimeError("B#setUp2 failed")
    def tearDown2(self):
        print("B#tearDown2")
    def test(self):
        pass

if __name__ == '__main__':
    unittest.main()

////////////////////////////////
// result

A#setUp2
B#setUp2
A#tearDown2
(snip)
msg116587 - (view) Author: Hirokazu Yamamoto (ocean-city) * (Python committer) Date: 2010-09-16 18:08
This patch is *as is* patch.

Index: Lib/test/test_locale.py
===================================================================
--- Lib/test/test_locale.py	(revision 84824)
+++ Lib/test/test_locale.py	(working copy)
@@ -352,13 +352,13 @@
     locale_type = locale.LC_ALL
 
     def setUp(self):
-        BaseLocalizedTest.setUp(self)
         enc = codecs.lookup(locale.getpreferredencoding(False) or 'ascii').name
         if enc not in ('utf-8', 'iso8859-1', 'cp1252'):
             raise unittest.SkipTest('encoding not suitable')
         if enc != 'iso8859-1' and (sys.platform == 'darwin' or
                                    sys.platform.startswith('freebsd')):
             raise unittest.SkipTest('wcscoll/wcsxfrm have known bugs')
+        BaseLocalizedTest.setUp(self)
 
     def test_strcoll_with_diacritic(self):
         self.assertLess(locale.strcoll('テ', 'b'), 0)
msg117183 - (view) Author: Michael Foord (michael.foord) * (Python committer) Date: 2010-09-23 13:34
unittest *can't* know which setUp methods have already been called if an error occurs in one of them (because they are called explicitly by the sub-classes and not by unittest itself). Given this, the specific fix suggested seems good.
msg117190 - (view) Author: Hirokazu Yamamoto (ocean-city) * (Python committer) Date: 2010-09-23 14:18
> unittest *can't* know which setUp methods have already been called if
> an error occurs in one of them (because they are called explicitly by
> the sub-classes and not by unittest itself).

Well, C++ constructor/destructor behaves like that when constructor
of subclass raised exception. Destructors of super classes are called
in reverse order. The benefit of it is implementator of subclass
don't have to care about finalization of super class. It is done
automatically. But if explicit call is essential for us, my proposal
is not needed.

> Given this, the specific fix suggested seems good.
Thanks, I'll commit this.
msg117191 - (view) Author: Michael Foord (michael.foord) * (Python committer) Date: 2010-09-23 14:21
Destructors are special cased in many languages and tearDown is not a destructor. More importantly though the change you suggest would be backwards incompatible.

The 'correct' way to do this in new code is to use cleanUp functions which *are* called even if an exception is raised during setUp.
msg117194 - (view) Author: Hirokazu Yamamoto (ocean-city) * (Python committer) Date: 2010-09-23 14:50
> Destructors are special cased in many languages and tearDown is not a
> destructor.

Yes, but they are similar.

> More importantly though the change you suggest would be
> backwards incompatible.

> The 'correct' way to do this in new code is to use cleanUp functions
> which *are* called even if an exception is raised during setUp.

I must admit I'm not familiar with unittest framework. Probably
better way exists.
msg117267 - (view) Author: Hirokazu Yamamoto (ocean-city) * (Python committer) Date: 2010-09-24 09:22
Committed in r84973(py3k) and r84990(release31-maint).
History
Date User Action Args
2022-04-11 14:57:06adminsetgithub: 54077
2010-09-24 09:22:27ocean-citysetstatus: open -> closed
resolution: fixed
messages: + msg117267
2010-09-23 14:50:27ocean-citysetmessages: + msg117194
2010-09-23 14:21:47michael.foordsetmessages: + msg117191
2010-09-23 14:18:30ocean-citysetmessages: + msg117190
2010-09-23 13:34:32michael.foordsetmessages: + msg117183
2010-09-20 22:51:03eric.araujosetnosy: + lemburg, pitrou, giampaolo.rodola, michael.foord
2010-09-16 18:08:00ocean-citysetmessages: + msg116587
2010-09-16 04:11:39ocean-citysetmessages: + msg116507
2010-09-16 03:21:08ocean-citycreate