Merged revisions 63412,63445-63447,63449-63450,63452,63454,63459,63463,63465,63470,63483-63484,63496-63497,63499-63501,63530-63531,63540,63614 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r63412 | georg.brandl | 2008-05-17 19:57:01 +0200 (Sat, 17 May 2008) | 2 lines

  #961805: fix Edit.text_modified().
........
  r63445 | georg.brandl | 2008-05-18 10:52:59 +0200 (Sun, 18 May 2008) | 2 lines

  GHOP #180 by Michael Schneider: add examples to the socketserver documentation.
........
  r63446 | georg.brandl | 2008-05-18 11:12:20 +0200 (Sun, 18 May 2008) | 2 lines

  GHOP #134, #171, #137: unit tests for the three HTTPServer modules.
........
  r63447 | georg.brandl | 2008-05-18 12:39:26 +0200 (Sun, 18 May 2008) | 3 lines

  Take namedtuple item names only from ascii_letters (this blew up on OSX),
  and make sure there are no duplicate names.
........
  r63449 | georg.brandl | 2008-05-18 13:46:51 +0200 (Sun, 18 May 2008) | 2 lines

  GHOP #217: add support for compiling Python with coverage checking enabled.
........
  r63450 | georg.brandl | 2008-05-18 13:52:36 +0200 (Sun, 18 May 2008) | 2 lines

  GHOP #257: test distutils' build_ext command, written by Josip Dzolonga.
........
  r63452 | georg.brandl | 2008-05-18 15:34:06 +0200 (Sun, 18 May 2008) | 2 lines

  Add GHOP students.
........
  r63454 | georg.brandl | 2008-05-18 18:32:48 +0200 (Sun, 18 May 2008) | 2 lines

  GHOP #121: improve test_pydoc, by Benjamin Peterson.
........
  r63459 | benjamin.peterson | 2008-05-18 22:48:07 +0200 (Sun, 18 May 2008) | 2 lines

  bring test_pydoc up to my high standards (now that I have them)
........
  r63463 | georg.brandl | 2008-05-18 23:10:19 +0200 (Sun, 18 May 2008) | 2 lines

  Fix test_pyclbr after another platform-dependent function was added to urllib.
........
  r63465 | benjamin.peterson | 2008-05-19 01:07:07 +0200 (Mon, 19 May 2008) | 2 lines

  change some imports in tests so they will not be skipped in 3.0
........
  r63470 | georg.brandl | 2008-05-19 18:47:25 +0200 (Mon, 19 May 2008) | 2 lines

  test_httpservers has unpredictable refcount behavior.
........
  r63483 | georg.brandl | 2008-05-20 08:15:36 +0200 (Tue, 20 May 2008) | 2 lines

  Activate two more test cases in test_httpservers.
........
  r63484 | georg.brandl | 2008-05-20 08:47:31 +0200 (Tue, 20 May 2008) | 2 lines

  Argh, this is the *actual* test that works under Windows.
........
  r63496 | georg.brandl | 2008-05-20 10:07:36 +0200 (Tue, 20 May 2008) | 2 lines

  Improve diffing logic and output for test_pydoc.
........
  r63497 | georg.brandl | 2008-05-20 10:10:03 +0200 (Tue, 20 May 2008) | 2 lines

  Use inspect.getabsfile() to get the documented module's filename.
........
  r63499 | georg.brandl | 2008-05-20 10:25:48 +0200 (Tue, 20 May 2008) | 3 lines

  Patch #1775025: allow opening zipfile members via ZipInfo instances.
  Patch by Graham Horler.
........
  r63500 | georg.brandl | 2008-05-20 10:40:43 +0200 (Tue, 20 May 2008) | 2 lines

  #2592: delegate nb_index and the floor/truediv slots in weakref.proxy.
........
  r63501 | georg.brandl | 2008-05-20 10:48:34 +0200 (Tue, 20 May 2008) | 2 lines

  #615772: raise a more explicit error from Tkinter.Misc.__contains__.
........
  r63530 | benjamin.peterson | 2008-05-22 02:57:02 +0200 (Thu, 22 May 2008) | 2 lines

  use more specific asserts in test_opcode
........
  r63531 | benjamin.peterson | 2008-05-22 03:02:23 +0200 (Thu, 22 May 2008) | 2 lines

  remove redundant invocation of json doctests
