diff --git a/Doc/info/Makefile b/Doc/info/Makefile index 3dbbd747bec..a9a037b4d81 100644 --- a/Doc/info/Makefile +++ b/Doc/info/Makefile @@ -34,10 +34,10 @@ $(WHATSNEW): python$(VERSION)-$(WHATSNEW).info check-emacs-version: @v="`$(EMACS) --version 2>&1 | egrep '^(GNU |X)Emacs [12]*'`"; \ - if `echo "$$v" | grep '^GNU Emacs 21' >/dev/null 2>&1`; then \ + if `echo "$$v" | grep '^GNU Emacs 2[12]' >/dev/null 2>&1`; then \ echo "Using $(EMACS) to build the info docs"; \ else \ - echo "GNU Emacs 21 is required to build the info docs"; \ + echo "GNU Emacs 21 or 22 is required to build the info docs"; \ echo "Found $$v"; \ false; \ fi diff --git a/Doc/lib/librunpy.tex b/Doc/lib/librunpy.tex index c7a7e51971c..60707caf4ba 100644 --- a/Doc/lib/librunpy.tex +++ b/Doc/lib/librunpy.tex @@ -56,9 +56,11 @@ the top level namespace of the \module{__builtin__} module. If the argument \var{alter_sys} is supplied and evaluates to \code{True}, then \code{sys.argv[0]} is updated with the value of \code{__file__} and \code{sys.modules[__name__]} is updated with a -temporary module object for the module being executed. Both -\code{sys.argv[0]} and \code{sys.modules[__name__]} are restored to -their original values before the function returns. +new module object for the module being executed. Note that neither +\code{sys.argv[0]} nor \code{sys.modules[__name__]} are restored to +their original values before the function returns - if client code +needs these values preserved, it must either save them explicitly or +else avoid enabling the automatic alterations to \module{sys}. Note that this manipulation of \module{sys} is not thread-safe. Other threads may see the partially initialised module, as well as the diff --git a/Doc/lib/libxmlrpclib.tex b/Doc/lib/libxmlrpclib.tex index 2a6f3f62328..22f29b8ae33 100644 --- a/Doc/lib/libxmlrpclib.tex +++ b/Doc/lib/libxmlrpclib.tex @@ -94,7 +94,8 @@ When passing strings, characters special to XML such as \samp{<}, \samp{>}, and \samp{\&} will be automatically escaped. However, it's the caller's responsibility to ensure that the string is free of characters that aren't allowed in XML, such as the control characters -with ASCII values between 0 and 31; failing to do this will result in +with ASCII values between 0 and 31 (except, of course, tab, newline and +carriage return); failing to do this will result in an XML-RPC request that isn't well-formed XML. If you have to pass arbitrary strings via XML-RPC, use the \class{Binary} wrapper class described below. diff --git a/Doc/tut/tut.tex b/Doc/tut/tut.tex index a41487be145..a322eb595b4 100644 --- a/Doc/tut/tut.tex +++ b/Doc/tut/tut.tex @@ -3748,7 +3748,9 @@ been handled by an \keyword{except} clause (or it has occurred in a \keyword{finally} clause has been executed. The \keyword{finally} clause is also executed ``on the way out'' when any other clause of the \keyword{try} statement is left via a \keyword{break}, \keyword{continue} -or \keyword{return} statement. A more complicated example: +or \keyword{return} statement. A more complicated example (having +\keyword{except} and \keyword{finally} clauses in the same \keyword{try} +statement works as of Python 2.5): \begin{verbatim} >>> def divide(x, y): diff --git a/Doc/whatsnew/whatsnew25.tex b/Doc/whatsnew/whatsnew25.tex index b2f73804e4c..b6bac493bb0 100644 --- a/Doc/whatsnew/whatsnew25.tex +++ b/Doc/whatsnew/whatsnew25.tex @@ -640,15 +640,20 @@ with expression [as variable]: \end{verbatim} The expression is evaluated, and it should result in an object that -supports the context management protocol. This object may return a -value that can optionally be bound to the name \var{variable}. (Note -carefully that \var{variable} is \emph{not} assigned the result of -\var{expression}.) The object can then run set-up code -before \var{with-block} is executed and some clean-up code -is executed after the block is done, even if the block raised an exception. +supports the context management protocol (that is, has \method{__enter__()} +and \method{__exit__()} methods. -To enable the statement in Python 2.5, you need -to add the following directive to your module: +The object's \method{__enter__()} is called before \var{with-block} is +executed and therefore can run set-up code. It also may return a value +that is bound to the name \var{variable}, if given. (Note carefully +that \var{variable} is \emph{not} assigned the result of \var{expression}.) + +After execution of the \var{with-block} is finished, the object's +\method{__exit__()} method is called, even if the block raised an exception, +and can therefore run clean-up code. + +To enable the statement in Python 2.5, you need to add the following +directive to your module: \begin{verbatim} from __future__ import with_statement @@ -668,9 +673,13 @@ with open('/etc/passwd', 'r') as f: \end{verbatim} After this statement has executed, the file object in \var{f} will -have been automatically closed, even if the 'for' loop +have been automatically closed, even if the \keyword{for} loop raised an exception part-way through the block. +\note{In this case, \var{f} is the same object created by + \function{open()}, because \method{file.__enter__()} returns + \var{self}.} + The \module{threading} module's locks and condition variables also support the '\keyword{with}' statement: diff --git a/Include/structmember.h b/Include/structmember.h index a46788dfaba..b7d00b713d4 100644 --- a/Include/structmember.h +++ b/Include/structmember.h @@ -68,11 +68,12 @@ typedef struct PyMemberDef { #ifdef HAVE_LONG_LONG #define T_LONGLONG 17 #define T_ULONGLONG 18 -#define T_PYSSIZET 19 /* Py_ssize_t */ #endif /* HAVE_LONG_LONG */ +#define T_PYSSIZET 19 /* Py_ssize_t */ #define T_NONE 20 /* Value is always None */ + /* Flags */ #define READONLY 1 #define RO READONLY /* Shorthand */ diff --git a/Lib/asynchat.py b/Lib/asynchat.py index 22069848847..9157f339a6b 100644 --- a/Lib/asynchat.py +++ b/Lib/asynchat.py @@ -104,7 +104,7 @@ class async_chat (asyncore.dispatcher): if not terminator: # no terminator, collect it all self.collect_incoming_data (self.ac_in_buffer) - self.ac_in_buffer = '' + self.ac_in_buffer = b'' elif isinstance(terminator, int) or isinstance(terminator, int): # numeric terminator n = terminator diff --git a/Lib/distutils/command/register.py b/Lib/distutils/command/register.py index 53f4293e177..10a903e33de 100644 --- a/Lib/distutils/command/register.py +++ b/Lib/distutils/command/register.py @@ -22,7 +22,7 @@ class register(Command): description = ("register the distribution with the Python package index") - DEFAULT_REPOSITORY = 'http://www.python.org/pypi' + DEFAULT_REPOSITORY = 'http://pypi.python.org/pypi' user_options = [ ('repository=', 'r', diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py index 438ae99a9c7..d1cf87a871a 100644 --- a/Lib/distutils/command/upload.py +++ b/Lib/distutils/command/upload.py @@ -20,7 +20,7 @@ class upload(Command): description = "upload binary package to PyPI" - DEFAULT_REPOSITORY = 'http://www.python.org/pypi' + DEFAULT_REPOSITORY = 'http://pypi.python.org/pypi' user_options = [ ('repository=', 'r', diff --git a/Lib/httplib.py b/Lib/httplib.py index 89af296af82..0931446e59d 100644 --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -1129,6 +1129,9 @@ class FakeSocket(SharedSocketClient): def __getattr__(self, attr): return getattr(self._sock, attr) + def close(self): + SharedSocketClient.close(self) + self._ssl = None class HTTPSConnection(HTTPConnection): "This class allows communication via SSL." diff --git a/Lib/runpy.py b/Lib/runpy.py index b0129c9a472..b463f2b1299 100755 --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -33,36 +33,21 @@ def _run_code(code, run_globals, init_globals, return run_globals def _run_module_code(code, init_globals=None, - mod_name=None, mod_fname=None, - mod_loader=None, alter_sys=False): + mod_name=None, mod_fname=None, + mod_loader=None, alter_sys=False): """Helper for run_module""" # Set up the top level namespace dictionary if alter_sys: - # Modify sys.argv[0] and sys.module[mod_name] - temp_module = imp.new_module(mod_name) - mod_globals = temp_module.__dict__ - saved_argv0 = sys.argv[0] - restore_module = mod_name in sys.modules - if restore_module: - saved_module = sys.modules[mod_name] + # Modify sys.argv[0] and sys.modules[mod_name] sys.argv[0] = mod_fname - sys.modules[mod_name] = temp_module - try: - _run_code(code, mod_globals, init_globals, - mod_name, mod_fname, mod_loader) - finally: - sys.argv[0] = saved_argv0 - if restore_module: - sys.modules[mod_name] = saved_module - else: - del sys.modules[mod_name] - # Copy the globals of the temporary module, as they - # may be cleared when the temporary module goes away - return mod_globals.copy() + module = imp.new_module(mod_name) + sys.modules[mod_name] = module + mod_globals = module.__dict__ else: # Leave the sys module alone - return _run_code(code, {}, init_globals, - mod_name, mod_fname, mod_loader) + mod_globals = {} + return _run_code(code, mod_globals, init_globals, + mod_name, mod_fname, mod_loader) # This helper is needed due to a missing component in the PEP 302 @@ -84,10 +69,13 @@ def run_module(mod_name, init_globals=None, """ loader = get_loader(mod_name) if loader is None: - raise ImportError("No module named " + mod_name) + raise ImportError("No module named %s" % mod_name) + if loader.is_package(mod_name): + raise ImportError(("%s is a package and cannot " + + "be directly executed") % mod_name) code = loader.get_code(mod_name) if code is None: - raise ImportError("No code object available for " + mod_name) + raise ImportError("No code object available for %s" % mod_name) filename = _get_filename(loader, mod_name) if run_name is None: run_name = mod_name diff --git a/Lib/smtpd.py b/Lib/smtpd.py index 2e09c5ad992..98ef436857b 100755 --- a/Lib/smtpd.py +++ b/Lib/smtpd.py @@ -132,7 +132,7 @@ class SMTPChannel(asynchat.async_chat): # Implementation of base class abstract method def collect_incoming_data(self, data): - self.__line.append(data) + self.__line.append(str(data, "utf8")) # Implementation of base class abstract method def found_terminator(self): diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 67904a2f7a0..0d61f50142f 100755 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -344,11 +344,11 @@ class SMTP: self.file = self.sock.makefile('rb') while 1: line = self.file.readline() - if line == '': + if not line: self.close() raise SMTPServerDisconnected("Connection unexpectedly closed") if self.debuglevel > 0: print('reply:', repr(line), file=stderr) - resp.append(line[4:].strip(b' \t\n')) + resp.append(line[4:].strip(b' \t\r\n')) code=line[:3] # Check that the error code is syntactically correct. # Don't attempt to read a continuation line if it is broken. @@ -358,7 +358,7 @@ class SMTP: errcode = -1 break # Check if multiline response. - if line[3:4]!="-": + if line[3:4] != b"-": break errmsg = b"\n".join(resp) diff --git a/Lib/test/test_asynchat.py b/Lib/test/test_asynchat.py index 7629296b002..be8e116fdc3 100644 --- a/Lib/test/test_asynchat.py +++ b/Lib/test/test_asynchat.py @@ -3,12 +3,17 @@ import thread # If this fails, we can't test this module import asyncore, asynchat, socket, threading, time import unittest +import sys from test import test_support HOST = "127.0.0.1" PORT = 54322 +SERVER_QUIT = b'QUIT\n' class echo_server(threading.Thread): + # parameter to determine the number of bytes passed back to the + # client each send + chunk_size = 1 def run(self): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -17,15 +22,28 @@ class echo_server(threading.Thread): PORT = test_support.bind_port(sock, HOST, PORT) sock.listen(1) conn, client = sock.accept() - buffer = b"" - while b"\n" not in buffer: + self.buffer = b"" + # collect data until quit message is seen + while SERVER_QUIT not in self.buffer: data = conn.recv(1) if not data: break - buffer = buffer + data - while buffer: - n = conn.send(buffer) - buffer = buffer[n:] + self.buffer = self.buffer + data + + # remove the SERVER_QUIT message + self.buffer = self.buffer.replace(SERVER_QUIT, b'') + + # re-send entire set of collected data + try: + # this may fail on some tests, such as test_close_when_done, since + # the client closes the channel when it's done sending + while self.buffer: + n = conn.send(self.buffer[:self.chunk_size]) + time.sleep(0.001) + self.buffer = self.buffer[n:] + except: + pass + conn.close() sock.close() @@ -33,7 +51,7 @@ class echo_client(asynchat.async_chat): def __init__(self, terminator): asynchat.async_chat.__init__(self) - self.contents = None + self.contents = [] self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect((HOST, PORT)) self.set_terminator(terminator) @@ -41,53 +59,194 @@ class echo_client(asynchat.async_chat): def handle_connect(self): pass - ##print "Connected" + + if sys.platform == 'darwin': + # select.poll returns a select.POLLHUP at the end of the tests + # on darwin, so just ignore it + def handle_expt(self): + pass def collect_incoming_data(self, data): - self.buffer = self.buffer + data + self.buffer += data def found_terminator(self): - #print "Received:", repr(self.buffer) - self.contents = self.buffer + self.contents.append(self.buffer) self.buffer = b"" - self.close() class TestAsynchat(unittest.TestCase): + usepoll = False + def setUp (self): pass def tearDown (self): pass - def test_line_terminator(self): + def line_terminator_check(self, term, server_chunk): s = echo_server() + s.chunk_size = server_chunk s.start() - time.sleep(1) # Give server time to initialize - c = echo_client('\n') - c.push("hello ") - c.push("world\n") - asyncore.loop() + time.sleep(0.5) # Give server time to initialize + c = echo_client(term) + c.push(b"hello ") + c.push(bytes("world%s" % term)) + c.push(bytes("I'm not dead yet!%s" % term)) + c.push(SERVER_QUIT) + asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) s.join() - self.assertEqual(c.contents, b'hello world') + self.assertEqual(c.contents, [b"hello world", b"I'm not dead yet!"]) - def test_numeric_terminator(self): + # the line terminator tests below check receiving variously-sized + # chunks back from the server in order to exercise all branches of + # async_chat.handle_read + + def test_line_terminator1(self): + # test one-character terminator + for l in (1,2,3): + self.line_terminator_check(b'\n', l) + + def test_line_terminator2(self): + # test two-character terminator + for l in (1,2,3): + self.line_terminator_check(b'\r\n', l) + + def test_line_terminator3(self): + # test three-character terminator + for l in (1,2,3): + self.line_terminator_check(b'qqq', l) + + def numeric_terminator_check(self, termlen): # Try reading a fixed number of bytes s = echo_server() s.start() - time.sleep(1) # Give server time to initialize - c = echo_client(6) - c.push("hello ") - c.push("world\n") - asyncore.loop() + time.sleep(0.5) # Give server time to initialize + c = echo_client(termlen) + data = b"hello world, I'm not dead yet!\n" + c.push(data) + c.push(SERVER_QUIT) + asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) s.join() - self.assertEqual(c.contents, b'hello ') + self.assertEqual(c.contents, [data[:termlen]]) + + def test_numeric_terminator1(self): + # check that ints & longs both work (since type is + # explicitly checked in async_chat.handle_read) + self.numeric_terminator_check(1) + + def test_numeric_terminator2(self): + self.numeric_terminator_check(6) + + def test_none_terminator(self): + # Try reading a fixed number of bytes + s = echo_server() + s.start() + time.sleep(0.5) # Give server time to initialize + c = echo_client(None) + data = b"hello world, I'm not dead yet!\n" + c.push(data) + c.push(SERVER_QUIT) + asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) + s.join() + + self.assertEqual(c.contents, []) + self.assertEqual(c.buffer, data) + + def test_simple_producer(self): + s = echo_server() + s.start() + time.sleep(0.5) # Give server time to initialize + c = echo_client(b'\n') + data = b"hello world\nI'm not dead yet!\n" + p = asynchat.simple_producer(data+SERVER_QUIT, buffer_size=8) + c.push_with_producer(p) + asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) + s.join() + + self.assertEqual(c.contents, [b"hello world", b"I'm not dead yet!"]) + + def test_string_producer(self): + s = echo_server() + s.start() + time.sleep(0.5) # Give server time to initialize + c = echo_client(b'\n') + data = b"hello world\nI'm not dead yet!\n" + c.push_with_producer(data+SERVER_QUIT) + asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) + s.join() + + self.assertEqual(c.contents, [b"hello world", b"I'm not dead yet!"]) + + def test_empty_line(self): + # checks that empty lines are handled correctly + s = echo_server() + s.start() + time.sleep(0.5) # Give server time to initialize + c = echo_client(b'\n') + c.push("hello world\n\nI'm not dead yet!\n") + c.push(SERVER_QUIT) + asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) + s.join() + + self.assertEqual(c.contents, + [b"hello world", b"", b"I'm not dead yet!"]) + + def test_close_when_done(self): + s = echo_server() + s.start() + time.sleep(0.5) # Give server time to initialize + c = echo_client(b'\n') + c.push("hello world\nI'm not dead yet!\n") + c.push(SERVER_QUIT) + c.close_when_done() + asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) + s.join() + + self.assertEqual(c.contents, []) + # the server might have been able to send a byte or two back, but this + # at least checks that it received something and didn't just fail + # (which could still result in the client not having received anything) + self.assertTrue(len(s.buffer) > 0) + + +class TestAsynchat_WithPoll(TestAsynchat): + usepoll = True + +class TestHelperFunctions(unittest.TestCase): + def test_find_prefix_at_end(self): + self.assertEqual(asynchat.find_prefix_at_end("qwerty\r", "\r\n"), 1) + self.assertEqual(asynchat.find_prefix_at_end("qwertydkjf", "\r\n"), 0) + +class TestFifo(unittest.TestCase): + def test_basic(self): + f = asynchat.fifo() + f.push(7) + f.push(b'a') + self.assertEqual(len(f), 2) + self.assertEqual(f.first(), 7) + self.assertEqual(f.pop(), (1, 7)) + self.assertEqual(len(f), 1) + self.assertEqual(f.first(), b'a') + self.assertEqual(f.is_empty(), False) + self.assertEqual(f.pop(), (1, b'a')) + self.assertEqual(len(f), 0) + self.assertEqual(f.is_empty(), True) + self.assertEqual(f.pop(), (0, None)) + + def test_given_list(self): + f = asynchat.fifo([b'x', 17, 3]) + self.assertEqual(len(f), 3) + self.assertEqual(f.pop(), (1, b'x')) + self.assertEqual(f.pop(), (1, 17)) + self.assertEqual(f.pop(), (1, 3)) + self.assertEqual(f.pop(), (0, None)) def test_main(verbose=None): - test_support.run_unittest(TestAsynchat) + test_support.run_unittest(TestAsynchat, TestAsynchat_WithPoll, + TestHelperFunctions, TestFifo) if __name__ == "__main__": test_main(verbose=True) diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py index 6f848a72489..33c2fb26363 100644 --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -12,7 +12,7 @@ from test.test_support import TESTFN, run_unittest, unlink from io import StringIO, BytesIO HOST = "127.0.0.1" -PORT = 54329 +PORT = None class dummysocket: def __init__(self): @@ -53,12 +53,14 @@ class crashingdummy: # used when testing senders; just collects what it gets until newline is sent def capture_server(evt, buf): - serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - serv.settimeout(3) - serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - serv.bind(("", PORT)) - serv.listen(5) try: + serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + serv.settimeout(3) + serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + serv.bind(("", 0)) + global PORT + PORT = serv.getsockname()[1] + serv.listen(5) conn, addr = serv.accept() except socket.timeout: pass @@ -79,6 +81,7 @@ def capture_server(evt, buf): conn.close() finally: serv.close() + PORT = None evt.set() @@ -107,87 +110,83 @@ class HelperFunctionTests(unittest.TestCase): asyncore._exception(tr2) self.assertEqual(tr2.error_handled, True) -## Commented out these tests because test a non-documented function -## (which is actually public, why it's not documented?). Anyway, the -## tests *and* the function uses constants in the select module that -## are not present in Windows systems (see this thread: -## http://mail.python.org/pipermail/python-list/2001-October/109973.html) -## Note even that these constants are mentioned in the select -## documentation, as a parameter of "poll" method "register", but are -## not explicit declared as constants of the module. -## . Facundo Batista -## -## def test_readwrite(self): -## # Check that correct methods are called by readwrite() -## -## class testobj: -## def __init__(self): -## self.read = False -## self.write = False -## self.expt = False -## -## def handle_read_event(self): -## self.read = True -## -## def handle_write_event(self): -## self.write = True -## -## def handle_expt_event(self): -## self.expt = True -## -## def handle_error(self): -## self.error_handled = True -## -## for flag in (select.POLLIN, select.POLLPRI): -## tobj = testobj() -## self.assertEqual(tobj.read, False) -## asyncore.readwrite(tobj, flag) -## self.assertEqual(tobj.read, True) -## -## # check that ExitNow exceptions in the object handler method -## # bubbles all the way up through asyncore readwrite call -## tr1 = exitingdummy() -## self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag) -## -## # check that an exception other than ExitNow in the object handler -## # method causes the handle_error method to get called -## tr2 = crashingdummy() -## asyncore.readwrite(tr2, flag) -## self.assertEqual(tr2.error_handled, True) -## -## tobj = testobj() -## self.assertEqual(tobj.write, False) -## asyncore.readwrite(tobj, select.POLLOUT) -## self.assertEqual(tobj.write, True) -## -## # check that ExitNow exceptions in the object handler method -## # bubbles all the way up through asyncore readwrite call -## tr1 = exitingdummy() -## self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, -## select.POLLOUT) -## -## # check that an exception other than ExitNow in the object handler -## # method causes the handle_error method to get called -## tr2 = crashingdummy() -## asyncore.readwrite(tr2, select.POLLOUT) -## self.assertEqual(tr2.error_handled, True) -## -## for flag in (select.POLLERR, select.POLLHUP, select.POLLNVAL): -## tobj = testobj() -## self.assertEqual(tobj.expt, False) -## asyncore.readwrite(tobj, flag) -## self.assertEqual(tobj.expt, True) -## -## # check that ExitNow exceptions in the object handler method -## # bubbles all the way up through asyncore readwrite calls -## tr1 = exitingdummy() -## self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag) -## -## # check that an exception other than ExitNow in the object handler -## # method causes the handle_error method to get called -## tr2 = crashingdummy() -## asyncore.readwrite(tr2, flag) -## self.assertEqual(tr2.error_handled, True) + # asyncore.readwrite uses constants in the select module that + # are not present in Windows systems (see this thread: + # http://mail.python.org/pipermail/python-list/2001-October/109973.html) + # These constants should be present as long as poll is available + + if hasattr(select, 'poll'): + def test_readwrite(self): + # Check that correct methods are called by readwrite() + + class testobj: + def __init__(self): + self.read = False + self.write = False + self.expt = False + + def handle_read_event(self): + self.read = True + + def handle_write_event(self): + self.write = True + + def handle_expt_event(self): + self.expt = True + + def handle_error(self): + self.error_handled = True + + for flag in (select.POLLIN, select.POLLPRI): + tobj = testobj() + self.assertEqual(tobj.read, False) + asyncore.readwrite(tobj, flag) + self.assertEqual(tobj.read, True) + + # check that ExitNow exceptions in the object handler method + # bubbles all the way up through asyncore readwrite call + tr1 = exitingdummy() + self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag) + + # check that an exception other than ExitNow in the object handler + # method causes the handle_error method to get called + tr2 = crashingdummy() + asyncore.readwrite(tr2, flag) + self.assertEqual(tr2.error_handled, True) + + tobj = testobj() + self.assertEqual(tobj.write, False) + asyncore.readwrite(tobj, select.POLLOUT) + self.assertEqual(tobj.write, True) + + # check that ExitNow exceptions in the object handler method + # bubbles all the way up through asyncore readwrite call + tr1 = exitingdummy() + self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, + select.POLLOUT) + + # check that an exception other than ExitNow in the object handler + # method causes the handle_error method to get called + tr2 = crashingdummy() + asyncore.readwrite(tr2, select.POLLOUT) + self.assertEqual(tr2.error_handled, True) + + for flag in (select.POLLERR, select.POLLHUP, select.POLLNVAL): + tobj = testobj() + self.assertEqual(tobj.expt, False) + asyncore.readwrite(tobj, flag) + self.assertEqual(tobj.expt, True) + + # check that ExitNow exceptions in the object handler method + # bubbles all the way up through asyncore readwrite calls + tr1 = exitingdummy() + self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag) + + # check that an exception other than ExitNow in the object handler + # method causes the handle_error method to get called + tr2 = crashingdummy() + asyncore.readwrite(tr2, flag) + self.assertEqual(tr2.error_handled, True) def test_closeall(self): self.closeall_check(False) @@ -343,12 +342,26 @@ class DispatcherWithSendTests(unittest.TestCase): self.evt = threading.Event() cap = BytesIO() threading.Thread(target=capture_server, args=(self.evt, cap)).start() - time.sleep(1) # Give server time to initialize - data = b"Suppose there isn't a 16-ton weight?"*5 + # wait until server thread has assigned a port number + n = 1000 + while PORT is None and n > 0: + time.sleep(0.01) + n -= 1 + + # wait a little longer for the server to initialize (it sometimes + # refuses connections on slow machines without this wait) + time.sleep(0.2) + + data = b"Suppose there isn't a 16-ton weight?" d = dispatcherwithsend_noread() d.create_socket(socket.AF_INET, socket.SOCK_STREAM) d.connect((HOST, PORT)) + + # give time for socket to connect + time.sleep(0.1) + + d.send(data) d.send(data) d.send(b'\n') @@ -359,7 +372,7 @@ class DispatcherWithSendTests(unittest.TestCase): self.evt.wait() - self.assertEqual(cap.getvalue(), data) + self.assertEqual(cap.getvalue(), data*2) class DispatcherWithSendTests_UsePoll(DispatcherWithSendTests): diff --git a/Lib/test/test_codecmaps_cn.py b/Lib/test/test_codecmaps_cn.py index 75541ac8b71..344fc562f71 100644 --- a/Lib/test/test_codecmaps_cn.py +++ b/Lib/test/test_codecmaps_cn.py @@ -19,6 +19,13 @@ class TestGBKMap(test_multibytecodec_support.TestBase_Mapping, mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/' \ 'MICSFT/WINDOWS/CP936.TXT' +class TestGB18030Map(test_multibytecodec_support.TestBase_Mapping, + unittest.TestCase): + encoding = 'gb18030' + mapfileurl = 'http://source.icu-project.org/repos/icu/data/' \ + 'trunk/charset/data/xml/gb-18030-2000.xml' + + def test_main(): test_support.run_unittest(__name__) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index e5c6ead80fb..c28902b94f3 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -12,7 +12,11 @@ class MathTests(unittest.TestCase): def ftest(self, name, value, expected): if abs(value-expected) > eps: - self.fail('%s returned %f, expected %f'%\ + # Use %r instead of %f so the error message + # displays full precision. Otherwise discrepancies + # in the last few bits will lead to very confusing + # error messages + self.fail('%s returned %r, expected %r' % (name, value, expected)) def testConstants(self): @@ -92,6 +96,10 @@ class MathTests(unittest.TestCase): self.ftest('floor(-0.5)', math.floor(-0.5), -1) self.ftest('floor(-1.0)', math.floor(-1.0), -1) self.ftest('floor(-1.5)', math.floor(-1.5), -2) + # pow() relies on floor() to check for integers + # This fails on some platforms - so check it here + self.ftest('floor(1.23e167)', math.floor(1.23e167), 1.23e167) + self.ftest('floor(-1.23e167)', math.floor(-1.23e167), -1.23e167) def testFmod(self): self.assertRaises(TypeError, math.fmod) diff --git a/Lib/test/test_multibytecodec_support.py b/Lib/test/test_multibytecodec_support.py index 40a67ea12b0..20732237720 100644 --- a/Lib/test/test_multibytecodec_support.py +++ b/Lib/test/test_multibytecodec_support.py @@ -5,7 +5,7 @@ # import sys, codecs, os.path -import unittest +import unittest, re from test import test_support from io import BytesIO @@ -272,6 +272,12 @@ class TestBase_Mapping(unittest.TestCase): return test_support.open_urlresource(self.mapfileurl) def test_mapping_file(self): + if self.mapfileurl.endswith('.xml'): + self._test_mapping_file_ucm() + else: + self._test_mapping_file_plain() + + def _test_mapping_file_plain(self): unichrs = lambda s: ''.join(map(chr, map(eval, s.split('+')))) urt_wa = {} @@ -303,6 +309,14 @@ class TestBase_Mapping(unittest.TestCase): self._testpoint(csetch, unich) + def _test_mapping_file_ucm(self): + ucmdata = self.open_mapping_file().read() + uc = re.findall('', ucmdata) + for uni, coded in uc: + unich = chr(int(uni, 16)) + codech = bytes(int(c, 16) for c in coded.split()) + self._testpoint(codech, unich) + def test_mapping_supplemental(self): for mapping in self.supmaps: self._testpoint(*mapping) diff --git a/Lib/test/test_pow.py b/Lib/test/test_pow.py index 62c641b10bd..9b358f1970e 100644 --- a/Lib/test/test_pow.py +++ b/Lib/test/test_pow.py @@ -106,6 +106,9 @@ class PowTest(unittest.TestCase): # platform pow() was buggy, and Python didn't worm around it. eq = self.assertEquals a = -1.0 + # The next two tests can still fail if the platform floor() + # function doesn't treat all large inputs as integers + # test_math should also fail if that is happening eq(pow(a, 1.23e167), 1.0) eq(pow(a, -1.23e167), 1.0) for b in range(-10, 11): diff --git a/Lib/test/test_resource.py b/Lib/test/test_resource.py index 2450e782f6d..25fea977c30 100644 --- a/Lib/test/test_resource.py +++ b/Lib/test/test_resource.py @@ -49,17 +49,24 @@ class ResourceTest(unittest.TestCase): except ValueError: limit_set = False f = open(test_support.TESTFN, "wb") - f.write("X" * 1024) try: - f.write("Y") - f.flush() - except IOError: - if not limit_set: - raise - f.close() - os.unlink(test_support.TESTFN) + f.write("X" * 1024) + try: + f.write("Y") + f.flush() + except IOError: + if not limit_set: + raise + if limit_set: + # Close will attempt to flush the byte we wrote + # Restore limit first to avoid getting a spurious error + resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max)) + finally: + f.close() + os.unlink(test_support.TESTFN) finally: - resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max)) + if limit_set: + resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max)) def test_fsize_toobig(self): # Be sure that setrlimit is checking for really large values diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py index 868662d10bb..d10e40fc8d2 100644 --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -21,12 +21,12 @@ class RunModuleCodeTest(unittest.TestCase): "# Check the sys module\n" "import sys\n" "run_argv0 = sys.argv[0]\n" - "if __name__ in sys.modules:\n" - " run_name = sys.modules[__name__].__name__\n" + "run_name_in_sys_modules = __name__ in sys.modules\n" + "if run_name_in_sys_modules:\n" + " module_in_sys_modules = globals() is sys.modules[__name__].__dict__\n" "# Check nested operation\n" "import runpy\n" - "nested = runpy._run_module_code('x=1\\n', mod_name='',\n" - " alter_sys=True)\n" + "nested = runpy._run_module_code('x=1\\n', mod_name='')\n" ) @@ -37,34 +37,44 @@ class RunModuleCodeTest(unittest.TestCase): loader = "Now you're just being silly" d1 = dict(initial=initial) saved_argv0 = sys.argv[0] - d2 = _run_module_code(self.test_source, - d1, - name, - file, - loader, - True) - self.failUnless("result" not in d1) - self.failUnless(d2["initial"] is initial) - self.assertEqual(d2["result"], self.expected_result) - self.assertEqual(d2["nested"]["x"], 1) - self.failUnless(d2["__name__"] is name) - self.failUnless(d2["run_name"] is name) - self.failUnless(d2["__file__"] is file) - self.failUnless(d2["run_argv0"] is file) - self.failUnless(d2["__loader__"] is loader) - self.failUnless(sys.argv[0] is saved_argv0) - self.failUnless(name not in sys.modules) + try: + d2 = _run_module_code(self.test_source, + d1, + name, + file, + loader, + alter_sys=True) + self.failUnless("result" not in d1) + self.failUnless(d2["initial"] is initial) + self.assertEqual(d2["result"], self.expected_result) + self.assertEqual(d2["nested"]["x"], 1) + self.assertEqual(d2["nested"]["__name__"], "") + self.failUnless(d2["__name__"] is name) + self.failUnless(d2["__file__"] is file) + self.failUnless(d2["__loader__"] is loader) + self.failUnless(d2["run_argv0"] is file) + self.failUnless(d2["run_name_in_sys_modules"]) + self.failUnless(d2["module_in_sys_modules"]) + self.failUnless(sys.argv[0] is not saved_argv0) + self.failUnless(name in sys.modules) + finally: + sys.argv[0] = saved_argv0 + if name in sys.modules: + del sys.modules[name] def test_run_module_code_defaults(self): saved_argv0 = sys.argv[0] d = _run_module_code(self.test_source) self.assertEqual(d["result"], self.expected_result) + self.failUnless(d["nested"]["x"] == 1) + self.failUnless(d["nested"]["__name__"] == "") self.failUnless(d["__name__"] is None) self.failUnless(d["__file__"] is None) self.failUnless(d["__loader__"] is None) self.failUnless(d["run_argv0"] is saved_argv0) - self.failUnless("run_name" not in d) + self.failUnless(not d["run_name_in_sys_modules"]) self.failUnless(sys.argv[0] is saved_argv0) + self.failUnless(None not in sys.modules) class RunModuleTest(unittest.TestCase): @@ -77,19 +87,29 @@ class RunModuleTest(unittest.TestCase): self.fail("Expected import error for " + mod_name) def test_invalid_names(self): + # Builtin module self.expect_import_error("sys") + # Non-existent modules self.expect_import_error("sys.imp.eric") self.expect_import_error("os.path.half") self.expect_import_error("a.bee") self.expect_import_error(".howard") self.expect_import_error("..eaten") + # Package + self.expect_import_error("logging") def test_library_module(self): run_module("runpy") + def _add_pkg_dir(self, pkg_dir): + os.mkdir(pkg_dir) + pkg_fname = os.path.join(pkg_dir, "__init__"+os.extsep+"py") + pkg_file = open(pkg_fname, "w") + pkg_file.close() + return pkg_fname + def _make_pkg(self, source, depth): pkg_name = "__runpy_pkg__" - init_fname = "__init__"+os.extsep+"py" test_fname = "runpy_test"+os.extsep+"py" pkg_dir = sub_dir = tempfile.mkdtemp() if verbose: print(" Package tree in:", sub_dir) @@ -97,11 +117,8 @@ class RunModuleTest(unittest.TestCase): if verbose: print(" Updated sys.path:", sys.path[0]) for i in range(depth): sub_dir = os.path.join(sub_dir, pkg_name) - os.mkdir(sub_dir) + pkg_fname = self._add_pkg_dir(sub_dir) if verbose: print(" Next level in:", sub_dir) - pkg_fname = os.path.join(sub_dir, init_fname) - pkg_file = open(pkg_fname, "w") - pkg_file.close() if verbose: print(" Created:", pkg_fname) mod_fname = os.path.join(sub_dir, test_fname) mod_file = open(mod_fname, "w") @@ -112,13 +129,9 @@ class RunModuleTest(unittest.TestCase): return pkg_dir, mod_fname, mod_name def _del_pkg(self, top, depth, mod_name): - for i in range(depth+1): # Don't forget the module itself - parts = mod_name.rsplit(".", i) - entry = parts[0] - try: + for entry in list(sys.modules): + if entry.startswith("__runpy_pkg__"): del sys.modules[entry] - except KeyError as ex: - if verbose: print(ex) # Persist with cleaning up if verbose: print(" Removed sys.modules entries") del sys.path[0] if verbose: print(" Removed sys.path entry") @@ -146,23 +159,81 @@ class RunModuleTest(unittest.TestCase): try: if verbose: print("Running from source:", mod_name) d1 = run_module(mod_name) # Read from source + self.failUnless("x" in d1) self.assertEqual(d1["x"], 1) del d1 # Ensure __loader__ entry doesn't keep file open __import__(mod_name) os.remove(mod_fname) if verbose: print("Running from compiled:", mod_name) d2 = run_module(mod_name) # Read from bytecode + self.failUnless("x" in d2) self.assertEqual(d2["x"], 1) del d2 # Ensure __loader__ entry doesn't keep file open finally: self._del_pkg(pkg_dir, depth, mod_name) if verbose: print("Module executed successfully") + def _add_relative_modules(self, base_dir, depth): + if depth <= 1: + raise ValueError("Relative module test needs depth > 1") + pkg_name = "__runpy_pkg__" + module_dir = base_dir + for i in range(depth): + parent_dir = module_dir + module_dir = os.path.join(module_dir, pkg_name) + # Add sibling module + sibling_fname = os.path.join(module_dir, "sibling"+os.extsep+"py") + sibling_file = open(sibling_fname, "w") + sibling_file.close() + if verbose: print(" Added sibling module:", sibling_fname) + # Add nephew module + uncle_dir = os.path.join(parent_dir, "uncle") + self._add_pkg_dir(uncle_dir) + if verbose: print(" Added uncle package:", uncle_dir) + cousin_dir = os.path.join(uncle_dir, "cousin") + self._add_pkg_dir(cousin_dir) + if verbose: print(" Added cousin package:", cousin_dir) + nephew_fname = os.path.join(cousin_dir, "nephew"+os.extsep+"py") + nephew_file = open(nephew_fname, "w") + nephew_file.close() + if verbose: print(" Added nephew module:", nephew_fname) + + def _check_relative_imports(self, depth, run_name=None): + contents = """\ +from __future__ import absolute_import +from . import sibling +from ..uncle.cousin import nephew +""" + pkg_dir, mod_fname, mod_name = ( + self._make_pkg(contents, depth)) + try: + self._add_relative_modules(pkg_dir, depth) + if verbose: print("Running from source:", mod_name) + d1 = run_module(mod_name) # Read from source + self.failUnless("sibling" in d1) + self.failUnless("nephew" in d1) + del d1 # Ensure __loader__ entry doesn't keep file open + __import__(mod_name) + os.remove(mod_fname) + if verbose: print("Running from compiled:", mod_name) + d2 = run_module(mod_name) # Read from bytecode + self.failUnless("sibling" in d2) + self.failUnless("nephew" in d2) + del d2 # Ensure __loader__ entry doesn't keep file open + finally: + self._del_pkg(pkg_dir, depth, mod_name) + if verbose: print("Module executed successfully") + def test_run_module(self): for depth in range(4): if verbose: print("Testing package depth:", depth) self._check_module(depth) + def test_explicit_relative_import(self): + for depth in range(2, 5): + if verbose: print("Testing relative imports at depth:", depth) + self._check_relative_imports(depth) + def test_main(): run_unittest(RunModuleCodeTest) diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 3542ddbf5f0..cf92662a445 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -1,53 +1,100 @@ +import asyncore import socket import threading +import smtpd import smtplib +import io +import sys import time +import select from unittest import TestCase from test import test_support +# PORT is used to communicate the port number assigned to the server +# to the test client +HOST = "localhost" +PORT = None -def server(evt): - serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - serv.settimeout(3) - serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - serv.bind(("", 9091)) - serv.listen(5) +def server(evt, buf): try: + serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + serv.settimeout(3) + serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + serv.bind(("", 0)) + global PORT + PORT = serv.getsockname()[1] + serv.listen(5) conn, addr = serv.accept() except socket.timeout: pass else: - conn.send("220 Hola mundo\n") + n = 500 + while buf and n > 0: + r, w, e = select.select([], [conn], []) + if w: + sent = conn.send(buf) + buf = buf[sent:] + + n -= 1 + time.sleep(0.01) + conn.close() finally: serv.close() + PORT = None evt.set() class GeneralTests(TestCase): def setUp(self): self.evt = threading.Event() - threading.Thread(target=server, args=(self.evt,)).start() - time.sleep(.1) + servargs = (self.evt, "220 Hola mundo\n") + threading.Thread(target=server, args=servargs).start() + + # wait until server thread has assigned a port number + n = 500 + while PORT is None and n > 0: + time.sleep(0.01) + n -= 1 + + # wait a little longer (sometimes connections are refused + # on slow machines without this additional wait) + time.sleep(0.5) def tearDown(self): self.evt.wait() - def testBasic(self): + def testBasic1(self): # connects - smtp = smtplib.SMTP("localhost", 9091) + smtp = smtplib.SMTP(HOST, PORT) smtp.sock.close() + def testBasic2(self): + # connects, include port in host name + smtp = smtplib.SMTP("%s:%s" % (HOST, PORT)) + smtp.sock.close() + + def testLocalHostName(self): + # check that supplied local_hostname is used + smtp = smtplib.SMTP(HOST, PORT, local_hostname="testhost") + self.assertEqual(smtp.local_hostname, "testhost") + smtp.sock.close() + + def testNonnumericPort(self): + # check that non-numeric port raises ValueError + self.assertRaises(socket.error, smtplib.SMTP, + "localhost", "bogus") + def testTimeoutDefault(self): # default - smtp = smtplib.SMTP("localhost", 9091) + smtp = smtplib.SMTP(HOST, PORT) self.assertTrue(smtp.sock.gettimeout() is None) smtp.sock.close() def testTimeoutValue(self): # a value - smtp = smtplib.SMTP("localhost", 9091, timeout=30) + smtp = smtplib.SMTP(HOST, PORT, timeout=30) self.assertEqual(smtp.sock.gettimeout(), 30) smtp.sock.close() @@ -56,16 +103,149 @@ class GeneralTests(TestCase): previous = socket.getdefaulttimeout() socket.setdefaulttimeout(30) try: - smtp = smtplib.SMTP("localhost", 9091, timeout=None) + smtp = smtplib.SMTP(HOST, PORT, timeout=None) finally: socket.setdefaulttimeout(previous) self.assertEqual(smtp.sock.gettimeout(), 30) smtp.sock.close() +# Test server using smtpd.DebuggingServer +def debugging_server(serv_evt, client_evt): + serv = smtpd.DebuggingServer(("", 0), ('nowhere', -1)) + global PORT + PORT = serv.getsockname()[1] + + try: + if hasattr(select, 'poll'): + poll_fun = asyncore.poll2 + else: + poll_fun = asyncore.poll + + n = 1000 + while asyncore.socket_map and n > 0: + poll_fun(0.01, asyncore.socket_map) + + # when the client conversation is finished, it will + # set client_evt, and it's then ok to kill the server + if client_evt.isSet(): + serv.close() + break + + n -= 1 + + except socket.timeout: + pass + finally: + # allow some time for the client to read the result + time.sleep(0.5) + serv.close() + asyncore.close_all() + PORT = None + time.sleep(0.5) + serv_evt.set() + +MSG_BEGIN = '---------- MESSAGE FOLLOWS ----------\n' +MSG_END = '------------ END MESSAGE ------------\n' + +# Test behavior of smtpd.DebuggingServer +# NOTE: the SMTP objects are created with a non-default local_hostname +# argument to the constructor, since (on some systems) the FQDN lookup +# caused by the default local_hostname sometimes takes so long that the +# test server times out, causing the test to fail. +class DebuggingServerTests(TestCase): + + def setUp(self): + # temporarily replace sys.stdout to capture DebuggingServer output + self.old_stdout = sys.stdout + self.output = io.StringIO() + sys.stdout = self.output + + self.serv_evt = threading.Event() + self.client_evt = threading.Event() + serv_args = (self.serv_evt, self.client_evt) + threading.Thread(target=debugging_server, args=serv_args).start() + + # wait until server thread has assigned a port number + n = 500 + while PORT is None and n > 0: + time.sleep(0.01) + n -= 1 + + # wait a little longer (sometimes connections are refused + # on slow machines without this additional wait) + time.sleep(0.5) + + def tearDown(self): + # indicate that the client is finished + self.client_evt.set() + # wait for the server thread to terminate + self.serv_evt.wait() + # restore sys.stdout + sys.stdout = self.old_stdout + + def testBasic(self): + # connect + smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3) + smtp.quit() + + def testEHLO(self): + smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3) + expected = (502, b'Error: command "EHLO" not implemented') + self.assertEqual(smtp.ehlo(), expected) + smtp.quit() + + def testHELP(self): + smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3) + self.assertEqual(smtp.help(), b'Error: command "HELP" not implemented') + smtp.quit() + + def testSend(self): + # connect and send mail + m = 'A test message' + smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3) + smtp.sendmail('John', 'Sally', m) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + mexpect = '%s%s\n%s' % (MSG_BEGIN, m, MSG_END) + self.assertEqual(self.output.getvalue(), mexpect) + + +class BadHELOServerTests(TestCase): + + def setUp(self): + self.old_stdout = sys.stdout + self.output = io.StringIO() + sys.stdout = self.output + + self.evt = threading.Event() + servargs = (self.evt, b"199 no hello for you!\n") + threading.Thread(target=server, args=servargs).start() + + # wait until server thread has assigned a port number + n = 500 + while PORT is None and n > 0: + time.sleep(0.01) + n -= 1 + + # wait a little longer (sometimes connections are refused + # on slow machines without this additional wait) + time.sleep(0.5) + + def tearDown(self): + self.evt.wait() + sys.stdout = self.old_stdout + + def testFailingHELO(self): + self.assertRaises(smtplib.SMTPConnectError, smtplib.SMTP, + HOST, PORT, 'localhost', 3) def test_main(verbose=None): - test_support.run_unittest(GeneralTests) + test_support.run_unittest(GeneralTests, DebuggingServerTests, + BadHELOServerTests) if __name__ == '__main__': test_main() diff --git a/Lib/test/test_socket_ssl.py b/Lib/test/test_socket_ssl.py index 42efb6edc28..fd4383fd9fc 100644 --- a/Lib/test/test_socket_ssl.py +++ b/Lib/test/test_socket_ssl.py @@ -106,6 +106,25 @@ class BasicTests(unittest.TestCase): connector() t.join() + def test_978833(self): + if test_support.verbose: + print("test_978833 ...") + + import os, httplib + with test_support.transient_internet(): + s = socket.socket(socket.AF_INET) + s.connect(("www.sf.net", 443)) + fd = s.fileno() + sock = httplib.FakeSocket(s, socket.ssl(s)) + s = None + sock.close() + try: + os.fstat(fd) + except OSError: + pass + else: + raise test_support.TestFailed("Failed to close socket") + class OpenSSLTests(unittest.TestCase): def testBasic(self): diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index 95706b2ffa9..91c4700242b 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -214,6 +214,9 @@ class UnicodeMiscTest(UnicodeDatabaseTest): count += 1 self.assert_(count >= 10) # should have tested at least the ASCII digits + def test_bug_1704793(self): + self.assertEquals(self.db.lookup("GOTHIC LETTER FAIHU"), '\U00010346') + def test_main(): test.test_support.run_unittest( UnicodeMiscTest, diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py index 737ecbd2b16..a126262140f 100644 --- a/Lib/test/test_urllib2_localnet.py +++ b/Lib/test/test_urllib2_localnet.py @@ -40,14 +40,16 @@ class LoopbackHttpServer(BaseHTTPServer.HTTPServer): class LoopbackHttpServerThread(threading.Thread): """Stoppable thread that runs a loopback http server.""" - def __init__(self, port, RequestHandlerClass): + def __init__(self, request_handler): threading.Thread.__init__(self) - self._RequestHandlerClass = RequestHandlerClass self._stop = False - self._port = port - self._server_address = ('127.0.0.1', self._port) self.ready = threading.Event() - self.error = None + request_handler.protocol_version = "HTTP/1.0" + self.httpd = LoopbackHttpServer(('127.0.0.1', 0), + request_handler) + #print "Serving HTTP on %s port %s" % (self.httpd.server_name, + # self.httpd.server_port) + self.port = self.httpd.server_port def stop(self): """Stops the webserver if it's currently running.""" @@ -58,24 +60,9 @@ class LoopbackHttpServerThread(threading.Thread): self.join() def run(self): - protocol = "HTTP/1.0" - - try: - self._RequestHandlerClass.protocol_version = protocol - httpd = LoopbackHttpServer(self._server_address, - self._RequestHandlerClass) - - sa = httpd.socket.getsockname() - #print "Serving HTTP on", sa[0], "port", sa[1], "..." - except: - # Fail "gracefully" if we are unable to start. - self.ready.set() - self.error = sys.exc_info()[1] - raise - self.ready.set() while not self._stop: - httpd.handle_request() + self.httpd.handle_request() # Authentication infrastructure @@ -232,26 +219,21 @@ class FakeProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler): class ProxyAuthTests(unittest.TestCase): URL = "http://www.foo.com" - PORT = 8080 USER = "tester" PASSWD = "test123" REALM = "TestRealm" - PROXY_URL = "http://127.0.0.1:%d" % PORT - def setUp(self): FakeProxyHandler.digest_auth_handler.set_users({ self.USER : self.PASSWD }) FakeProxyHandler.digest_auth_handler.set_realm(self.REALM) - self.server = LoopbackHttpServerThread(self.PORT, FakeProxyHandler) + self.server = LoopbackHttpServerThread(FakeProxyHandler) self.server.start() self.server.ready.wait() - if self.server.error: - raise self.server.error - - handler = urllib2.ProxyHandler({"http" : self.PROXY_URL}) + proxy_url = "http://127.0.0.1:%d" % self.server.port + handler = urllib2.ProxyHandler({"http" : proxy_url}) self._digest_auth_handler = urllib2.ProxyDigestAuthHandler() self.opener = urllib2.build_opener(handler, self._digest_auth_handler) diff --git a/Lib/threading.py b/Lib/threading.py index 489713c6867..cae2f77c8ea 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -85,9 +85,10 @@ class _RLock(_Verbose): self.__count = 0 def __repr__(self): + owner = self.__owner return "<%s(%s, %d)>" % ( self.__class__.__name__, - self.__owner and self.__owner.getName(), + owner and owner.getName(), self.__count) def acquire(self, blocking=1): diff --git a/Modules/cjkcodecs/_codecs_cn.c b/Modules/cjkcodecs/_codecs_cn.c index c811a67eda0..4542ce62f06 100644 --- a/Modules/cjkcodecs/_codecs_cn.c +++ b/Modules/cjkcodecs/_codecs_cn.c @@ -197,6 +197,7 @@ ENCODER(gb18030) REQUIRE_OUTBUF(2) GBK_ENCODE(c, code) + else TRYMAP_ENC(gb18030ext, code, c); else { const struct _gb18030_to_unibmp_ranges *utrrange; diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index 5a2515c9652..87d71ac2f8a 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -1077,8 +1077,7 @@ static PyObject * unicodedata_lookup(PyObject* self, PyObject* args) { Py_UCS4 code; - Py_UNICODE str[1]; - char errbuf[256]; + Py_UNICODE str[2]; char* name; int namelen; @@ -1086,24 +1085,20 @@ unicodedata_lookup(PyObject* self, PyObject* args) return NULL; if (!_getcode(self, name, namelen, &code)) { - /* XXX(nnorwitz): why are we allocating for the error msg? - Why not always use snprintf? */ - char fmt[] = "undefined character name '%s'"; - char *buf = PyMem_MALLOC(sizeof(fmt) + namelen); - if (buf) - sprintf(buf, fmt, name); - else { - buf = errbuf; - PyOS_snprintf(buf, sizeof(errbuf), fmt, name); - } - PyErr_SetString(PyExc_KeyError, buf); - if (buf != errbuf) - PyMem_FREE(buf); + PyErr_Format(PyExc_KeyError, "undefined character name '%s'", + name); return NULL; } +#ifndef Py_UNICODE_WIDE + if (code >= 0x10000) { + str[0] = 0xd800 + ((code - 0x10000) >> 10); + str[1] = 0xdc00 + ((code - 0x10000) & 0x3ff); + return PyUnicode_FromUnicode(str, 2); + } +#endif str[0] = (Py_UNICODE) code; - return PyUnicode_FromUnicode(str, 1); + return PyUnicode_FromUnicode(str, 1); } /* XXX Add doc strings. */ diff --git a/Objects/stringobject.c b/Objects/stringobject.c index 68dfd35de5f..6b030473250 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -1868,7 +1868,7 @@ PyDoc_STRVAR(find__doc__, "S.find(sub [,start [,end]]) -> int\n\ \n\ Return the lowest index in S where substring sub is found,\n\ -such that sub is contained within s[start,end]. Optional\n\ +such that sub is contained within s[start:end]. Optional\n\ arguments start and end are interpreted as in slice notation.\n\ \n\ Return -1 on failure."); @@ -1907,7 +1907,7 @@ PyDoc_STRVAR(rfind__doc__, "S.rfind(sub [,start [,end]]) -> int\n\ \n\ Return the highest index in S where substring sub is found,\n\ -such that sub is contained within s[start,end]. Optional\n\ +such that sub is contained within s[start:end]. Optional\n\ arguments start and end are interpreted as in slice notation.\n\ \n\ Return -1 on failure."); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 27fedca463a..0dcc372b554 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -6295,7 +6295,7 @@ PyDoc_STRVAR(find__doc__, "S.find(sub [,start [,end]]) -> int\n\ \n\ Return the lowest index in S where substring sub is found,\n\ -such that sub is contained within s[start,end]. Optional\n\ +such that sub is contained within s[start:end]. Optional\n\ arguments start and end are interpreted as in slice notation.\n\ \n\ Return -1 on failure."); @@ -7149,7 +7149,7 @@ PyDoc_STRVAR(rfind__doc__, "S.rfind(sub [,start [,end]]) -> int\n\ \n\ Return the highest index in S where substring sub is found,\n\ -such that sub is contained within s[start,end]. Optional\n\ +such that sub is contained within s[start:end]. Optional\n\ arguments start and end are interpreted as in slice notation.\n\ \n\ Return -1 on failure."); diff --git a/PC/pyconfig.h b/PC/pyconfig.h index 5b662cef01f..6d7ff0f4858 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -32,6 +32,11 @@ MS_CORE_DLL. #define MS_WINCE #endif +/* Deprecated USE_DL_EXPORT macro - please use Py_BUILD_CORE */ +#ifdef USE_DL_EXPORT +# define Py_BUILD_CORE +#endif /* USE_DL_EXPORT */ + /* Visual Studio 2005 introduces deprecation warnings for "insecure" and POSIX functions. The insecure functions should be replaced by *_s versions (according to Microsoft); the @@ -140,7 +145,7 @@ MS_CORE_DLL. #if defined(_M_IA64) #define COMPILER _Py_PASTE_VERSION("64 bit (Itanium)") #define MS_WINI64 -#elif defined(_M_X64) +#elif defined(_M_X64) || defined(_M_AMD64) #define COMPILER _Py_PASTE_VERSION("64 bit (AMD64)") #define MS_WINX64 #else @@ -151,12 +156,26 @@ MS_CORE_DLL. /* set the version macros for the windows headers */ #ifdef MS_WINX64 /* 64 bit only runs on XP or greater */ -#define _WIN32_WINNT 0x0501 -#define WINVER 0x0501 +#define Py_WINVER 0x0501 #else /* NT 4.0 or greater required otherwise */ -#define _WIN32_WINNT 0x0400 -#define WINVER 0x0400 +#define Py_WINVER 0x0400 +#endif + +/* We only set these values when building Python - we don't want to force + these values on extensions, as that will affect the prototypes and + structures exposed in the Windows headers. Even when building Python, we + allow a single source file to override this - they may need access to + structures etc so it can optionally use new Windows features if it + determines at runtime they are available. +*/ +#ifdef Py_BUILD_CORE +#ifndef WINVER +#define WINVER Py_WINVER +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT Py_WINVER +#endif #endif /* _W64 is not defined for VC6 or eVC4 */ @@ -287,11 +306,6 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ # define MS_COREDLL /* deprecated old symbol */ #endif /* !MS_NO_COREDLL && ... */ -/* Deprecated USE_DL_EXPORT macro - please use Py_BUILD_CORE */ -#ifdef USE_DL_EXPORT -# define Py_BUILD_CORE -#endif /* USE_DL_EXPORT */ - /* All windows compilers that use this header support __declspec */ #define HAVE_DECLSPEC_DLL diff --git a/Python/structmember.c b/Python/structmember.c index 5165a99432f..041f29b7c09 100644 --- a/Python/structmember.c +++ b/Python/structmember.c @@ -156,6 +156,12 @@ PyMember_Set(char *addr, struct memberlist *mlist, const char *name, PyObject *v return -1; } +#define WARN(msg) \ + do { \ + if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0) \ + return -1; \ + } while (0) + int PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) { @@ -174,60 +180,54 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) addr += l->offset; switch (l->type) { case T_BYTE:{ - long long_val; - long_val = PyInt_AsLong(v); + long long_val = PyInt_AsLong(v); if ((long_val == -1) && PyErr_Occurred()) return -1; + *(char*)addr = (char)long_val; /* XXX: For compatibility, only warn about truncations for now. */ if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN)) - PyErr_Warn(PyExc_RuntimeWarning, "Truncation of value to char"); - *(char*)addr = (char)long_val; + WARN("Truncation of value to char"); break; } case T_UBYTE:{ - long long_val; - long_val = PyInt_AsLong(v); + long long_val = PyInt_AsLong(v); if ((long_val == -1) && PyErr_Occurred()) return -1; - if ((long_val > UCHAR_MAX) || (long_val < 0)) - PyErr_Warn(PyExc_RuntimeWarning, "Truncation of value to unsigned char"); *(unsigned char*)addr = (unsigned char)long_val; + if ((long_val > UCHAR_MAX) || (long_val < 0)) + WARN("Truncation of value to unsigned char"); break; } case T_SHORT:{ - long long_val; - long_val = PyInt_AsLong(v); + long long_val = PyInt_AsLong(v); if ((long_val == -1) && PyErr_Occurred()) return -1; - if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN)) - PyErr_Warn(PyExc_RuntimeWarning, "Truncation of value to short"); *(short*)addr = (short)long_val; + if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN)) + WARN("Truncation of value to short"); break; } case T_USHORT:{ - long long_val; - long_val = PyInt_AsLong(v); + long long_val = PyInt_AsLong(v); if ((long_val == -1) && PyErr_Occurred()) return -1; - if ((long_val > USHRT_MAX) || (long_val < 0)) - PyErr_Warn(PyExc_RuntimeWarning, "Truncation of value to unsigned short"); *(unsigned short*)addr = (unsigned short)long_val; + if ((long_val > USHRT_MAX) || (long_val < 0)) + WARN("Truncation of value to unsigned short"); break; } case T_INT:{ - long long_val; - long_val = PyInt_AsLong(v); + long long_val = PyInt_AsLong(v); if ((long_val == -1) && PyErr_Occurred()) return -1; - if ((long_val > INT_MAX) || (long_val < INT_MIN)) - PyErr_Warn(PyExc_RuntimeWarning, "Truncation of value to int"); *(int *)addr = (int)long_val; + if ((long_val > INT_MAX) || (long_val < INT_MIN)) + WARN("Truncation of value to int"); break; } case T_UINT:{ - unsigned long ulong_val; - ulong_val = PyLong_AsUnsignedLong(v); + unsigned long ulong_val = PyLong_AsUnsignedLong(v); if ((ulong_val == (unsigned int)-1) && PyErr_Occurred()) { /* XXX: For compatibility, accept negative int values as well. */ @@ -235,11 +235,12 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) ulong_val = PyLong_AsLong(v); if ((ulong_val == (unsigned int)-1) && PyErr_Occurred()) return -1; - PyErr_Warn(PyExc_RuntimeWarning, "Writing negative value into unsigned field"); - } + *(unsigned int *)addr = (unsigned int)ulong_val; + WARN("Writing negative value into unsigned field"); + } else + *(unsigned int *)addr = (unsigned int)ulong_val; if (ulong_val > UINT_MAX) - PyErr_Warn(PyExc_RuntimeWarning, "Truncation of value to unsigned int"); - *(unsigned int *)addr = (unsigned int)ulong_val; + WARN("Truncation of value to unsigned int"); break; } case T_LONG:{ @@ -256,9 +257,10 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) as well. */ PyErr_Clear(); *(unsigned long*)addr = PyLong_AsLong(v); - if ((*(unsigned long*)addr == (unsigned int)-1) && PyErr_Occurred()) + if ((*(unsigned long*)addr == (unsigned int)-1) + && PyErr_Occurred()) return -1; - PyErr_Warn(PyExc_RuntimeWarning, "Writing negative value into unsigned field"); + WARN("Writing negative value into unsigned field"); } break; } @@ -270,8 +272,7 @@ PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) break; } case T_FLOAT:{ - double double_val; - double_val = PyFloat_AsDouble(v); + double double_val = PyFloat_AsDouble(v); if ((double_val == -1) && PyErr_Occurred()) return -1; *(float*)addr = (float)double_val; diff --git a/configure b/configure index 61d9d39bfa4..53736e07aae 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 54283 . +# From configure.in Revision: 55739 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.61 for python 3.0. # @@ -1838,6 +1838,14 @@ cat >>confdefs.h <<\_ACEOF _ACEOF +# OpenBSD undoes our definition of __BSD_VISIBLE if _XOPEN_SOURCE is +# also defined. This can be overridden by defining _BSD_SOURCE + +cat >>confdefs.h <<\_ACEOF +#define _BSD_SOURCE 1 +_ACEOF + + # The later defininition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables # u_int on Irix 5.3. Defining _BSD_TYPES brings it back. diff --git a/configure.in b/configure.in index 9a07fb9c68c..2d272c45e27 100644 --- a/configure.in +++ b/configure.in @@ -50,6 +50,10 @@ AC_DEFINE(_NETBSD_SOURCE, 1, [Define on NetBSD to activate all library features] # them. AC_DEFINE(__BSD_VISIBLE, 1, [Define on FreeBSD to activate all library features]) +# OpenBSD undoes our definition of __BSD_VISIBLE if _XOPEN_SOURCE is +# also defined. This can be overridden by defining _BSD_SOURCE +AC_DEFINE(_BSD_SOURCE, 1, [Define on OpenBSD to activate all library features]) + # The later defininition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables # u_int on Irix 5.3. Defining _BSD_TYPES brings it back. AC_DEFINE(_BSD_TYPES, 1, [Define on Irix to enable u_int]) diff --git a/pyconfig.h.in b/pyconfig.h.in index d5dafc1d176..012bf7e0d20 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -103,6 +103,10 @@ /* Define if you have the 'resize_term' function. */ #undef HAVE_CURSES_RESIZE_TERM +/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. + */ +#undef HAVE_DECL_TZNAME + /* Define to 1 if you have the device macros. */ #undef HAVE_DEVICE_MACROS @@ -802,22 +806,22 @@ /* Define if i>>j for signed int i does not extend the sign bit when i < 0 */ #undef SIGNED_RIGHT_SHIFT_ZERO_FILLS -/* The size of a `double', as computed by sizeof. */ +/* The size of `double', as computed by sizeof. */ #undef SIZEOF_DOUBLE -/* The size of a `float', as computed by sizeof. */ +/* The size of `float', as computed by sizeof. */ #undef SIZEOF_FLOAT -/* The size of a `fpos_t', as computed by sizeof. */ +/* The size of `fpos_t', as computed by sizeof. */ #undef SIZEOF_FPOS_T -/* The size of a `int', as computed by sizeof. */ +/* The size of `int', as computed by sizeof. */ #undef SIZEOF_INT -/* The size of a `long', as computed by sizeof. */ +/* The size of `long', as computed by sizeof. */ #undef SIZEOF_LONG -/* The size of a `long long', as computed by sizeof. */ +/* The size of `long long', as computed by sizeof. */ #undef SIZEOF_LONG_LONG /* The number of bytes in an off_t. */ @@ -826,25 +830,25 @@ /* The number of bytes in a pthread_t. */ #undef SIZEOF_PTHREAD_T -/* The size of a `short', as computed by sizeof. */ +/* The size of `short', as computed by sizeof. */ #undef SIZEOF_SHORT -/* The size of a `size_t', as computed by sizeof. */ +/* The size of `size_t', as computed by sizeof. */ #undef SIZEOF_SIZE_T /* The number of bytes in a time_t. */ #undef SIZEOF_TIME_T -/* The size of a `uintptr_t', as computed by sizeof. */ +/* The size of `uintptr_t', as computed by sizeof. */ #undef SIZEOF_UINTPTR_T -/* The size of a `void *', as computed by sizeof. */ +/* The size of `void *', as computed by sizeof. */ #undef SIZEOF_VOID_P -/* The size of a `wchar_t', as computed by sizeof. */ +/* The size of `wchar_t', as computed by sizeof. */ #undef SIZEOF_WCHAR_T -/* The size of a `_Bool', as computed by sizeof. */ +/* The size of `_Bool', as computed by sizeof. */ #undef SIZEOF__BOOL /* Define to 1 if you have the ANSI C header files. */ @@ -924,6 +928,9 @@ # undef _ALL_SOURCE #endif +/* Define on OpenBSD to activate all library features */ +#undef _BSD_SOURCE + /* Define on Irix to enable u_int */ #undef _BSD_TYPES @@ -980,7 +987,7 @@ /* Define to `int' if does not define. */ #undef mode_t -/* Define to `long' if does not define. */ +/* Define to `long int' if does not define. */ #undef off_t /* Define to `int' if does not define. */ @@ -989,7 +996,7 @@ /* Define to empty if the keyword does not work. */ #undef signed -/* Define to `unsigned' if does not define. */ +/* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if does not define. */