summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/basehttpserver.rst9
-rw-r--r--Doc/library/difflib.rst113
-rw-r--r--Doc/library/dis.rst2
-rw-r--r--Doc/library/signal.rst15
-rw-r--r--Doc/library/simplexmlrpcserver.rst10
-rw-r--r--Lib/BaseHTTPServer.py11
-rw-r--r--Lib/curses/__init__.py4
-rw-r--r--Lib/test/test_logging.py39
-rw-r--r--Lib/test/test_signal.py48
-rw-r--r--Modules/signalmodule.c33
10 files changed, 248 insertions, 36 deletions
diff --git a/Doc/library/basehttpserver.rst b/Doc/library/basehttpserver.rst
index 0f65b26..9ac3aaf 100644
--- a/Doc/library/basehttpserver.rst
+++ b/Doc/library/basehttpserver.rst
@@ -122,6 +122,15 @@ to a handler. Code to create and run the server looks like this::
class variable.
+.. attribute:: BaseHTTPRequestHandler.error_content_type
+
+ Specifies the Content-Type HTTP header of error responses sent to the client.
+ The default value is ``'text/html'``.
+
+ .. versionadded:: 2.6
+ Previously, the content type was always ``'text/html'``.
+
+
.. attribute:: BaseHTTPRequestHandler.protocol_version
This specifies the HTTP protocol version used in responses. If set to
diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst
index 7e61aa9..66f64e5 100644
--- a/Doc/library/difflib.rst
+++ b/Doc/library/difflib.rst
@@ -144,7 +144,27 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module.
expressed in the format returned by :func:`time.ctime`. If not specified, the
strings default to blanks.
- :file:`Tools/scripts/diff.py` is a command-line front-end for this function.
+ ::
+
+ >>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n']
+ >>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n']
+ >>> for line in context_diff(s1, s2, fromfile='before.py', tofile='after.py'):
+ ... sys.stdout.write(line)
+ *** before.py
+ --- after.py
+ ***************
+ *** 1,4 ****
+ ! bacon
+ ! eggs
+ ! ham
+ guido
+ --- 1,4 ----
+ ! python
+ ! eggy
+ ! hamster
+ guido
+
+ See :ref:`difflib-interface` for a more detailed example.
.. function:: get_close_matches(word, possibilities[, n][, cutoff])
@@ -259,7 +279,24 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module.
expressed in the format returned by :func:`time.ctime`. If not specified, the
strings default to blanks.
- :file:`Tools/scripts/diff.py` is a command-line front-end for this function.
+ ::
+
+ >>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n']
+ >>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n']
+ >>> for line in unified_diff(s1, s2, fromfile='before.py', tofile='after.py'):
+ ... sys.stdout.write(line)
+ --- before.py
+ +++ after.py
+ @@ -1,4 +1,4 @@
+ -bacon
+ -eggs
+ -ham
+ +python
+ +eggy
+ +hamster
+ guido
+
+ See :ref:`difflib-interface` for a more detailed example.
.. function:: IS_LINE_JUNK(line)
@@ -635,3 +672,75 @@ As a single multi-line string it looks like this::
? ++++ ^ ^
+ 5. Flat is better than nested.
+
+.. _difflib-interface:
+
+A command-line interface to difflib
+-----------------------------------
+
+This example shows how to use difflib to create a ``diff``-like utility.
+It is also contained in the Python source distribution, as
+:file:`Tools/scripts/diff.py`.
+
+::
+
+ """ Command line interface to difflib.py providing diffs in four formats:
+
+ * ndiff: lists every line and highlights interline changes.
+ * context: highlights clusters of changes in a before/after format.
+ * unified: highlights clusters of changes in an inline format.
+ * html: generates side by side comparison with change highlights.
+
+ """
+
+ import sys, os, time, difflib, optparse
+
+ def main():
+ # Configure the option parser
+ usage = "usage: %prog [options] fromfile tofile"
+ parser = optparse.OptionParser(usage)
+ parser.add_option("-c", action="store_true", default=False,
+ help='Produce a context format diff (default)')
+ parser.add_option("-u", action="store_true", default=False,
+ help='Produce a unified format diff')
+ hlp = 'Produce HTML side by side diff (can use -c and -l in conjunction)'
+ parser.add_option("-m", action="store_true", default=False, help=hlp)
+ parser.add_option("-n", action="store_true", default=False,
+ help='Produce a ndiff format diff')
+ parser.add_option("-l", "--lines", type="int", default=3,
+ help='Set number of context lines (default 3)')
+ (options, args) = parser.parse_args()
+
+ if len(args) == 0:
+ parser.print_help()
+ sys.exit(1)
+ if len(args) != 2:
+ parser.error("need to specify both a fromfile and tofile")
+
+ n = options.lines
+ fromfile, tofile = args # as specified in the usage string
+
+ # we're passing these as arguments to the diff function
+ fromdate = time.ctime(os.stat(fromfile).st_mtime)
+ todate = time.ctime(os.stat(tofile).st_mtime)
+ fromlines = open(fromfile, 'U').readlines()
+ tolines = open(tofile, 'U').readlines()
+
+ if options.u:
+ diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile,
+ fromdate, todate, n=n)
+ elif options.n:
+ diff = difflib.ndiff(fromlines, tolines)
+ elif options.m:
+ diff = difflib.HtmlDiff().make_file(fromlines, tolines, fromfile,
+ tofile, context=options.c,
+ numlines=n)
+ else:
+ diff = difflib.context_diff(fromlines, tolines, fromfile, tofile,
+ fromdate, todate, n=n)
+
+ # we're using writelines because diff is a generator
+ sys.stdout.writelines(diff)
+
+ if __name__ == '__main__':
+ main()
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
index 78a7d5b..5b09847 100644
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -437,7 +437,7 @@ the more significant byte last.
.. opcode:: STORE_NAME (namei)
Implements ``name = TOS``. *namei* is the index of *name* in the attribute
- :attr:`co_names` of the code object. The compiler tries to use ``STORE_LOCAL``
+ :attr:`co_names` of the code object. The compiler tries to use ``STORE_FAST``
or ``STORE_GLOBAL`` if possible.
diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst
index 920752b..cf6f8f8 100644
--- a/Doc/library/signal.rst
+++ b/Doc/library/signal.rst
@@ -124,6 +124,21 @@ The :mod:`signal` module defines the following functions:
exception to be raised.
+
+.. function:: siginterrupt(signalnum, flag)
+
+ Change system call restart behaviour: if *flag* is :const:`False`, system calls
+ will be restarted when interrupted by signal *signalnum*, else system calls will
+ be interrupted. Returns nothing. Availability: Unix, Mac (see the man page
+ :manpage:`siginterrupt(3)` for further information).
+
+ Note that installing a signal handler with :func:`signal` will reset the restart
+ behaviour to interruptible by implicitly calling siginterrupt with a true *flag*
+ value for the given signal.
+
+ .. versionadded:: 2.6
+
+
.. function:: signal(signalnum, handler)
Set the handler for signal *signalnum* to the function *handler*. *handler* can
diff --git a/Doc/library/simplexmlrpcserver.rst b/Doc/library/simplexmlrpcserver.rst
index 557b525..c736e2a 100644
--- a/Doc/library/simplexmlrpcserver.rst
+++ b/Doc/library/simplexmlrpcserver.rst
@@ -101,7 +101,7 @@ alone XML-RPC servers.
Registers the XML-RPC multicall function system.multicall.
-.. attribute:: SimpleXMLRPCServer.rpc_paths
+.. attribute:: SimpleXMLRPCRequestHandler.rpc_paths
An attribute value that must be a tuple listing valid path portions of the URL
for receiving XML-RPC requests. Requests posted to other paths will result in a
@@ -116,9 +116,15 @@ SimpleXMLRPCServer Example
Server code::
from SimpleXMLRPCServer import SimpleXMLRPCServer
+ from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler
+
+ # Restrict to a particular path.
+ class RequestHandler(SimpleXMLRPCRequestHandler):
+ rpc_paths = ('/RPC2',)
# Create server
- server = SimpleXMLRPCServer(("localhost", 8000))
+ server = SimpleXMLRPCServer(("localhost", 8000),
+ requestHandler=RequestHandler)
server.register_introspection_functions()
# Register pow() function; this will use the value of
diff --git a/Lib/BaseHTTPServer.py b/Lib/BaseHTTPServer.py
index f8a1138..fbb8108 100644
--- a/Lib/BaseHTTPServer.py
+++ b/Lib/BaseHTTPServer.py
@@ -77,7 +77,7 @@ import socket # For gethostbyaddr()
import mimetools
import SocketServer
-# Default error message
+# Default error message template
DEFAULT_ERROR_MESSAGE = """\
<head>
<title>Error response</title>
@@ -90,6 +90,8 @@ DEFAULT_ERROR_MESSAGE = """\
</body>
"""
+DEFAULT_ERROR_CONTENT_TYPE = "text/html;charset=utf-8"
+
def _quote_html(html):
return html.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
@@ -217,6 +219,9 @@ class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
# where each string is of the form name[/version].
server_version = "BaseHTTP/" + __version__
+ error_message_format = DEFAULT_ERROR_MESSAGE
+ error_content_type = DEFAULT_ERROR_CONTENT_TYPE
+
def parse_request(self):
"""Parse a request (internal).
@@ -356,14 +361,12 @@ class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
content = (self.error_message_format %
{'code': code, 'message': _quote_html(message), 'explain': explain})
self.send_response(code, message)
- self.send_header("Content-Type", "text/html;charset=utf-8")
+ self.send_header("Content-Type", self.error_content_type)
self.send_header('Connection', 'close')
self.end_headers()
if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
self.wfile.write(content.encode('UTF-8', 'replace'))
- error_message_format = DEFAULT_ERROR_MESSAGE
-
def send_response(self, code, message=None):
"""Send the response header and log the response code.
diff --git a/Lib/curses/__init__.py b/Lib/curses/__init__.py
index aba540b..c3f2f25 100644
--- a/Lib/curses/__init__.py
+++ b/Lib/curses/__init__.py
@@ -14,6 +14,7 @@ __revision__ = "$Id$"
from _curses import *
from curses.wrapper import wrapper
+import os as _os
# Some constants, most notably the ACS_* ones, are only added to the C
# _curses module's dictionary after initscr() is called. (Some
@@ -25,6 +26,9 @@ from curses.wrapper import wrapper
def initscr():
import _curses, curses
+ # we call setupterm() here because it raises an error
+ # instead of calling exit() in error cases.
+ setupterm(term=_os.environ.get("TERM", "unknown"))
stdscr = _curses.initscr()
for key, value in _curses.__dict__.items():
if key[0:4] == 'ACS_' or key in ('LINES', 'COLS'):
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index a31ad37..66aa9fa 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -1828,8 +1828,7 @@ Test Main
>>> import logging, logging.handlers, logging.config
>>> from test import test_logging
-XXX: The test is unstable!
-#>>> test_logging.test_main_inner()
+>>> test_logging.test_main_inner()
ERR -> CRITICAL: Message 0 (via logrecv.tcp.ERR)
ERR -> ERROR: Message 1 (via logrecv.tcp.ERR)
INF -> CRITICAL: Message 2 (via logrecv.tcp.INF)
@@ -2010,7 +2009,7 @@ class LogRecordSocketReceiver(ThreadingTCPServer):
port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
handler=LogRecordStreamHandler):
ThreadingTCPServer.__init__(self, (host, port), handler)
- self.abort = 0
+ self.abort = False
self.timeout = 1
def serve_until_stopped(self):
@@ -2019,11 +2018,11 @@ class LogRecordSocketReceiver(ThreadingTCPServer):
self.timeout)
if rd:
self.handle_request()
+ socketDataProcessed.set()
# close the listen socket
self.server_close()
def process_request(self, request, client_address):
- #import threading
t = threading.Thread(target = self.finish_request,
args = (request, client_address))
t.start()
@@ -2108,28 +2107,18 @@ def test_main_inner():
rootLogger = logging.getLogger("")
rootLogger.setLevel(logging.DEBUG)
- # Find an unused port number
- port = logging.handlers.DEFAULT_TCP_LOGGING_PORT
- while port < logging.handlers.DEFAULT_TCP_LOGGING_PORT+100:
- try:
- tcpserver = LogRecordSocketReceiver(port=port)
- except socket.error:
- port += 1
- else:
- break
- else:
- raise ImportError("Could not find unused port")
-
-
- #Set up a handler such that all events are sent via a socket to the log
- #receiver (logrecv).
- #The handler will only be added to the rootLogger for some of the tests
+ tcpserver = LogRecordSocketReceiver(port=0)
+ port = tcpserver.socket.getsockname()[1]
+
+ # Set up a handler such that all events are sent via a socket to the log
+ # receiver (logrecv).
+ # The handler will only be added to the rootLogger for some of the tests
shdlr = logging.handlers.SocketHandler('localhost', port)
rootLogger.addHandler(shdlr)
- #Configure the logger for logrecv so events do not propagate beyond it.
- #The sockLogger output is buffered in memory until the end of the test,
- #and printed at the end.
+ # Configure the logger for logrecv so events do not propagate beyond it.
+ # The sockLogger output is buffered in memory until the end of the test,
+ # and printed at the end.
sockOut = io.StringIO()
sockLogger = logging.getLogger("logrecv")
sockLogger.setLevel(logging.DEBUG)
@@ -2158,9 +2147,9 @@ def test_main_inner():
finally:
#wait for TCP receiver to terminate
-# socketDataProcessed.wait()
+ socketDataProcessed.wait()
# ensure the server dies
- tcpserver.abort = 1
+ tcpserver.abort = True
for thread in threads:
thread.join(2.0)
print(sockOut.getvalue())
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index 80a0bb2..03e8101 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -1,7 +1,7 @@
import unittest
from test import test_support
import signal
-import os, sys, time
+import os, sys, time, errno
class HandlerBCalled(Exception):
pass
@@ -211,6 +211,50 @@ class WakeupSignalTests(unittest.TestCase):
os.close(self.write)
signal.signal(signal.SIGALRM, self.alrm)
+class SiginterruptTest(unittest.TestCase):
+ signum = signal.SIGUSR1
+ def readpipe_interrupted(self, cb):
+ r, w = os.pipe()
+ ppid = os.getpid()
+ pid = os.fork()
+
+ oldhandler = signal.signal(self.signum, lambda x,y: None)
+ cb()
+ if pid==0:
+ # child code: sleep, kill, sleep. and then exit,
+ # which closes the pipe from which the parent process reads
+ try:
+ time.sleep(0.2)
+ os.kill(ppid, self.signum)
+ time.sleep(0.2)
+ finally:
+ os._exit(0)
+
+ try:
+ os.close(w)
+
+ try:
+ d=os.read(r, 1)
+ return False
+ except OSError as err:
+ if err.errno != errno.EINTR:
+ raise
+ return True
+ finally:
+ signal.signal(self.signum, oldhandler)
+ os.waitpid(pid, 0)
+
+ def test_without_siginterrupt(self):
+ i=self.readpipe_interrupted(lambda: None)
+ self.assertEquals(i, True)
+
+ def test_siginterrupt_on(self):
+ i=self.readpipe_interrupted(lambda: signal.siginterrupt(self.signum, 1))
+ self.assertEquals(i, True)
+
+ def test_siginterrupt_off(self):
+ i=self.readpipe_interrupted(lambda: signal.siginterrupt(self.signum, 0))
+ self.assertEquals(i, False)
def test_main():
if sys.platform[:3] in ('win', 'os2'):
@@ -218,7 +262,7 @@ def test_main():
sys.platform)
test_support.run_unittest(BasicSignalTests, InterProcessSignalTests,
- WakeupSignalTests)
+ WakeupSignalTests, SiginterruptTest)
if __name__ == "__main__":
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index fbb7b4f..18f1b52 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -272,6 +272,36 @@ SIG_DFL -- if the default action for the signal is in effect\n\
None -- if an unknown handler is in effect\n\
anything else -- the callable Python object used as a handler");
+#ifdef HAVE_SIGINTERRUPT
+PyDoc_STRVAR(siginterrupt_doc,
+"siginterrupt(sig, flag) -> None\n\
+change system call restart behaviour: if flag is False, system calls\n\
+will be restarted when interrupted by signal sig, else system calls\n\
+will be interrupted.");
+
+static PyObject *
+signal_siginterrupt(PyObject *self, PyObject *args)
+{
+ int sig_num;
+ int flag;
+
+ if (!PyArg_ParseTuple(args, "ii:siginterrupt", &sig_num, &flag))
+ return NULL;
+ if (sig_num < 1 || sig_num >= NSIG) {
+ PyErr_SetString(PyExc_ValueError,
+ "signal number out of range");
+ return NULL;
+ }
+ if (siginterrupt(sig_num, flag)<0) {
+ PyErr_SetFromErrno(PyExc_RuntimeError);
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#endif
static PyObject *
signal_set_wakeup_fd(PyObject *self, PyObject *args)
@@ -325,6 +355,9 @@ static PyMethodDef signal_methods[] = {
{"signal", signal_signal, METH_VARARGS, signal_doc},
{"getsignal", signal_getsignal, METH_VARARGS, getsignal_doc},
{"set_wakeup_fd", signal_set_wakeup_fd, METH_VARARGS, set_wakeup_fd_doc},
+#ifdef HAVE_SIGINTERRUPT
+ {"siginterrupt", signal_siginterrupt, METH_VARARGS, siginterrupt_doc},
+#endif
#ifdef HAVE_PAUSE
{"pause", (PyCFunction)signal_pause,
METH_NOARGS,pause_doc},