........
  r63540 | benjamin.peterson | 2008-05-23 01:09:26 +0200 (Fri, 23 May 2008) | 3 lines

  fix test_pydoc so it works on make installed Python installations
  Also let it pass when invoked directly
........
  r63614 | georg.brandl | 2008-05-25 10:07:37 +0200 (Sun, 25 May 2008) | 2 lines

  #2959: allow multiple close() calls for GzipFile.
........
This commit is contained in:
Georg Brandl 2008-05-25 18:19:30 +00:00
parent cea777423b
commit b533e26dfa
23 changed files with 1135 additions and 97 deletions

View file

@ -236,8 +236,8 @@ users of the server object.
.. function:: handle_timeout() .. function:: handle_timeout()
This function is called when the :attr:`timeout` attribute has been set to a 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 value other than :const:`None` and the timeout period has passed with no
requests being received. The default action for forking servers is requests being received. The default action for forking servers is
to collect the status of any child processes that have exited, while to collect the status of any child processes that have exited, while
in threading servers this method does nothing. in threading servers this method does nothing.
@ -284,27 +284,28 @@ request.
.. function:: finish() .. function:: finish()
Called after the :meth:`handle` method to perform any clean-up actions required. Called after the :meth:`handle` method to perform any clean-up actions
The default implementation does nothing. If :meth:`setup` or :meth:`handle` required. The default implementation does nothing. If :meth:`setup` or
raise an exception, this function will not be called. :meth:`handle` raise an exception, this function will not be called.
.. function:: handle() .. function:: handle()
This function must do all the work required to service a request. The default This function must do all the work required to service a request. The
implementation does nothing. Several instance attributes are available to it; default implementation does nothing. Several instance attributes are
the request is available as :attr:`self.request`; the client address as available to it; the request is available as :attr:`self.request`; the client
:attr:`self.client_address`; and the server instance as :attr:`self.server`, in address as :attr:`self.client_address`; and the server instance as
case it needs access to per-server information. :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. The type of :attr:`self.request` is different for datagram or stream
For stream services, :attr:`self.request` is a socket object; for datagram services. For stream services, :attr:`self.request` is a socket object; for
services, :attr:`self.request` is a string. However, this can be hidden by using datagram services, :attr:`self.request` is a pair of string and socket.
the request handler subclasses :class:`StreamRequestHandler` or However, this can be hidden by using the request handler subclasses
:class:`DatagramRequestHandler`, which override the :meth:`setup` and :class:`StreamRequestHandler` or :class:`DatagramRequestHandler`, which
:meth:`finish` methods, and provide :attr:`self.rfile` and :attr:`self.wfile` override the :meth:`setup` and :meth:`finish` methods, and provide
attributes. :attr:`self.rfile` and :attr:`self.wfile` can be read or written, :attr:`self.rfile` and :attr:`self.wfile` attributes. :attr:`self.rfile` and
respectively, to get the request data or return data to the client. :attr:`self.wfile` can be read or written, respectively, to get the request
data or return data to the client.
.. function:: setup() .. function:: setup()
@ -312,3 +313,217 @@ request.
Called before the :meth:`handle` method to perform any initialization actions Called before the :meth:`handle` method to perform any initialization actions
required. The default implementation does nothing. 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.

View file

