From 9b0e9180e220cb455881de9f4d922a4e2ce0435f Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Sun, 28 Mar 2010 11:42:38 +0000 Subject: [PATCH] Note: only the relevant parts of r79474 are merged. Merged revisions 78793,78798-78799,78977,79095,79196,79474 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/py3k ................ r78793 | florent.xicluna | 2010-03-08 13:25:35 +0100 (lun, 08 mar 2010) | 2 lines Fix macpath to deal with bytes ................ r78798 | florent.xicluna | 2010-03-08 14:32:17 +0100 (lun, 08 mar 2010) | 18 lines Merged revisions 78777,78787,78790 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r78777 | florent.xicluna | 2010-03-08 00:49:03 +0100 (lun, 08 mar 2010) | 4 lines Backport the Popen.poll() protection from subprocess to multiprocessing. See #1731717. It should fix transient failures on test_multiprocessing. ........ r78787 | florent.xicluna | 2010-03-08 08:21:16 +0100 (lun, 08 mar 2010) | 2 lines Don't fail on a debug() statement, if the worker PID is (still) None. ........ r78790 | florent.xicluna | 2010-03-08 12:01:39 +0100 (lun, 08 mar 2010) | 2 lines On finalize, don't try to join not started process. ........ ................ r78799 | florent.xicluna | 2010-03-08 15:44:41 +0100 (lun, 08 mar 2010) | 2 lines Fix ntpath abspath to deal with bytes. ................ r78977 | florent.xicluna | 2010-03-15 14:14:39 +0100 (lun, 15 mar 2010) | 2 lines Fix \xhh specs, #1889. (an oversight of r60193, r60210). ................ r79095 | florent.xicluna | 2010-03-19 15:40:31 +0100 (ven, 19 mar 2010) | 2 lines Rename test.test_support to test.support for 3.x. ................ r79196 | florent.xicluna | 2010-03-21 13:29:50 +0100 (dim, 21 mar 2010) | 9 lines Merged revisions 79195 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r79195 | florent.xicluna | 2010-03-21 13:27:20 +0100 (dim, 21 mar 2010) | 2 lines Issue #8179: Fix macpath.realpath() on a non-existing path. ........ ................ r79474 | florent.xicluna | 2010-03-28 01:25:02 +0100 (dim, 28 mar 2010) | 33 lines Merged revisions 79297,79310,79382,79425-79427,79450 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r79297 | florent.xicluna | 2010-03-22 18:18:18 +0100 (lun, 22 mar 2010) | 2 lines #7668: Fix test_httpservers failure when sys.executable contains non-ASCII bytes. ........ r79310 | florent.xicluna | 2010-03-22 23:52:11 +0100 (lun, 22 mar 2010) | 2 lines Issue #8205: Remove the "Modules" directory from sys.path when Python is running from the build directory (POSIX only). ........ r79382 | florent.xicluna | 2010-03-24 20:33:25 +0100 (mer, 24 mar 2010) | 2 lines Skip tests which depend on multiprocessing.sharedctypes, if _ctypes is not available. ........ r79425 | florent.xicluna | 2010-03-25 21:32:07 +0100 (jeu, 25 mar 2010) | 2 lines Syntax cleanup `== None` -> `is None` ........ r79426 | florent.xicluna | 2010-03-25 21:33:49 +0100 (jeu, 25 mar 2010) | 2 lines #8207: Fix test_pep277 on OS X ........ r79427 | florent.xicluna | 2010-03-25 21:39:10 +0100 (jeu, 25 mar 2010) | 2 lines Fix test_unittest and test_warnings when running "python -Werror -m test.regrtest" ........ r79450 | florent.xicluna | 2010-03-26 20:32:44 +0100 (ven, 26 mar 2010) | 2 lines Ensure that the failed or unexpected tests are sorted before printing. ........ ................ --- Doc/reference/lexical_analysis.rst | 2 +- Lib/idlelib/PyShell.py | 2 +- Lib/macpath.py | 11 ++++- Lib/multiprocessing/forking.py | 7 +++- Lib/multiprocessing/pool.py | 5 ++- Lib/multiprocessing/process.py | 2 +- Lib/ntpath.py | 2 + Lib/test/regrtest.py | 8 +--- Lib/test/test_httpservers.py | 14 ++++++- Lib/test/test_multiprocessing.py | 64 +++++++++++++++--------------- Lib/test/test_warnings.py | 6 +++ Lib/turtle.py | 12 +++--- Misc/NEWS | 4 +- 13 files changed, 86 insertions(+), 53 deletions(-) diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index ab1b7f52989..7df0c2b14c0 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -503,7 +503,7 @@ Notes: As in Standard C, up to three octal digits are accepted. (2) - Unlike in Standard C, at most two hex digits are accepted. + Unlike in Standard C, exactly two hex digits are required. (3) In a bytes literal, hexadecimal and octal escapes denote the byte with the diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py index 01360891c86..0898dfe6e82 100644 --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -347,7 +347,7 @@ class ModifiedInterpreter(InteractiveInterpreter): rpcpid = None def spawn_subprocess(self): - if self.subprocess_arglist == None: + if self.subprocess_arglist is None: self.subprocess_arglist = self.build_subprocess_arglist() args = self.subprocess_arglist self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args) diff --git a/Lib/macpath.py b/Lib/macpath.py index c0236462443..3b3e4ff0716 100644 --- a/Lib/macpath.py +++ b/Lib/macpath.py @@ -172,7 +172,11 @@ def normpath(s): def abspath(path): """Return an absolute path.""" if not isabs(path): - path = join(os.getcwd(), path) + if isinstance(path, bytes): + cwd = os.getcwdb() + else: + cwd = os.getcwd() + path = join(cwd, path) return normpath(path) # realpath is a no-op on systems without islink support @@ -189,7 +193,10 @@ def realpath(path): path = components[0] + colon for c in components[1:]: path = join(path, c) - path = Carbon.File.FSResolveAliasFile(path, 1)[0].as_pathname() + try: + path = Carbon.File.FSResolveAliasFile(path, 1)[0].as_pathname() + except Carbon.File.Error: + pass return path supports_unicode_filenames = False diff --git a/Lib/multiprocessing/forking.py b/Lib/multiprocessing/forking.py index 3c0f5689272..5d66fa32736 100644 --- a/Lib/multiprocessing/forking.py +++ b/Lib/multiprocessing/forking.py @@ -104,7 +104,12 @@ if sys.platform != 'win32': def poll(self, flag=os.WNOHANG): if self.returncode is None: - pid, sts = os.waitpid(self.pid, flag) + try: + pid, sts = os.waitpid(self.pid, flag) + except os.error: + # Child process not yet created. See #1731717 + # e.errno == errno.ECHILD == 10 + return None if pid == self.pid: if os.WIFSIGNALED(sts): self.returncode = -os.WTERMSIG(sts) diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py index d3ecc9b84b3..3489aea2841 100644 --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -387,7 +387,10 @@ class Pool(object): if pool and hasattr(pool[0], 'terminate'): debug('joining pool workers') for p in pool: - p.join() + if p.is_alive(): + # worker has not yet exited + debug('cleaning up worker %d' % p.pid) + p.join() # # Class whose instances are returned by `Pool.apply_async()` diff --git a/Lib/multiprocessing/process.py b/Lib/multiprocessing/process.py index 1a5c25fbb1b..c96a4b72756 100644 --- a/Lib/multiprocessing/process.py +++ b/Lib/multiprocessing/process.py @@ -179,7 +179,7 @@ class Process(object): @property def ident(self): ''' - Return indentifier (PID) of process or `None` if it has yet to start + Return identifier (PID) of process or `None` if it has yet to start ''' if self is _current_process: return os.getpid() diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 2fd26b1f3d5..1cec8954d03 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -561,6 +561,8 @@ else: # use native Windows method on Windows path = _getfullpathname(path) except WindowsError: pass # Bad path - return unchanged. + elif isinstance(path, bytes): + path = os.getcwdb() else: path = os.getcwd() return normpath(path) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index c985c50f5af..8d81bc91571 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -453,11 +453,6 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, generate=False, if module not in save_modules and module.startswith("test."): support.unload(module) - # The lists won't be sorted if running with -r - good.sort() - bad.sort() - skipped.sort() - if good and not quiet: if not bad and not skipped and len(good) > 1: print("All", end=' ') @@ -893,7 +888,8 @@ def printlist(x, width=70, indent=4): from textwrap import fill blanks = ' ' * indent - print(fill(' '.join(map(str, x)), width, + # Print the sorted list: 'x' may be a '--random' list or a set() + print(fill(' '.join(str(elt) for elt in sorted(x)), width, initial_indent=blanks, subsequent_indent=blanks)) # Map sys.platform to a string containing the basenames of tests diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index 13e4030fea7..4653f4c458b 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -294,14 +294,22 @@ class CGIHTTPServerTestCase(BaseTestCase): self.cgi_dir = os.path.join(self.parent_dir, 'cgi-bin') os.mkdir(self.cgi_dir) + # The shebang line should be pure ASCII: use symlink if possible. + # See issue #7668. + if hasattr(os, 'symlink'): + self.pythonexe = os.path.join(self.parent_dir, 'python') + os.symlink(sys.executable, self.pythonexe) + else: + self.pythonexe = sys.executable + self.file1_path = os.path.join(self.cgi_dir, 'file1.py') with open(self.file1_path, 'w') as file1: - file1.write(cgi_file1 % sys.executable) + file1.write(cgi_file1 % self.pythonexe) os.chmod(self.file1_path, 0o777) self.file2_path = os.path.join(self.cgi_dir, 'file2.py') with open(self.file2_path, 'w') as file2: - file2.write(cgi_file2 % sys.executable) + file2.write(cgi_file2 % self.pythonexe) os.chmod(self.file2_path, 0o777) self.cwd = os.getcwd() @@ -310,6 +318,8 @@ class CGIHTTPServerTestCase(BaseTestCase): def tearDown(self): try: os.chdir(self.cwd) + if self.pythonexe != sys.executable: + os.remove(self.pythonexe) os.remove(self.file1_path) os.remove(self.file2_path) os.rmdir(self.cgi_dir) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py index d3620b70513..f901a05245c 100644 --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -63,6 +63,16 @@ HAVE_GETVALUE = not getattr(_multiprocessing, WIN32 = (sys.platform == "win32") +# +# Some tests require ctypes +# + +try: + from ctypes import Structure, Value, copy, c_int, c_double +except ImportError: + Structure = object + c_int = c_double = None + # # Creates a wrapper for a function which records the time it takes to finish # @@ -506,7 +516,7 @@ class _TestQueue(BaseTestCase): queue = self.JoinableQueue() if sys.version_info < (2, 5) and not hasattr(queue, 'task_done'): - return + self.skipTest("requires 'queue.task_done()' method") workers = [self.Process(target=self._test_task_done, args=(queue,)) for i in range(4)] @@ -783,6 +793,8 @@ class _TestEvent(BaseTestCase): class _TestValue(BaseTestCase): + ALLOWED_TYPES = ('processes',) + codes_values = [ ('i', 4343, 24234), ('d', 3.625, -4.25), @@ -795,10 +807,8 @@ class _TestValue(BaseTestCase): sv.value = cv[2] + @unittest.skipIf(c_int is None, "requires _ctypes") def test_value(self, raw=False): - if self.TYPE != 'processes': - return - if raw: values = [self.RawValue(code, value) for code, value, _ in self.codes_values] @@ -816,13 +826,12 @@ class _TestValue(BaseTestCase): for sv, cv in zip(values, self.codes_values): self.assertEqual(sv.value, cv[2]) + @unittest.skipIf(c_int is None, "requires _ctypes") def test_rawvalue(self): self.test_value(raw=True) + @unittest.skipIf(c_int is None, "requires _ctypes") def test_getobj_getlock(self): - if self.TYPE != 'processes': - return - val1 = self.Value('i', 5) lock1 = val1.get_lock() obj1 = val1.get_obj() @@ -850,14 +859,14 @@ class _TestValue(BaseTestCase): class _TestArray(BaseTestCase): + ALLOWED_TYPES = ('processes',) + def f(self, seq): for i in range(1, len(seq)): seq[i] += seq[i-1] + @unittest.skipIf(c_int is None, "requires _ctypes") def test_array(self, raw=False): - if self.TYPE != 'processes': - return - seq = [680, 626, 934, 821, 150, 233, 548, 982, 714, 831] if raw: arr = self.RawArray('i', seq) @@ -880,13 +889,12 @@ class _TestArray(BaseTestCase): self.assertEqual(list(arr[:]), seq) + @unittest.skipIf(c_int is None, "requires _ctypes") def test_rawarray(self): self.test_array(raw=True) + @unittest.skipIf(c_int is None, "requires _ctypes") def test_getobj_getlock_obj(self): - if self.TYPE != 'processes': - return - arr1 = self.Array('i', list(range(10))) lock1 = arr1.get_lock() obj1 = arr1.get_obj() @@ -1538,12 +1546,6 @@ class _TestHeap(BaseTestCase): # # -try: - from ctypes import Structure, Value, copy, c_int, c_double -except ImportError: - Structure = object - c_int = c_double = None - class _Foo(Structure): _fields_ = [ ('x', c_int), @@ -1563,10 +1565,8 @@ class _TestSharedCTypes(BaseTestCase): for i in range(len(arr)): arr[i] *= 2 + @unittest.skipIf(c_int is None, "requires _ctypes") def test_sharedctypes(self, lock=False): - if c_int is None: - return - x = Value('i', 7, lock=lock) y = Value(ctypes.c_double, 1.0/3.0, lock=lock) foo = Value(_Foo, 3, 2, lock=lock) @@ -1589,10 +1589,8 @@ class _TestSharedCTypes(BaseTestCase): def test_synchronize(self): self.test_sharedctypes(lock=True) + @unittest.skipIf(c_int is None, "requires _ctypes") def test_copy(self): - if c_int is None: - return - foo = _Foo(2, 5.0) bar = copy(foo) foo.x = 0 @@ -1664,13 +1662,17 @@ class _TestImportStar(BaseTestCase): ALLOWED_TYPES = ('processes',) def test_import(self): - modules = ( + modules = [ 'multiprocessing', 'multiprocessing.connection', 'multiprocessing.heap', 'multiprocessing.managers', 'multiprocessing.pool', 'multiprocessing.process', - 'multiprocessing.reduction', 'multiprocessing.sharedctypes', + 'multiprocessing.reduction', 'multiprocessing.synchronize', 'multiprocessing.util' - ) + ] + + if c_int is not None: + # This module requires _ctypes + modules.append('multiprocessing.sharedctypes') for name in modules: __import__(name) @@ -1730,12 +1732,12 @@ class _TestLogging(BaseTestCase): class TestInvalidHandle(unittest.TestCase): + @unittest.skipIf(WIN32, "skipped on Windows") def test_invalid_handles(self): - if WIN32: - return conn = _multiprocessing.Connection(44977608) self.assertRaises(IOError, conn.poll) self.assertRaises(IOError, _multiprocessing.Connection, -1) + # # Functions used to create test cases from the base ones in this module # @@ -1752,7 +1754,7 @@ def get_attributes(Source, names): def create_test_cases(Mixin, type): result = {} glob = globals() - Type = type[0].upper() + type[1:] + Type = type.capitalize() for name in list(glob.keys()): if name.startswith('_Test'): diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py index 7393d25e427..c1e29b87fce 100644 --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -27,11 +27,15 @@ def warnings_state(module): except NameError: pass original_warnings = warning_tests.warnings + original_filters = module.filters try: + module.filters = original_filters[:] + module.simplefilter("once") warning_tests.warnings = module yield finally: warning_tests.warnings = original_warnings + module.filters = original_filters class BaseTest(unittest.TestCase): @@ -194,6 +198,7 @@ class WarnTests(unittest.TestCase): def test_message(self): with original_warnings.catch_warnings(record=True, module=self.module) as w: + self.module.simplefilter("once") for i in range(4): text = 'multi %d' %i # Different text on each call. self.module.warn(text) @@ -206,6 +211,7 @@ class WarnTests(unittest.TestCase): for ob in (Warning, None, 42): with original_warnings.catch_warnings(record=True, module=self.module) as w: + self.module.simplefilter("once") self.module.warn(ob) # Don't directly compare objects since # ``Warning() != Warning()``. diff --git a/Lib/turtle.py b/Lib/turtle.py index 1355d564adb..6f0605984fd 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -778,7 +778,7 @@ class TurtleScreenBase(object): # needs amendment if not isinstance(self.cv, ScrolledCanvas): return self.canvwidth, self.canvheight - if canvwidth is None and canvheight is None and bg is None: + if canvwidth is canvheight is bg is None: return self.cv.canvwidth, self.cv.canvheight if canvwidth is not None: self.canvwidth = canvwidth @@ -1046,7 +1046,7 @@ class TurtleScreen(TurtleScreenBase): >>> mode() 'logo' """ - if mode == None: + if mode is None: return self._mode mode = mode.lower() if mode not in ["standard", "logo", "world"]: @@ -1385,7 +1385,7 @@ class TurtleScreen(TurtleScreenBase): ### repeatedly pressing the up-arrow key, ### consequently drawing a hexagon """ - if fun == None: + if fun is None: if key in self._keys: self._keys.remove(key) elif key not in self._keys: @@ -1418,7 +1418,7 @@ class TurtleScreen(TurtleScreenBase): ### or by keeping pressed the up-arrow key. ### consequently drawing a hexagon. """ - if fun == None: + if fun is None: if key in self._keys: self._keys.remove(key) elif key is not None and key not in self._keys: @@ -1540,7 +1540,7 @@ class TNavigator(object): def _setmode(self, mode=None): """Set turtle-mode to 'standard', 'world' or 'logo'. """ - if mode == None: + if mode is None: return self._mode if mode not in ["standard", "logo", "world"]: return @@ -2795,7 +2795,7 @@ class RawTurtle(TPen, TNavigator): >>> turtle.shapesize(5, 5, 12) >>> turtle.shapesize(outline=8) """ - if stretch_wid is stretch_len is outline == None: + if stretch_wid is stretch_len is outline is None: stretch_wid, stretch_len = self._stretchfactor return stretch_wid, stretch_len, self._outlinewidth if stretch_wid == 0 or stretch_len == 0: diff --git a/Misc/NEWS b/Misc/NEWS index 1db6757b98e..36204c32941 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -20,6 +20,8 @@ Core and Builtins Library ------- +- Issue #8179: Fix macpath.realpath() on a non-existing path. + - Issue #8139: ossaudiodev didn't initialize its types properly, therefore some methods (such as oss_mixer_device.fileno()) were not available. Initial patch by Bertrand Janin. @@ -452,7 +454,7 @@ Tests test_capi (only seen so far on platforms where the curses module wasn't built), due to an uncleared exception. -- issue #7728: test_timeout was changed to use test_support.bind_port +- issue #7728: test_timeout was changed to use test.support.bind_port instead of a hard coded port. - Issue #7376: instead of running a self-test (which was failing) when called