diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst
index e24b4296bc7..b176ca3ad2e 100644
--- a/Doc/library/socketserver.rst
+++ b/Doc/library/socketserver.rst
@@ -236,8 +236,8 @@ users of the server object.
.. function:: handle_timeout()
- This function is called when the :attr:`timeout` attribute has been set to a
- value other than :const:`None` and the timeout period has passed with no
+ This function is called when the :attr:`timeout` attribute has been set to a
+ value other than :const:`None` and the timeout period has passed with no
requests being received. The default action for forking servers is
to collect the status of any child processes that have exited, while
in threading servers this method does nothing.
@@ -284,27 +284,28 @@ request.
.. function:: finish()
- Called after the :meth:`handle` method to perform any clean-up actions required.
- The default implementation does nothing. If :meth:`setup` or :meth:`handle`
- raise an exception, this function will not be called.
+ Called after the :meth:`handle` method to perform any clean-up actions
+ required. The default implementation does nothing. If :meth:`setup` or
+ :meth:`handle` raise an exception, this function will not be called.
.. function:: handle()
- This function must do all the work required to service a request. The default
- implementation does nothing. Several instance attributes are available to it;
- the request is available as :attr:`self.request`; the client address as
- :attr:`self.client_address`; and the server instance as :attr:`self.server`, in
- case it needs access to per-server information.
+ This function must do all the work required to service a request. The
+ default implementation does nothing. Several instance attributes are
+ available to it; the request is available as :attr:`self.request`; the client
+ address as :attr:`self.client_address`; and the server instance as
+ :attr:`self.server`, in case it needs access to per-server information.
- The type of :attr:`self.request` is different for datagram or stream services.
- For stream services, :attr:`self.request` is a socket object; for datagram
- services, :attr:`self.request` is a string. However, this can be hidden by using
- the request handler subclasses :class:`StreamRequestHandler` or
- :class:`DatagramRequestHandler`, which override the :meth:`setup` and
- :meth:`finish` methods, and provide :attr:`self.rfile` and :attr:`self.wfile`
- attributes. :attr:`self.rfile` and :attr:`self.wfile` can be read or written,
- respectively, to get the request data or return data to the client.
+ The type of :attr:`self.request` is different for datagram or stream
+ services. For stream services, :attr:`self.request` is a socket object; for
+ datagram services, :attr:`self.request` is a pair of string and socket.
+ However, this can be hidden by using the request handler subclasses
+ :class:`StreamRequestHandler` or :class:`DatagramRequestHandler`, which
+ override the :meth:`setup` and :meth:`finish` methods, and provide
+ :attr:`self.rfile` and :attr:`self.wfile` attributes. :attr:`self.rfile` and
+ :attr:`self.wfile` can be read or written, respectively, to get the request
+ data or return data to the client.
.. function:: setup()
@@ -312,3 +313,217 @@ request.
Called before the :meth:`handle` method to perform any initialization actions
required. The default implementation does nothing.
+
+Examples
+--------
+
+:class:`socketserver.TCPServer` Example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the server side::
+
+ import socketserver
+
+ class MyTCPHandler(socketserver.BaseRequestHandler):
+ """
+ The RequestHandler class for our server.
+
+ It is instantiated once per connection to the server, and must
+ override the handle() method to implement communication to the
+ client.
+ """
+
+ def handle(self):
+ # self.request is the TCP socket connected to the client
+ self.data = self.request.recv(1024).strip()
+ print "%s wrote:" % self.client_address[0]
+ print self.data
+ # just send back the same data, but upper-cased
+ self.request.send(self.data.upper())
+
+ if __name__ == "__main__":
+ HOST, PORT = "localhost", 9999
+
+ # Create the server, binding to localhost on port 9999
+ server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
+
+ # Activate the server; this will keep running until you
+ # interrupt the program with Ctrl-C
+ server.serve_forever()
+
+An alternative request handler class that makes use of streams (file-like
+objects that simplify communication by providing the standard file interface)::
+
+ class MyTCPHandler(socketserver.StreamRequestHandler):
+
+ def handle(self):
+ # self.rfile is a file-like object created by the handler;
+ # we can now use e.g. readline() instead of raw recv() calls
+ self.data = self.rfile.readline().strip()
+ print "%s wrote:" % self.client_address[0]
+ print self.data
+ # Likewise, self.wfile is a file-like object used to write back
+ # to the client
+ self.wfile.write(self.data.upper())
+
+The difference is that the ``readline()`` call in the second handler will call
+``recv()`` multiple times until it encounters a newline character, while the
+single ``recv()`` call in the first handler will just return what has been sent
+from the client in one ``send()`` call.
+
+
+This is the client side::
+
+ import socket
+ import sys
+
+ HOST, PORT = "localhost", 9999
+ data = " ".join(sys.argv[1:])
+
+ # Create a socket (SOCK_STREAM means a TCP socket)
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ # Connect to server and send data
+ sock.connect((HOST, PORT))
+ sock.send(data + "\n")
+
+ # Receive data from the server and shut down
+ received = sock.recv(1024)
+ sock.close()
+
+ print "Sent: %s" % data
+ print "Received: %s" % received
+
+
+The output of the example should look something like this:
+
+Server::
+
+ $ python TCPServer.py
+ 127.0.0.1 wrote:
+ hello world with TCP
+ 127.0.0.1 wrote:
+ python is nice
+
+Client::
+
+ $ python TCPClient.py hello world with TCP
+ Sent: hello world with TCP
+ Received: HELLO WORLD WITH TCP
+ $ python TCPClient.py python is nice
+ Sent: python is nice
+ Received: PYTHON IS NICE
+
+
+:class:`socketserver.UDPServer` Example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the server side::
+
+ import socketserver
+
+ class MyUDPHandler(socketserver.BaseRequestHandler):
+ """
+ This class works similar to the TCP handler class, except that
+ self.request consists of a pair of data and client socket, and since
+ there is no connection the client address must be given explicitly
+ when sending data back via sendto().
+ """
+
+ def handle(self):
+ data = self.request[0].strip()
+ socket = self.request[1]
+ print "%s wrote:" % self.client_address[0]
+ print data
+ socket.sendto(data.upper(), self.client_address)
+
+ if __name__ == "__main__":
+ HOST, PORT = "localhost", 9999
+ server = socketserver.UDPServer((HOST, PORT), BaseUDPRequestHandler)
+ server.serve_forever()
+
+This is the client side::
+
+ import socket
+ import sys
+
+ HOST, PORT = "localhost"
+ data = " ".join(sys.argv[1:])
+
+ # SOCK_DGRAM is the socket type to use for UDP sockets
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+ # As you can see, there is no connect() call; UDP has no connections.
+ # Instead, data is directly sent to the recipient via sendto().
+ sock.sendto(data + "\n", (HOST, PORT))
+ received = sock.recv(1024)
+
+ print "Sent: %s" % data
+ print "Received: %s" % received
+
+The output of the example should look exactly like for the TCP server example.
+
+
+Asynchronous Mixins
+~~~~~~~~~~~~~~~~~~~
+
+To build asynchronous handlers, use the :class:`ThreadingMixIn` and
+:class:`ForkingMixIn` classes.
+
+An example for the :class:`ThreadingMixIn` class::
+
+ import socket
+ import threading
+ import socketserver
+
+ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
+
+ def handle(self):
+ data = self.request.recv(1024)
+ cur_thread = threading.currentThread()
+ response = "%s: %s" % (cur_thread.getName(), data)
+ self.request.send(response)
+
+ class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
+ pass
+
+ def client(ip, port, message):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.connect((ip, port))
+ sock.send(message)
+ response = sock.recv(1024)
+ print "Received: %s" % response
+ sock.close()
+
+ if __name__ == "__main__":
+ # Port 0 means to select an arbitrary unused port
+ HOST, PORT = "localhost", 0
+
+ server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
+ ip, port = server.server_address
+
+ # Start a thread with the server -- that thread will then start one
+ # more thread for each request
+ server_thread = threading.Thread(target=server.serve_forever)
+ # Exit the server thread when the main thread terminates
+ server_thread.setDaemon(True)
+ server_thread.start()
+ print "Server loop running in thread:", t.getName()
+
+ client(ip, port, "Hello World 1")
+ client(ip, port, "Hello World 2")
+ client(ip, port, "Hello World 3")
+
+ server.shutdown()
+
+The output of the example should look something like this::
+
+ $ python ThreadedTCPServer.py
+ Server loop running in thread: Thread-1
+ Received: Thread-2: Hello World 1
+ Received: Thread-3: Hello World 2
+ Received: Thread-4: Hello World 3
+
+
+The :class:`ForkingMixIn` class is used in the same way, except that the server
+will spawn a new process for each request.
diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst
index 9b7721476f7..6e933f64e63 100644
--- a/Doc/library/zipfile.rst
+++ b/Doc/library/zipfile.rst
@@ -150,11 +150,11 @@ ZipFile Objects
.. method:: ZipFile.open(name[, mode[, pwd]])
Extract a member from the archive as a file-like object (ZipExtFile). *name* is
- the name of the file in the archive. The *mode* parameter, if included, must be
- one of the following: ``'r'`` (the default), ``'U'``, or ``'rU'``. Choosing
- ``'U'`` or ``'rU'`` will enable universal newline support in the read-only
- object. *pwd* is the password used for encrypted files. Calling :meth:`open`
- on a closed ZipFile will raise a :exc:`RuntimeError`.
+ the name of the file in the archive, or a :class:`ZipInfo` object. The *mode*
+ parameter, if included, must be one of the following: ``'r'`` (the default),
+ ``'U'``, or ``'rU'``. Choosing ``'U'`` or ``'rU'`` will enable universal newline
+ support in the read-only object. *pwd* is the password used for encrypted files.
+ Calling :meth:`open` on a closed ZipFile will raise a :exc:`RuntimeError`.
.. note::
@@ -173,14 +173,20 @@ ZipFile Objects
create a new file object that will be held by the ZipExtFile, allowing it to
operate independently of the ZipFile.
+ .. note::
+
+ The :meth:`open`, :meth:`read` and :meth:`extract` methods can take a filename
+ or a :class:`ZipInfo` object. You will appreciate this when trying to read a
+ ZIP file that contains members with duplicate names.
+
.. method:: ZipFile.extract(member[, path[, pwd]])
- Extract a member from the archive to the current working directory, using its
- full name. Its file information is extracted as accurately as possible.
- *path* specifies a different directory to extract to. *member* can be a
- filename or a :class:`ZipInfo` object. *pwd* is the password used for
- encrypted files.
+ Extract a member from the archive to the current working directory; *member*
+ must be its full name or a :class:`ZipInfo` object). Its file information is
+ extracted as accurately as possible. *path* specifies a different directory
+ to extract to. *member* can be a filename or a :class:`ZipInfo` object.
+ *pwd* is the password used for encrypted files.
.. method:: ZipFile.extractall([path[, members[, pwd]]])
@@ -203,9 +209,10 @@ ZipFile Objects
.. method:: ZipFile.read(name[, pwd])
- Return the bytes of the file in the archive. The archive must be open for read
- or append. *pwd* is the password used for encrypted files and, if specified, it
- will override the default password set with :meth:`setpassword`. Calling
+ Return the bytes of the file *name* in the archive. *name* is the name of the
+ file in the archive, or a :class:`ZipInfo` object. The archive must be open for
+ read or append. *pwd* is the password used for encrypted files and, if specified,
+ it will override the default password set with :meth:`setpassword`. Calling
:meth:`read` on a closed ZipFile will raise a :exc:`RuntimeError`.
diff --git a/Lib/BaseHTTPServer.py b/Lib/BaseHTTPServer.py
index 8a099feca80..7fbbcf227cd 100644
--- a/Lib/BaseHTTPServer.py
+++ b/Lib/BaseHTTPServer.py
@@ -222,6 +222,12 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
error_message_format = DEFAULT_ERROR_MESSAGE
error_content_type = DEFAULT_ERROR_CONTENT_TYPE
+ # The default request version. This only affects responses up until
+ # the point where the request line is parsed, so it mainly decides what
+ # the client gets back when sending a malformed request line.
+ # Most web servers default to HTTP 0.9, i.e. don't send a status line.
+ default_request_version = "HTTP/0.9"
+
def parse_request(self):
"""Parse a request (internal).
@@ -234,7 +240,7 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
"""
self.command = None # set in case of error on the first line
- self.request_version = version = "HTTP/0.9" # Default
+ self.request_version = version = self.default_request_version
self.close_connection = 1
requestline = str(self.raw_requestline, 'iso-8859-1')
if requestline[-2:] == '\r\n':
diff --git a/Lib/CGIHTTPServer.py b/Lib/CGIHTTPServer.py
index 828b092496b..29d701af2f3 100644
--- a/Lib/CGIHTTPServer.py
+++ b/Lib/CGIHTTPServer.py
@@ -182,8 +182,10 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
env['AUTH_TYPE'] = authorization[0]
if authorization[0].lower() == "basic":
try:
- authorization = base64.decodestring(authorization[1])
- except binascii.Error:
+ authorization = authorization[1].encode('ascii')
+ authorization = base64.decodestring(authorization).\
+ decode('ascii')
+ except (binascii.Error, UnicodeError):
pass
else:
authorization = authorization.split(':')
diff --git a/Lib/SimpleHTTPServer.py b/Lib/SimpleHTTPServer.py
index beb0a392e0f..36a249c7d12 100644
--- a/Lib/SimpleHTTPServer.py
+++ b/Lib/SimpleHTTPServer.py
@@ -11,13 +11,14 @@ __version__ = "0.6"
__all__ = ["SimpleHTTPRequestHandler"]
import os
+import sys
import posixpath
import BaseHTTPServer
import urllib
import cgi
import shutil
import mimetypes
-from io import StringIO
+from io import BytesIO
class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
@@ -76,12 +77,8 @@ class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
else:
return self.list_directory(path)
ctype = self.guess_type(path)
- if ctype.startswith('text/'):
- mode = 'r'
- else:
- mode = 'rb'
try:
- f = open(path, mode)
+ f = open(path, 'rb')
except IOError:
self.send_error(404, "File not found")
return None
@@ -107,12 +104,12 @@ class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
self.send_error(404, "No permission to list directory")
return None
list.sort(key=lambda a: a.lower())
- f = StringIO()
+ r = []
displaypath = cgi.escape(urllib.unquote(self.path))
- f.write('')
- f.write("\n
Directory listing for %s\n" % displaypath)
- f.write("\nDirectory listing for %s
\n" % displaypath)
- f.write("
\n\n")
+ r.append('')
+ r.append("\nDirectory listing for %s\n" % displaypath)
+ r.append("\nDirectory listing for %s
\n" % displaypath)
+ r.append("
\n\n")
for name in list:
fullname = os.path.join(path, name)
displayname = linkname = name
@@ -123,14 +120,17 @@ class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
if os.path.islink(fullname):
displayname = name + "@"
# Note: a link to a directory displays with @ and links with /
- f.write('- %s\n'
+ r.append('
- %s\n'
% (urllib.quote(linkname), cgi.escape(displayname)))
- f.write("
\n
\n\n\n")
- length = f.tell()
+ r.append("
\n
\n\n\n")
+ enc = sys.getfilesystemencoding()
+ encoded = ''.join(r).encode(enc)
+ f = BytesIO()
+ f.write(encoded)
f.seek(0)
self.send_response(200)
- self.send_header("Content-type", "text/html")
- self.send_header("Content-Length", str(length))
+ self.send_header("Content-type", "text/html; charset=%s" % enc)
+ self.send_header("Content-Length", str(len(encoded)))
self.end_headers()
return f
diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py
new file mode 100644
index 00000000000..96c0a2395b0
--- /dev/null
+++ b/Lib/distutils/tests/test_build_ext.py
@@ -0,0 +1,72 @@
+import sys
+import os
+import tempfile
+import shutil
+from io import StringIO
+
+from distutils.core import Extension, Distribution
+from distutils.command.build_ext import build_ext
+from distutils import sysconfig
+
+import unittest
+from test import support
+
+class BuildExtTestCase(unittest.TestCase):
+ def setUp(self):
+ # Create a simple test environment
+ # Note that we're making changes to sys.path
+ self.tmp_dir = tempfile.mkdtemp(prefix="pythontest_")
+ self.sys_path = sys.path[:]
+ sys.path.append(self.tmp_dir)
+
+ xx_c = os.path.join(sysconfig.project_base, 'Modules', 'xxmodule.c')
+ shutil.copy(xx_c, self.tmp_dir)
+
+ def test_build_ext(self):
+ xx_c = os.path.join(self.tmp_dir, 'xxmodule.c')
+ xx_ext = Extension('xx', [xx_c])
+ dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]})
+ dist.package_dir = self.tmp_dir
+ cmd = build_ext(dist)
+ cmd.build_lib = self.tmp_dir
+ cmd.build_temp = self.tmp_dir
+
+ old_stdout = sys.stdout
+ if not support.verbose:
+ # silence compiler output
+ sys.stdout = StringIO()
+ try:
+ cmd.ensure_finalized()
+ cmd.run()
+ finally:
+ sys.stdout = old_stdout
+
+ import xx
+
+ for attr in ('error', 'foo', 'new', 'roj'):
+ self.assert_(hasattr(xx, attr))
+
+ self.assertEquals(xx.foo(2, 5), 7)
+ self.assertEquals(xx.foo(13,15), 28)
+ self.assertEquals(xx.new().demo(), None)
+ doc = 'This is a template module just for instruction.'
+ self.assertEquals(xx.__doc__, doc)
+ self.assert_(isinstance(xx.Null(), xx.Null))
+ self.assert_(isinstance(xx.Str(), xx.Str))
+
+ def tearDown(self):
+ # Get everything back to normal
+ support.unload('xx')
+ sys.path = self.sys_path
+ # XXX on Windows the test leaves a directory with xx.pyd in TEMP
+ shutil.rmtree(self.tmp_dir, False if os.name != "nt" else True)
+
+def test_suite():
+ if not sysconfig.python_build:
+ if support.verbose:
+ print('test_build_ext: The test must be run in a python build dir')
+ return unittest.TestSuite()
+ else: return unittest.makeSuite(BuildExtTestCase)
+
+if __name__ == '__main__':
+ support.run_unittest(test_suite())
diff --git a/Lib/gzip.py b/Lib/gzip.py
index 45fae9facf8..9d8dac5bdbc 100644
--- a/Lib/gzip.py
+++ b/Lib/gzip.py
@@ -323,6 +323,8 @@ class GzipFile:
raise IOError("Incorrect length of data produced")
def close(self):
+ if self.fileobj is None:
+ return
if self.mode == WRITE:
self.fileobj.write(self.compress.flush())
write32u(self.fileobj, self.crc)
diff --git a/Lib/test/pydoc_mod.py b/Lib/test/pydoc_mod.py
new file mode 100644
index 00000000000..8601e3f7abb
--- /dev/null
+++ b/Lib/test/pydoc_mod.py
@@ -0,0 +1,54 @@
+"""This is a test module for test_pydoc"""
+
+__author__ = "Benjamin Peterson"
+__credits__ = "Nobody"
+__version__ = "1.2.3.4"
+
+
+class A:
+ """Hello and goodbye"""
+ def __init__():
+ """Wow, I have no function!"""
+ pass
+
+class B(object):
+ NO_MEANING = "eggs"
+ pass
+
+def doc_func():
+ """
+ This function solves all of the world's problems:
+ hunger
+ lack of Python
+ war
+ """
+
+def nodoc_func():
+ pass
+"""This is a test module for test_pydoc"""
+
+__author__ = "Benjamin Peterson"
+__credits__ = "Nobody"
+__version__ = "1.2.3.4"
+
+
+class A:
+ """Hello and goodbye"""
+ def __init__():
+ """Wow, I have no function!"""
+ pass
+
+class B(object):
+ NO_MEANING = "eggs"
+ pass
+
+def doc_func():
+ """
+ This function solves all of the world's problems:
+ hunger
+ lack of Python
+ war
+ """
+
+def nodoc_func():
+ pass
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index ad8c2302dd9..4ed0e241655 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -114,7 +114,9 @@ class TestNamedTuple(unittest.TestCase):
# n = 10000
n = 254 # SyntaxError: more than 255 arguments:
import string, random
- names = [''.join([random.choice(string.ascii_letters) for j in range(10)]) for i in range(n)]
+ names = list(set(''.join([random.choice(string.ascii_letters)
+ for j in range(10)]) for i in range(n)))
+ n = len(names)
Big = namedtuple('Big', names)
b = Big(*range(n))
self.assertEqual(b, tuple(range(n)))
diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py
index c26035bae79..d28c024d07f 100644
--- a/Lib/test/test_gzip.py
+++ b/Lib/test/test_gzip.py
@@ -24,14 +24,14 @@ data2 = b"""/* zlibmodule.c -- gzip-compatible data compression */
class TestGzip(unittest.TestCase):
filename = support.TESTFN
- def setUp (self):
+ def setUp(self):
support.unlink(self.filename)
- def tearDown (self):
+ def tearDown(self):
support.unlink(self.filename)
- def test_write (self):
+ def test_write(self):
f = gzip.GzipFile(self.filename, 'wb') ; f.write(data1 * 50)
# Try flush and fileno.
@@ -41,6 +41,9 @@ class TestGzip(unittest.TestCase):
os.fsync(f.fileno())
f.close()
+ # Test multiple close() calls.
+ f.close()
+
def test_read(self):
self.test_write()
# Try reading.
diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
new file mode 100644
index 00000000000..cc79cb872c4
--- /dev/null
+++ b/Lib/test/test_httpservers.py
@@ -0,0 +1,354 @@
+"""Unittests for the various HTTPServer modules.
+
+Written by Cody A.W. Somerville ,
+Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest.
+"""
+
+from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from SimpleHTTPServer import SimpleHTTPRequestHandler
+from CGIHTTPServer import CGIHTTPRequestHandler
+
+import os
+import sys
+import base64
+import shutil
+import urllib
+import httplib
+import tempfile
+import threading
+
+import unittest
+from test import support
+
+
+class NoLogRequestHandler:
+ def log_message(self, *args):
+ # don't write log messages to stderr
+ pass
+
+
+class TestServerThread(threading.Thread):
+ def __init__(self, test_object, request_handler):
+ threading.Thread.__init__(self)
+ self.request_handler = request_handler
+ self.test_object = test_object
+ self.test_object.lock.acquire()
+
+ def run(self):
+ self.server = HTTPServer(('', 0), self.request_handler)
+ self.test_object.PORT = self.server.socket.getsockname()[1]
+ self.test_object.lock.release()
+ try:
+ self.server.serve_forever()
+ finally:
+ self.server.server_close()
+
+ def stop(self):
+ self.server.shutdown()
+
+
+class BaseTestCase(unittest.TestCase):
+ def setUp(self):
+ self.lock = threading.Lock()
+ self.thread = TestServerThread(self, self.request_handler)
+ self.thread.start()
+ self.lock.acquire()
+
+ def tearDown(self):
+ self.lock.release()
+ self.thread.stop()
+
+ def request(self, uri, method='GET', body=None, headers={}):
+ self.connection = httplib.HTTPConnection('localhost', self.PORT)
+ self.connection.request(method, uri, body, headers)
+ return self.connection.getresponse()
+
+
+class BaseHTTPServerTestCase(BaseTestCase):
+ class request_handler(NoLogRequestHandler, BaseHTTPRequestHandler):
+ protocol_version = 'HTTP/1.1'
+ default_request_version = 'HTTP/1.1'
+
+ def do_TEST(self):
+ self.send_response(204)
+ self.send_header('Content-Type', 'text/html')
+ self.send_header('Connection', 'close')
+ self.end_headers()
+
+ def do_KEEP(self):
+ self.send_response(204)
+ self.send_header('Content-Type', 'text/html')
+ self.send_header('Connection', 'keep-alive')
+ self.end_headers()
+
+ def do_KEYERROR(self):
+ self.send_error(999)
+
+ def do_CUSTOM(self):
+ self.send_response(999)
+ self.send_header('Content-Type', 'text/html')
+ self.send_header('Connection', 'close')
+ self.end_headers()
+
+ def setUp(self):
+ BaseTestCase.setUp(self)
+ self.con = httplib.HTTPConnection('localhost', self.PORT)
+ self.con.connect()
+
+ def test_command(self):
+ self.con.request('GET', '/')
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 501)
+
+ def test_request_line_trimming(self):
+ self.con._http_vsn_str = 'HTTP/1.1\n'
+ self.con.putrequest('GET', '/')
+ self.con.endheaders()
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 501)
+
+ def test_version_bogus(self):
+ self.con._http_vsn_str = 'FUBAR'
+ self.con.putrequest('GET', '/')
+ self.con.endheaders()
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 400)
+
+ def test_version_digits(self):
+ self.con._http_vsn_str = 'HTTP/9.9.9'
+ self.con.putrequest('GET', '/')
+ self.con.endheaders()
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 400)
+
+ def test_version_none_get(self):
+ self.con._http_vsn_str = ''
+ self.con.putrequest('GET', '/')
+ self.con.endheaders()
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 501)
+
+ def test_version_none(self):
+ self.con._http_vsn_str = ''
+ self.con.putrequest('PUT', '/')
+ self.con.endheaders()
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 400)
+
+ def test_version_invalid(self):
+ self.con._http_vsn = 99
+ self.con._http_vsn_str = 'HTTP/9.9'
+ self.con.putrequest('GET', '/')
+ self.con.endheaders()
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 505)
+
+ def test_send_blank(self):
+ self.con._http_vsn_str = ''
+ self.con.putrequest('', '')
+ self.con.endheaders()
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 400)
+
+ def test_header_close(self):
+ self.con.putrequest('GET', '/')
+ self.con.putheader('Connection', 'close')
+ self.con.endheaders()
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 501)
+
+ def test_head_keep_alive(self):
+ self.con._http_vsn_str = 'HTTP/1.1'
+ self.con.putrequest('GET', '/')
+ self.con.putheader('Connection', 'keep-alive')
+ self.con.endheaders()
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 501)
+
+ def test_handler(self):
+ self.con.request('TEST', '/')
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 204)
+
+ def test_return_header_keep_alive(self):
+ self.con.request('KEEP', '/')
+ res = self.con.getresponse()
+ self.assertEquals(res.getheader('Connection'), 'keep-alive')
+ self.con.request('TEST', '/')
+
+ def test_internal_key_error(self):
+ self.con.request('KEYERROR', '/')
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 999)
+
+ def test_return_custom_status(self):
+ self.con.request('CUSTOM', '/')
+ res = self.con.getresponse()
+ self.assertEquals(res.status, 999)
+
+
+class SimpleHTTPServerTestCase(BaseTestCase):
+ class request_handler(NoLogRequestHandler, SimpleHTTPRequestHandler):
+ pass
+
+ def setUp(self):
+ BaseTestCase.setUp(self)
+ self.cwd = os.getcwd()
+ basetempdir = tempfile.gettempdir()
+ os.chdir(basetempdir)
+ self.data = b'We are the knights who say Ni!'
+ self.tempdir = tempfile.mkdtemp(dir=basetempdir)
+ self.tempdir_name = os.path.basename(self.tempdir)
+ temp = open(os.path.join(self.tempdir, 'test'), 'wb')
+ temp.write(self.data)
+ temp.close()
+
+ def tearDown(self):
+ try:
+ os.chdir(self.cwd)
+ try:
+ shutil.rmtree(self.tempdir)
+ except:
+ pass
+ finally:
+ BaseTestCase.tearDown(self)
+
+ def check_status_and_reason(self, response, status, data=None):
+ body = response.read()
+ self.assert_(response)
+ self.assertEquals(response.status, status)
+ self.assert_(response.reason != None)
+ if data:
+ self.assertEqual(data, body)
+
+ def test_get(self):
+ #constructs the path relative to the root directory of the HTTPServer
+ response = self.request(self.tempdir_name + '/test')
+ self.check_status_and_reason(response, 200, data=self.data)
+ response = self.request(self.tempdir_name + '/')
+ self.check_status_and_reason(response, 200)
+ response = self.request(self.tempdir_name)
+ self.check_status_and_reason(response, 301)
+ response = self.request('/ThisDoesNotExist')
+ self.check_status_and_reason(response, 404)
+ response = self.request('/' + 'ThisDoesNotExist' + '/')
+ self.check_status_and_reason(response, 404)
+ f = open(os.path.join(self.tempdir_name, 'index.html'), 'w')
+ response = self.request('/' + self.tempdir_name + '/')
+ self.check_status_and_reason(response, 200)
+ if os.name == 'posix':
+ # chmod won't work as expected on Windows platforms
+ os.chmod(self.tempdir, 0)
+ response = self.request(self.tempdir_name + '/')
+ self.check_status_and_reason(response, 404)
+ os.chmod(self.tempdir, 0o755)
+
+ def test_head(self):
+ response = self.request(
+ self.tempdir_name + '/test', method='HEAD')
+ self.check_status_and_reason(response, 200)
+ self.assertEqual(response.getheader('content-length'),
+ str(len(self.data)))
+ self.assertEqual(response.getheader('content-type'),
+ 'application/octet-stream')
+
+ def test_invalid_requests(self):
+ response = self.request('/', method='FOO')
+ self.check_status_and_reason(response, 501)
+ # requests must be case sensitive,so this should fail too
+ response = self.request('/', method='get')
+ self.check_status_and_reason(response, 501)
+ response = self.request('/', method='GETs')
+ self.check_status_and_reason(response, 501)
+
+
+cgi_file1 = """\
+#!%s
+
+print("Content-type: text/html")
+print()
+print("Hello World")
+"""
+
+cgi_file2 = """\
+#!%s
+import cgi
+
+print("Content-type: text/html")
+print()
+
+form = cgi.FieldStorage()
+print("%%s, %%s, %%s" %% (form.getfirst("spam"), form.getfirst("eggs"),\
+ form.getfirst("bacon")))
+"""
+
+class CGIHTTPServerTestCase(BaseTestCase):
+ class request_handler(NoLogRequestHandler, CGIHTTPRequestHandler):
+ pass
+
+ def setUp(self):
+ BaseTestCase.setUp(self)
+ self.parent_dir = tempfile.mkdtemp()
+ self.cgi_dir = os.path.join(self.parent_dir, 'cgi-bin')
+ os.mkdir(self.cgi_dir)
+
+ 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)
+ 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)
+ os.chmod(self.file2_path, 0o777)
+
+ self.cwd = os.getcwd()
+ os.chdir(self.parent_dir)
+
+ def tearDown(self):
+ try:
+ os.chdir(self.cwd)
+ os.remove(self.file1_path)
+ os.remove(self.file2_path)
+ os.rmdir(self.cgi_dir)
+ os.rmdir(self.parent_dir)
+ finally:
+ BaseTestCase.tearDown(self)
+
+ def test_headers_and_content(self):
+ res = self.request('/cgi-bin/file1.py')
+ self.assertEquals((b'Hello World\n', 'text/html', 200), \
+ (res.read(), res.getheader('Content-type'), res.status))
+
+ def test_post(self):
+ params = urllib.urlencode({'spam' : 1, 'eggs' : 'python', 'bacon' : 123456})
+ headers = {'Content-type' : 'application/x-www-form-urlencoded'}
+ res = self.request('/cgi-bin/file2.py', 'POST', params, headers)
+
+ self.assertEquals(res.read(), b'1, python, 123456\n')
+
+ def test_invaliduri(self):
+ res = self.request('/cgi-bin/invalid')
+ res.read()
+ self.assertEquals(res.status, 404)
+
+ def test_authorization(self):
+ headers = {b'Authorization' : b'Basic ' +
+ base64.b64encode(b'username:pass')}
+ res = self.request('/cgi-bin/file1.py', 'GET', headers=headers)
+ self.assertEquals((b'Hello World\n', 'text/html', 200), \
+ (res.read(), res.getheader('Content-type'), res.status))
+
+
+def test_main(verbose=None):
+ try:
+ cwd = os.getcwd()
+ support.run_unittest(#BaseHTTPServerTestCase,
+ SimpleHTTPServerTestCase,
+ CGIHTTPServerTestCase
+ )
+ finally:
+ os.chdir(cwd)
+
+if __name__ == '__main__':
+ test_main()
diff --git a/Lib/test/test_json.py b/Lib/test/test_json.py
index 17e1daf3607..a4b6e7a8294 100644
--- a/Lib/test/test_json.py
+++ b/Lib/test/test_json.py
@@ -11,7 +11,6 @@ import test.support
def test_main():
test.support.run_unittest(json.tests.test_suite())
- test.support.run_doctest(json)
if __name__ == "__main__":
diff --git a/Lib/test/test_opcodes.py b/Lib/test/test_opcodes.py
index 42ba600843a..8fe77ac6b72 100644
--- a/Lib/test/test_opcodes.py
+++ b/Lib/test/test_opcodes.py
@@ -68,35 +68,35 @@ class OpcodeTest(unittest.TestCase):
f = eval('lambda: None')
g = eval('lambda: None')
- self.failIf(f == g)
+ self.assertNotEquals(f, g)
f = eval('lambda a: a')
g = eval('lambda a: a')
- self.failIf(f == g)
+ self.assertNotEquals(f, g)
f = eval('lambda a=1: a')
g = eval('lambda a=1: a')
- self.failIf(f == g)
+ self.assertNotEquals(f, g)
f = eval('lambda: 0')
g = eval('lambda: 1')
- self.failIf(f == g)
+ self.assertNotEquals(f, g)
f = eval('lambda: None')
g = eval('lambda a: None')
- self.failIf(f == g)
+ self.assertNotEquals(f, g)
f = eval('lambda a: None')
g = eval('lambda b: None')
- self.failIf(f == g)
+ self.assertNotEquals(f, g)
f = eval('lambda a: None')
g = eval('lambda a=None: None')
- self.failIf(f == g)
+ self.assertNotEquals(f, g)
f = eval('lambda a=0: None')
g = eval('lambda a=1: None')
- self.failIf(f == g)
+ self.assertNotEquals(f, g)
def test_main():
diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py
index bcc16df16d1..ca0aefc049c 100644
--- a/Lib/test/test_pyclbr.py
+++ b/Lib/test/test_pyclbr.py
@@ -158,6 +158,7 @@ class PyclbrTest(TestCase):
cm('cgi', ignore=('log',)) # set with = in module
cm('urllib', ignore=('_CFNumberToInt32',
'_CStringFromCFString',
+ '_CFSetup',
'getproxies_registry',
'proxy_bypass_registry',
'proxy_bypass_macosx_sysconf',
diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py
index cc4a096f00d..ab1b083b485 100644
--- a/Lib/test/test_pydoc.py
+++ b/Lib/test/test_pydoc.py
@@ -1,25 +1,285 @@
-from test import support
-import unittest
-import pydoc
-
-class TestDescriptions(unittest.TestCase):
- def test_module(self):
- # Check that pydocfodder module can be described
- from test import pydocfodder
- doc = pydoc.render_doc(pydocfodder)
- assert "pydocfodder" in doc
-
- def test_class(self):
- class C(object): "New-style class"
- c = C()
-
- self.failUnlessEqual(pydoc.describe(C), 'class C')
- self.failUnlessEqual(pydoc.describe(c), 'C')
- self.failUnless('C in module test.test_pydoc object'
- in pydoc.render_doc(c))
-
-def test_main():
- support.run_unittest(TestDescriptions)
-
-if __name__ == "__main__":
- unittest.main()
+import sys
+import os
+import difflib
+import subprocess
+import re
+import pydoc
+import inspect
+import unittest
+import test.support
+
+from test import pydoc_mod
+
+expected_text_pattern = \
+"""
+NAME
+ test.pydoc_mod - This is a test module for test_pydoc
+
+FILE
+ %s
+%s
+CLASSES
+ builtins.object
+ A
+ B
+\x20\x20\x20\x20
+ class A(builtins.object)
+ | Hello and goodbye
+ |\x20\x20
+ | Methods defined here:
+ |\x20\x20
+ | __init__()
+ | Wow, I have no function!
+ |\x20\x20
+ | ----------------------------------------------------------------------
+ | Data descriptors defined here:
+ |\x20\x20
+ | __dict__
+ | dictionary for instance variables (if defined)
+ |\x20\x20
+ | __weakref__
+ | list of weak references to the object (if defined)
+\x20\x20\x20\x20
+ class B(builtins.object)
+ | Data descriptors defined here:
+ |\x20\x20
+ | __dict__
+ | dictionary for instance variables (if defined)
+ |\x20\x20
+ | __weakref__
+ | list of weak references to the object (if defined)
+ |\x20\x20
+ | ----------------------------------------------------------------------
+ | Data and other attributes defined here:
+ |\x20\x20
+ | NO_MEANING = 'eggs'
+
+FUNCTIONS
+ doc_func()
+ This function solves all of the world's problems:
+ hunger
+ lack of Python
+ war
+\x20\x20\x20\x20
+ nodoc_func()
+
+DATA
+ __author__ = 'Benjamin Peterson'
+ __credits__ = 'Nobody'
+ __package__ = None
+ __version__ = '1.2.3.4'
+
+VERSION
+ 1.2.3.4
+
+AUTHOR
+ Benjamin Peterson
+
+CREDITS
+ Nobody
+""".strip()
+
+expected_html_pattern = \
+"""
+
+ This is a test module for test_pydoc
+
+
+
+
+Classes |
+\x20\x20\x20\x20
+ | |
+
+- builtins.object
+
-
+
+- A
+
- B
+
+
+
+
+
+
+
+class A(builtins.object) |
+\x20\x20\x20\x20
+ |
+Hello and goodbye |
+ |
+Methods defined here:
+- __init__()
- Wow, I have no function!
+
+
+Data descriptors defined here:
+- __dict__
+- dictionary for instance variables (if defined)
+
+- __weakref__
+- list of weak references to the object (if defined)
+
+ |
+
+
+
+class B(builtins.object) |
+\x20\x20\x20\x20
+ | |
+Data descriptors defined here:
+- __dict__
+- dictionary for instance variables (if defined)
+
+- __weakref__
+- list of weak references to the object (if defined)
+
+
+Data and other attributes defined here:
+- NO_MEANING = 'eggs'
+
+ | |
+
+
+
+Functions |
+\x20\x20\x20\x20
+ | |
+- doc_func()
- This function solves all of the world's problems:
+hunger
+lack of Python
+war
+ - nodoc_func()
+ |
+
+
+
+Data |
+\x20\x20\x20\x20
+ | |
+__author__ = 'Benjamin Peterson'
+__credits__ = 'Nobody'
+__package__ = None
+__version__ = '1.2.3.4' |
+
+
+
+Author |
+\x20\x20\x20\x20
+ | |
+Benjamin Peterson |
+
+
+
+Credits |
+\x20\x20\x20\x20
+ | |
+Nobody |
+""".strip()
+
+
+# output pattern for missing module
+missing_pattern = "no Python documentation found for '%s'"
+
+def run_pydoc(module_name, *args):
+ """
+ Runs pydoc on the specified module. Returns the stripped
+ output of pydoc.
+ """
+ cmd = [sys.executable, pydoc.__file__, " ".join(args), module_name]
+ output = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout.read()
+ return output.strip()
+
+def get_pydoc_html(module):
+ "Returns pydoc generated output as html"
+ doc = pydoc.HTMLDoc()
+ output = doc.docmodule(module)
+ loc = doc.getdocloc(pydoc_mod) or ""
+ if loc:
+ loc = "
Module Docs"
+ return output.strip(), loc
+
+def get_pydoc_text(module):
+ "Returns pydoc generated output as text"
+ doc = pydoc.TextDoc()
+ loc = doc.getdocloc(pydoc_mod) or ""
+ if loc:
+ loc = "\nMODULE DOCS\n " + loc + "\n"
+
+ output = doc.docmodule(module)
+
+ # cleanup the extra text formatting that pydoc preforms
+ patt = re.compile('\b.')
+ output = patt.sub('', output)
+ return output.strip(), loc
+
+def print_diffs(text1, text2):
+ "Prints unified diffs for two texts"
+ lines1 = text1.splitlines(True)
+ lines2 = text2.splitlines(True)
+ diffs = difflib.unified_diff(lines1, lines2, n=0, fromfile='expected',
+ tofile='got')
+ print('\n' + ''.join(diffs))
+
+
+class PyDocDocTest(unittest.TestCase):
+
+ def test_html_doc(self):
+ result, doc_loc = get_pydoc_html(pydoc_mod)
+ mod_file = inspect.getabsfile(pydoc_mod)
+ expected_html = expected_html_pattern % (mod_file, mod_file, doc_loc)
+ if result != expected_html:
+ print_diffs(expected_html, result)
+ self.fail("outputs are not equal, see diff above")
+
+ def test_text_doc(self):
+ result, doc_loc = get_pydoc_text(pydoc_mod)
+ expected_text = expected_text_pattern % \
+ (inspect.getabsfile(pydoc_mod), doc_loc)
+ if result != expected_text:
+ print_diffs(expected_text, result)
+ self.fail("outputs are not equal, see diff above")
+
+ def test_not_here(self):
+ missing_module = "test.i_am_not_here"
+ result = str(run_pydoc(missing_module), 'ascii')
+ expected = missing_pattern % missing_module
+ self.assertEqual(expected, result,
+ "documentation for missing module found")
+
+
+class TestDescriptions(unittest.TestCase):
+
+ def test_module(self):
+ # Check that pydocfodder module can be described
+ from test import pydocfodder
+ doc = pydoc.render_doc(pydocfodder)
+ self.assert_("pydocfodder" in doc)
+
+ def test_classic_class(self):
+ class C: "Classic class"
+ c = C()
+ self.assertEqual(pydoc.describe(C), 'class C')
+ self.assertEqual(pydoc.describe(c), 'C')
+ expected = 'C in module %s' % __name__
+ self.assert_(expected in pydoc.render_doc(c))
+
+ def test_class(self):
+ class C(object): "New-style class"
+ c = C()
+
+ self.assertEqual(pydoc.describe(C), 'class C')
+ self.assertEqual(pydoc.describe(c), 'C')
+ expected = 'C in module %s object' % __name__
+ self.assert_(expected in pydoc.render_doc(c))
+
+
+def test_main():
+ test.support.run_unittest(PyDocDocTest, TestDescriptions)
+
+if __name__ == "__main__":
+ test_main()
diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py
index 303345befef..a056c233772 100644
--- a/Lib/test/test_weakref.py
+++ b/Lib/test/test_weakref.py
@@ -3,6 +3,7 @@ import sys
import unittest
import collections
import weakref
+import operator
from test import support
@@ -182,6 +183,26 @@ class ReferencesTestCase(TestBase):
self.assertEqual(L3[:5], p3[:5])
self.assertEqual(L3[2:5], p3[2:5])
+ def test_proxy_index(self):
+ class C:
+ def __index__(self):
+ return 10
+ o = C()
+ p = weakref.proxy(o)
+ self.assertEqual(operator.index(p), 10)
+
+ def test_proxy_div(self):
+ class C:
+ def __floordiv__(self, other):
+ return 42
+ def __ifloordiv__(self, other):
+ return 21
+ o = C()
+ p = weakref.proxy(o)
+ self.assertEqual(p // 5, 42)
+ p //= 5
+ self.assertEqual(p, 21)
+
# The PyWeakref_* C API is documented as allowing either NULL or
# None as the value for the callback, where either means "no
# callback". The "no callback" ref and proxy objects are supposed
@@ -1059,7 +1080,7 @@ class WeakKeyDictionaryTestCase(mapping_tests.BasicTestMappingProtocol):
def _reference(self):
return self.__ref.copy()
-libreftest = """ Doctest for examples in the library reference: libweakref.tex
+libreftest = """ Doctest for examples in the library reference: weakref.rst
>>> import weakref
>>> class Dict(dict):
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py
index 30efeb964a8..4682b7d06fc 100644
--- a/Lib/test/test_zipfile.py
+++ b/Lib/test/test_zipfile.py
@@ -125,6 +125,25 @@ class TestsWithSourceFile(unittest.TestCase):
for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
self.zipOpenTest(f, zipfile.ZIP_STORED)
+ def testOpenViaZipInfo(self):
+ # Create the ZIP archive
+ zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
+ zipfp.writestr("name", "foo")
+ zipfp.writestr("name", "bar")
+ zipfp.close()
+
+ zipfp = zipfile.ZipFile(TESTFN2, "r")
+ infos = zipfp.infolist()
+ data = b""
+ for info in infos:
+ data += zipfp.open(info).read()
+ self.assert_(data == b"foobar" or data == b"barfoo")
+ data = b""
+ for info in infos:
+ data += zipfp.read(info)
+ self.assert_(data == b"foobar" or data == b"barfoo")
+ zipfp.close()
+
def zipRandomOpenTest(self, f, compression):
self.makeTestArchive(f, compression)
diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py
index 49ca8a515ad..f26fda981c1 100644
--- a/Lib/tkinter/__init__.py
+++ b/Lib/tkinter/__init__.py
@@ -2903,8 +2903,7 @@ class Text(Widget):
and edit_undo
"""
- return self._getints(
- self.tk.call((self._w, 'edit') + args)) or ()
+ return self.tk.call(self._w, 'edit', *args)
def edit_modified(self, arg=None):
"""Get or Set the modified flag
diff --git a/Lib/zipfile.py b/Lib/zipfile.py
index 73b62afcbf8..fd923c8279e 100644
--- a/Lib/zipfile.py
+++ b/Lib/zipfile.py
@@ -783,10 +783,13 @@ class ZipFile:
else:
zef_file = io.open(self.filename, 'rb')
- # Get info object for name
- zinfo = self.getinfo(name)
-
- filepos = zef_file.tell()
+ # Make sure we have an info object
+ if isinstance(name, ZipInfo):
+ # 'name' is already an info object
+ zinfo = name
+ else:
+ # Get info object for name
+ zinfo = self.getinfo(name)
zef_file.seek(zinfo.header_offset, 0)
@@ -891,7 +894,7 @@ class ZipFile:
if upperdirs and not os.path.exists(upperdirs):
os.makedirs(upperdirs)
- source = self.open(member.filename, pwd=pwd)
+ source = self.open(member, pwd=pwd)
target = open(targetpath, "wb")
shutil.copyfileobj(source, target)
source.close()
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 976e54f42d5..6f70bd598e0 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -373,6 +373,12 @@ run_profile_task:
build_all_use_profile:
$(MAKE) all CFLAGS="$(CFLAGS) -fprofile-use"
+coverage:
+ @echo "Building with support for coverage checking:"
+ $(MAKE) clean
+ $(MAKE) all CFLAGS="$(CFLAGS) -O0 -pg -fprofile-arcs -ftest-coverage" LIBS="$(LIBS) -lgcov"
+
+
# Build the interpreter
$(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY)
$(LINKCC) $(LDFLAGS) $(LINKFORSHARED) -o $@ \
diff --git a/Misc/ACKS b/Misc/ACKS
index 19210a041ef..8a29b4bf68a 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -375,6 +375,7 @@ Damon Kohler
Joseph Koshy
Bob Kras
Holger Krekel
+Michael Kremer
Fabian Kreutz
Hannu Krosing
Andrew Kuchling
@@ -496,6 +497,7 @@ Piet van Oostrum
Jason Orendorff
Douglas Orr
Denis S. Otkidach
+Michael Otteneder
Russel Owen
Ondrej Palkovsky
Mike Pall
@@ -634,6 +636,7 @@ Gregory P. Smith
Rafal Smotrzyk
Dirk Soede
Paul Sokolovsky
+Cody Somerville
Clay Spence
Per Spilling
Joshua Spoerri
diff --git a/Misc/build.sh b/Misc/build.sh
index 3a0e9828290..0c8d4d5c23e 100755
--- a/Misc/build.sh
+++ b/Misc/build.sh
@@ -67,7 +67,7 @@ REFLOG="build/reflog.txt.out"
# Note: test_XXX (none currently) really leak, but are disabled
# so we don't send spam. Any test which really leaks should only
# be listed here if there are also test cases under Lib/test/leakers.
-LEAKY_TESTS="test_(asynchat|cmd_line|popen2|socket|smtplib|sys|threadsignals|urllib2_localnet)"
+LEAKY_TESTS="test_(asynchat|cmd_line|popen2|socket|smtplib|sys|threadsignals|urllib2_localnet|httpservers)"
# These tests always fail, so skip them so we don't get false positives.
_ALWAYS_SKIP=""
diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c
index c7dce8f859b..2f86ae8ad89 100644
--- a/Objects/weakrefobject.c
+++ b/Objects/weakrefobject.c
@@ -474,6 +474,8 @@ proxy_richcompare(PyObject *proxy, PyObject *v, int op)
WRAP_BINARY(proxy_add, PyNumber_Add)
WRAP_BINARY(proxy_sub, PyNumber_Subtract)
WRAP_BINARY(proxy_mul, PyNumber_Multiply)
+WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)
+WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)
WRAP_BINARY(proxy_mod, PyNumber_Remainder)
WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
WRAP_TERNARY(proxy_pow, PyNumber_Power)
@@ -492,6 +494,8 @@ WRAP_UNARY(proxy_float, PyNumber_Float)
WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
+WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)
+WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)
WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
@@ -499,6 +503,7 @@ WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
+WRAP_UNARY(proxy_index, PyNumber_Index)
static int
proxy_bool(PyWeakReference *proxy)
@@ -605,6 +610,11 @@ static PyNumberMethods proxy_as_number = {
proxy_iand, /*nb_inplace_and*/
proxy_ixor, /*nb_inplace_xor*/
proxy_ior, /*nb_inplace_or*/
+ proxy_floor_div, /*nb_floor_divide*/
+ proxy_true_div, /*nb_true_divide*/
+ proxy_ifloor_div, /*nb_inplace_floor_divide*/
+ proxy_itrue_div, /*nb_inplace_true_divide*/
+ proxy_index, /*nb_index*/
};
static PySequenceMethods proxy_as_sequence = {