@ -150,11 +150,11 @@ ZipFile Objects
.. method:: ZipFile.open(name[, mode[, pwd]]) .. method:: ZipFile.open(name[, mode[, pwd]])
Extract a member from the archive as a file-like object (ZipExtFile). *name* is 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 the name of the file in the archive, or a :class:`ZipInfo` object. The *mode*
one of the following: ``'r'`` (the default), ``'U'``, or ``'rU'``. Choosing parameter, if included, must be one of the following: ``'r'`` (the default),
``'U'`` or ``'rU'`` will enable universal newline support in the read-only ``'U'``, or ``'rU'``. Choosing ``'U'`` or ``'rU'`` will enable universal newline
object. *pwd* is the password used for encrypted files. Calling :meth:`open` support in the read-only object. *pwd* is the password used for encrypted files.
on a closed ZipFile will raise a :exc:`RuntimeError`. Calling :meth:`open` on a closed ZipFile will raise a :exc:`RuntimeError`.
.. note:: .. note::
@ -173,14 +173,20 @@ ZipFile Objects
create a new file object that will be held by the ZipExtFile, allowing it to create a new file object that will be held by the ZipExtFile, allowing it to
operate independently of the ZipFile. 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]]) .. method:: ZipFile.extract(member[, path[, pwd]])
Extract a member from the archive to the current working directory, using its Extract a member from the archive to the current working directory; *member*
full name. Its file information is extracted as accurately as possible. must be its full name or a :class:`ZipInfo` object). Its file information is
*path* specifies a different directory to extract to. *member* can be a extracted as accurately as possible. *path* specifies a different directory
filename or a :class:`ZipInfo` object. *pwd* is the password used for to extract to. *member* can be a filename or a :class:`ZipInfo` object.
encrypted files. *pwd* is the password used for encrypted files.
.. method:: ZipFile.extractall([path[, members[, pwd]]]) .. method:: ZipFile.extractall([path[, members[, pwd]]])
@ -203,9 +209,10 @@ ZipFile Objects
.. method:: ZipFile.read(name[, pwd]) .. method:: ZipFile.read(name[, pwd])
Return the bytes of the file in the archive. The archive must be open for read Return the bytes of the file *name* in the archive. *name* is the name of the
or append. *pwd* is the password used for encrypted files and, if specified, it file in the archive, or a :class:`ZipInfo` object. The archive must be open for
will override the default password set with :meth:`setpassword`. Calling 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`. :meth:`read` on a closed ZipFile will raise a :exc:`RuntimeError`.

View file

@ -222,6 +222,12 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
error_message_format = DEFAULT_ERROR_MESSAGE error_message_format = DEFAULT_ERROR_MESSAGE
error_content_type = DEFAULT_ERROR_CONTENT_TYPE 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): def parse_request(self):
"""Parse a request (internal). """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.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 self.close_connection = 1
requestline = str(self.raw_requestline, 'iso-8859-1') requestline = str(self.raw_requestline, 'iso-8859-1')
if requestline[-2:] == '\r\n': if requestline[-2:] == '\r\n':

View file

@ -182,8 +182,10 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
env['AUTH_TYPE'] = authorization[0] env['AUTH_TYPE'] = authorization[0]
if authorization[0].lower() == "basic": if authorization[0].lower() == "basic":
try: try:
authorization = base64.decodestring(authorization[1]) authorization = authorization[1].encode('ascii')
except binascii.Error: authorization = base64.decodestring(authorization).\
decode('ascii')
except (binascii.Error, UnicodeError):
pass pass
else: else:
authorization = authorization.split(':') authorization = authorization.split(':')

View file

@ -11,13 +11,14 @@ __version__ = "0.6"
__all__ = ["SimpleHTTPRequestHandler"] __all__ = ["SimpleHTTPRequestHandler"]
import os import os
import sys
import posixpath import posixpath
import BaseHTTPServer import BaseHTTPServer
import urllib import urllib
import cgi import cgi
import shutil import shutil
import mimetypes import mimetypes
from io import StringIO from io import BytesIO
class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
@ -76,12 +77,8 @@ class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
else: else:
return self.list_directory(path) return self.list_directory(path)
ctype = self.guess_type(path) ctype = self.guess_type(path)
if ctype.startswith('text/'):
mode = 'r'
else:
mode = 'rb'
try: try:
f = open(path, mode) f = open(path, 'rb')
except IOError: except IOError:
self.send_error(404, "File not found") self.send_error(404, "File not found")
return None return None
@ -107,12 +104,12 @@ class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
self.send_error(404, "No permission to list directory") self.send_error(404, "No permission to list directory")
return None return None
list.sort(key=lambda a: a.lower()) list.sort(key=lambda a: a.lower())
f = StringIO() r = []
displaypath = cgi.escape(urllib.unquote(self.path)) displaypath = cgi.escape(urllib.unquote(self.path))
f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">') r.append('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
f.write("<html>\n<title>Directory listing for %s</title>\n" % displaypath) r.append("<html>\n<title>Directory listing for %s</title>\n" % displaypath)
f.write("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath) r.append("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath)
f.write("<hr>\n<ul>\n") r.append("<hr>\n<ul>\n")
for name in list: for name in list:
fullname = os.path.join(path, name) fullname = os.path.join(path, name)
displayname = linkname = name displayname = linkname = name
@ -123,14 +120,17 @@ class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
if os.path.islink(fullname): if os.path.islink(fullname):
displayname = name + "@" displayname = name + "@"
# Note: a link to a directory displays with @ and links with / # Note: a link to a directory displays with @ and links with /
f.write('<li><a href="%s">%s</a>\n' r.append('<li><a href="%s">%s</a>\n'
% (urllib.quote(linkname), cgi.escape(displayname))) % (urllib.quote(linkname), cgi.escape(displayname)))
f.write("</ul>\n<hr>\n</body>\n</html>\n") r.append("</ul>\n<hr>\n</body>\n</html>\n")
length = f.tell() enc = sys.getfilesystemencoding()
encoded = ''.join(r).encode(enc)
f = BytesIO()
f.write(encoded)
f.seek(0) f.seek(0)
self.send_response(200) self.send_response(200)
self.send_header("Content-type", "text/html") self.send_header("Content-type", "text/html; charset=%s" % enc)
self.send_header("Content-Length", str(length)) self.send_header("Content-Length", str(len(encoded)))
self.end_headers() self.end_headers()
return f return f

View file

@ -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())

View file

@ -323,6 +323,8 @@ class GzipFile:
raise IOError("Incorrect length of data produced") raise IOError("Incorrect length of data produced")
def close(self): def close(self):
if self.fileobj is None:
return
if self.mode == WRITE: if self.mode == WRITE:
self.fileobj.write(self.compress.flush()) self.fileobj.write(self.compress.flush())
write32u(self.fileobj, self.crc) write32u(self.fileobj, self.crc)

54
Lib/test/pydoc_mod.py Normal file
View file

@ -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

View file

@ -114,7 +114,9 @@ class TestNamedTuple(unittest.TestCase):
# n = 10000 # n = 10000
n = 254 # SyntaxError: more than 255 arguments: n = 254 # SyntaxError: more than 255 arguments:
import string, random 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) Big = namedtuple('Big', names)
b = Big(*range(n)) b = Big(*range(n))
self.assertEqual(b, tuple(range(n))) self.assertEqual(b, tuple(range(n)))

View file

@ -24,14 +24,14 @@ data2 = b"""/* zlibmodule.c -- gzip-compatible data compression */
class TestGzip(unittest.TestCase): class TestGzip(unittest.TestCase):
filename = support.TESTFN filename = support.TESTFN
def setUp (self): def setUp(self):
support.unlink(self.filename) support.unlink(self.filename)
def tearDown (self): def tearDown(self):
support.unlink(self.filename) support.unlink(self.filename)
def test_write (self): def test_write(self):
f = gzip.GzipFile(self.filename, 'wb') ; f.write(data1 * 50) f = gzip.GzipFile(self.filename, 'wb') ; f.write(data1 * 50)
# Try flush and fileno. # Try flush and fileno.
@ -41,6 +41,9 @@ class TestGzip(unittest.TestCase):
os.fsync(f.fileno()) os.fsync(f.fileno())
f.close() f.close()
# Test multiple close() calls.
f.close()
def test_read(self): def test_read(self):
self.test_write() self.test_write()
# Try reading. # Try reading.

View file

@ -0,0 +1,354 @@
"""Unittests for the various HTTPServer modules.
Written by Cody A.W. Somerville <cody-somerville@ubuntu.com>,
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()

View file

@ -11,7 +11,6 @@ import test.support
def test_main(): def test_main():
test.support.run_unittest(json.tests.test_suite()) test.support.run_unittest(json.tests.test_suite())
test.support.run_doctest(json)
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -68,35 +68,35 @@ class OpcodeTest(unittest.TestCase):
f = eval('lambda: None') f = eval('lambda: None')
g = eval('lambda: None') g = eval('lambda: None')
self.failIf(f == g) self.assertNotEquals(f, g)
f = eval('lambda a: a') f = eval('lambda a: a')
g = eval('lambda a: a') g = eval('lambda a: a')
self.failIf(f == g) self.assertNotEquals(f, g)
f = eval('lambda a=1: a') f = eval('lambda a=1: a')
g = eval('lambda a=1: a') g = eval('lambda a=1: a')
self.failIf(f == g) self.assertNotEquals(f, g)
f = eval('lambda: 0') f = eval('lambda: 0')
g = eval('lambda: 1') g = eval('lambda: 1')
self.failIf(f == g) self.assertNotEquals(f, g)
f = eval('lambda: None') f = eval('lambda: None')
g = eval('lambda a: None') g = eval('lambda a: None')
self.failIf(f == g) self.assertNotEquals(f, g)
f = eval('lambda a: None') f = eval('lambda a: None')
g = eval('lambda b: None') g = eval('lambda b: None')
self.failIf(f == g) self.assertNotEquals(f, g)
f = eval('lambda a: None') f = eval('lambda a: None')
g = eval('lambda a=None: None') g = eval('lambda a=None: None')
self.failIf(f == g) self.assertNotEquals(f, g)
f = eval('lambda a=0: None') f = eval('lambda a=0: None')
g = eval('lambda a=1: None') g = eval('lambda a=1: None')
self.failIf(f == g) self.assertNotEquals(f, g)
def test_main(): def test_main():

View file

@ -158,6 +158,7 @@ class PyclbrTest(TestCase):
cm('cgi', ignore=('log',)) # set with = in module cm('cgi', ignore=('log',)) # set with = in module
cm('urllib', ignore=('_CFNumberToInt32', cm('urllib', ignore=('_CFNumberToInt32',
'_CStringFromCFString', '_CStringFromCFString',
'_CFSetup',
'getproxies_registry', 'getproxies_registry',
'proxy_bypass_registry', 'proxy_bypass_registry',
'proxy_bypass_macosx_sysconf', 'proxy_bypass_macosx_sysconf',

View file

@ -1,25 +1,285 @@
from test import support import sys
import unittest import os
import pydoc import difflib
import subprocess
class TestDescriptions(unittest.TestCase): import re
def test_module(self): import pydoc
# Check that pydocfodder module can be described import inspect
from test import pydocfodder import unittest
doc = pydoc.render_doc(pydocfodder) import test.support
assert "pydocfodder" in doc
from test import pydoc_mod
def test_class(self):
class C(object): "New-style class" expected_text_pattern = \
c = C() """
NAME
self.failUnlessEqual(pydoc.describe(C), 'class C') test.pydoc_mod - This is a test module for test_pydoc
self.failUnlessEqual(pydoc.describe(c), 'C')
self.failUnless('C in module test.test_pydoc object' FILE
in pydoc.render_doc(c)) %s
%s
def test_main(): CLASSES
support.run_unittest(TestDescriptions) builtins.object
A
if __name__ == "__main__": B
unittest.main() \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 = \
"""
<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="test.html"><font color="#ffffff">test</font></a>.pydoc_mod</strong></big></big> (version 1.2.3.4)</font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:%s">%s</a>%s</font></td></tr></table>
<p><tt>This&nbsp;is&nbsp;a&nbsp;test&nbsp;module&nbsp;for&nbsp;test_pydoc</tt></p>
<p>
<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ee77aa">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr>
\x20\x20\x20\x20
<tr><td bgcolor="#ee77aa"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%%"><dl>
<dt><font face="helvetica, arial"><a href="builtins.html#object">builtins.object</a>
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="test.pydoc_mod.html#A">A</a>
</font></dt><dt><font face="helvetica, arial"><a href="test.pydoc_mod.html#B">B</a>
</font></dt></dl>
</dd>
</dl>
<p>
<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="A">class <strong>A</strong></a>(<a href="builtins.html#object">builtins.object</a>)</font></td></tr>
\x20\x20\x20\x20
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>Hello&nbsp;and&nbsp;goodbye<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%%">Methods defined here:<br>
<dl><dt><a name="A-__init__"><strong>__init__</strong></a>()</dt><dd><tt>Wow,&nbsp;I&nbsp;have&nbsp;no&nbsp;function!</tt></dd></dl>
<hr>
Data descriptors defined here:<br>
<dl><dt><strong>__dict__</strong></dt>
<dd><tt>dictionary&nbsp;for&nbsp;instance&nbsp;variables&nbsp;(if&nbsp;defined)</tt></dd>
</dl>
<dl><dt><strong>__weakref__</strong></dt>
<dd><tt>list&nbsp;of&nbsp;weak&nbsp;references&nbsp;to&nbsp;the&nbsp;object&nbsp;(if&nbsp;defined)</tt></dd>
</dl>
</td></tr></table> <p>
<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="B">class <strong>B</strong></a>(<a href="builtins.html#object">builtins.object</a>)</font></td></tr>
\x20\x20\x20\x20
<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%%">Data descriptors defined here:<br>
<dl><dt><strong>__dict__</strong></dt>
<dd><tt>dictionary&nbsp;for&nbsp;instance&nbsp;variables&nbsp;(if&nbsp;defined)</tt></dd>
</dl>
<dl><dt><strong>__weakref__</strong></dt>
<dd><tt>list&nbsp;of&nbsp;weak&nbsp;references&nbsp;to&nbsp;the&nbsp;object&nbsp;(if&nbsp;defined)</tt></dd>
</dl>
<hr>
Data and other attributes defined here:<br>
<dl><dt><strong>NO_MEANING</strong> = 'eggs'</dl>
</td></tr></table></td></tr></table><p>
<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#eeaa77">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Functions</strong></big></font></td></tr>
\x20\x20\x20\x20
<tr><td bgcolor="#eeaa77"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%%"><dl><dt><a name="-doc_func"><strong>doc_func</strong></a>()</dt><dd><tt>This&nbsp;function&nbsp;solves&nbsp;all&nbsp;of&nbsp;the&nbsp;world's&nbsp;problems:<br>
hunger<br>
lack&nbsp;of&nbsp;Python<br>
war</tt></dd></dl>
<dl><dt><a name="-nodoc_func"><strong>nodoc_func</strong></a>()</dt></dl>
</td></tr></table><p>
<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#55aa55">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
\x20\x20\x20\x20
<tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%%"><strong>__author__</strong> = 'Benjamin Peterson'<br>
<strong>__credits__</strong> = 'Nobody'<br>
<strong>__package__</strong> = None<br>
<strong>__version__</strong> = '1.2.3.4'</td></tr></table><p>
<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#7799ee">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Author</strong></big></font></td></tr>
\x20\x20\x20\x20
<tr><td bgcolor="#7799ee"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%%">Benjamin&nbsp;Peterson</td></tr></table><p>
<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#7799ee">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Credits</strong></big></font></td></tr>
\x20\x20\x20\x20
<tr><td bgcolor="#7799ee"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%%">Nobody</td></tr></table>
""".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 = "<br><a href=\"" + loc + "\">Module Docs</a>"
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()

View file

@ -3,6 +3,7 @@ import sys
import unittest import unittest
import collections import collections
import weakref import weakref
import operator
from test import support from test import support
@ -182,6 +183,26 @@ class ReferencesTestCase(TestBase):
self.assertEqual(L3[:5], p3[:5]) self.assertEqual(L3[:5], p3[:5])
self.assertEqual(L3[2:5], p3[2: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 # The PyWeakref_* C API is documented as allowing either NULL or
# None as the value for the callback, where either means "no # None as the value for the callback, where either means "no
# callback". The "no callback" ref and proxy objects are supposed # callback". The "no callback" ref and proxy objects are supposed
@ -1059,7 +1080,7 @@ class WeakKeyDictionaryTestCase(mapping_tests.BasicTestMappingProtocol):
def _reference(self): def _reference(self):
return self.__ref.copy() 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 >>> import weakref
>>> class Dict(dict): >>> class Dict(dict):

View file

@ -125,6 +125,25 @@ class TestsWithSourceFile(unittest.TestCase):
for f in (TESTFN2, TemporaryFile(), io.BytesIO()): for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
self.zipOpenTest(f, zipfile.ZIP_STORED) 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): def zipRandomOpenTest(self, f, compression):
self.makeTestArchive(f, compression) self.makeTestArchive(f, compression)

View file

@ -2903,8 +2903,7 @@ class Text(Widget):
and edit_undo and edit_undo
""" """
return self._getints( return self.tk.call(self._w, 'edit', *args)
self.tk.call((self._w, 'edit') + args)) or ()
def edit_modified(self, arg=None): def edit_modified(self, arg=None):
"""Get or Set the modified flag """Get or Set the modified flag

View file

@ -783,10 +783,13 @@ class ZipFile:
else: else:
zef_file = io.open(self.filename, 'rb') zef_file = io.open(self.filename, 'rb')
# Get info object for name # Make sure we have an info object
zinfo = self.getinfo(name) if isinstance(name, ZipInfo):
# 'name' is already an info object
filepos = zef_file.tell() zinfo = name
else:
# Get info object for name
zinfo = self.getinfo(name)
zef_file.seek(zinfo.header_offset, 0) zef_file.seek(zinfo.header_offset, 0)
@ -891,7 +894,7 @@ class ZipFile:
if upperdirs and not os.path.exists(upperdirs): if upperdirs and not os.path.exists(upperdirs):
os.makedirs(upperdirs) os.makedirs(upperdirs)
source = self.open(member.filename, pwd=pwd) source = self.open(member, pwd=pwd)
target = open(targetpath, "wb") target = open(targetpath, "wb")
shutil.copyfileobj(source, target) shutil.copyfileobj(source, target)
source.close() source.close()

View file

@ -373,6 +373,12 @@ run_profile_task:
build_all_use_profile: build_all_use_profile:
$(MAKE) all CFLAGS="$(CFLAGS) -fprofile-use" $(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 # Build the interpreter
$(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY) $(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY)
$(LINKCC) $(LDFLAGS) $(LINKFORSHARED) -o $@ \ $(LINKCC) $(LDFLAGS) $(LINKFORSHARED) -o $@ \

View file

@ -375,6 +375,7 @@ Damon Kohler
Joseph Koshy Joseph Koshy
Bob Kras Bob Kras
Holger Krekel Holger Krekel
Michael Kremer
Fabian Kreutz Fabian Kreutz
Hannu Krosing Hannu Krosing
Andrew Kuchling Andrew Kuchling
@ -496,6 +497,7 @@ Piet van Oostrum
Jason Orendorff Jason Orendorff
Douglas Orr Douglas Orr
Denis S. Otkidach Denis S. Otkidach
Michael Otteneder
Russel Owen Russel Owen
Ondrej Palkovsky Ondrej Palkovsky
Mike Pall Mike Pall
@ -634,6 +636,7 @@ Gregory P. Smith
Rafal Smotrzyk Rafal Smotrzyk
Dirk Soede Dirk Soede
Paul Sokolovsky Paul Sokolovsky
Cody Somerville
Clay Spence Clay Spence
Per Spilling Per Spilling
Joshua Spoerri Joshua Spoerri

View file

@ -67,7 +67,7 @@ REFLOG="build/reflog.txt.out"
# Note: test_XXX (none currently) really leak, but are disabled # Note: test_XXX (none currently) really leak, but are disabled
# so we don't send spam. Any test which really leaks should only # 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. # 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. # These tests always fail, so skip them so we don't get false positives.
_ALWAYS_SKIP="" _ALWAYS_SKIP=""

View file

@ -474,6 +474,8 @@ proxy_richcompare(PyObject *proxy, PyObject *v, int op)
WRAP_BINARY(proxy_add, PyNumber_Add) WRAP_BINARY(proxy_add, PyNumber_Add)
WRAP_BINARY(proxy_sub, PyNumber_Subtract) WRAP_BINARY(proxy_sub, PyNumber_Subtract)
WRAP_BINARY(proxy_mul, PyNumber_Multiply) 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_mod, PyNumber_Remainder)
WRAP_BINARY(proxy_divmod, PyNumber_Divmod) WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
WRAP_TERNARY(proxy_pow, PyNumber_Power) 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_iadd, PyNumber_InPlaceAdd)
WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract) WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply) 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_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower) WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift) 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_iand, PyNumber_InPlaceAnd)
WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor) WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr) WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
WRAP_UNARY(proxy_index, PyNumber_Index)
static int static int
proxy_bool(PyWeakReference *proxy) proxy_bool(PyWeakReference *proxy)
@ -605,6 +610,11 @@ static PyNumberMethods proxy_as_number = {
proxy_iand, /*nb_inplace_and*/ proxy_iand, /*nb_inplace_and*/
proxy_ixor, /*nb_inplace_xor*/ proxy_ixor, /*nb_inplace_xor*/
proxy_ior, /*nb_inplace_or*/ 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 = { static PySequenceMethods proxy_as_sequence = {