svn+ssh://pythondev@svn.python.org/python/trunk
........
r60080 | andrew.kuchling | 2008-01-19 17:26:13 +0100 (Sat, 19 Jan 2008) | 2 lines
Patch #742598 from Michael Pomraning: add .timeout attribute to SocketServer that will call
.handle_timeout() method when no requests are received within the timeout period.
........
r60081 | andrew.kuchling | 2008-01-19 17:34:09 +0100 (Sat, 19 Jan 2008) | 1 line
Add item
........
r60082 | christian.heimes | 2008-01-19 17:39:27 +0100 (Sat, 19 Jan 2008) | 2 lines
Disabled test_xmlrpc:test_404. It's causing lots of false alarms.
I also disabled a test in test_ssl which requires network access to svn.python.org. This fixes a bug Skip has reported a while ago.
........
r60083 | georg.brandl | 2008-01-19 18:38:53 +0100 (Sat, 19 Jan 2008) | 2 lines
Clarify thread.join() docs. #1873.
........
r60084 | georg.brandl | 2008-01-19 19:02:46 +0100 (Sat, 19 Jan 2008) | 2 lines
#1782: don't leak in error case in PyModule_AddXxxConstant. Patch by Hrvoje Nik?\197?\161i?\196?\135.
........
r60085 | andrew.kuchling | 2008-01-19 19:08:52 +0100 (Sat, 19 Jan 2008) | 1 line
Sort two names into position
........
r60086 | andrew.kuchling | 2008-01-19 19:18:41 +0100 (Sat, 19 Jan 2008) | 2 lines
Patch #976880: add mmap .rfind() method, and 'end' paramter to .find().
Contributed by John Lenton.
........
r60087 | facundo.batista | 2008-01-19 19:38:19 +0100 (Sat, 19 Jan 2008) | 5 lines
Fix #
1693149. Now you can pass several modules separated by
coma to trace.py in the same --ignore-module option.
Thanks Raghuram Devarakonda.
........
r60088 | facundo.batista | 2008-01-19 19:45:46 +0100 (Sat, 19 Jan 2008) | 3 lines
Comment in NEWS regarding the change in trace.py.
........
r60089 | skip.montanaro | 2008-01-19 19:47:24 +0100 (Sat, 19 Jan 2008) | 2 lines
missing from r60088 checkin.
........
r60091 | andrew.kuchling | 2008-01-19 20:14:05 +0100 (Sat, 19 Jan 2008) | 1 line
Add item
........
r60092 | georg.brandl | 2008-01-19 20:27:05 +0100 (Sat, 19 Jan 2008) | 4 lines
Fix #1679: "0x" was taken as a valid integer literal.
Fixes the tokenizer, tokenize.py and int() to reject this.
Patches by Malte Helmert.
........
r60093 | georg.brandl | 2008-01-19 20:48:19 +0100 (Sat, 19 Jan 2008) | 3 lines
Fix #1146: TextWrap vs words 1-character shorter than the width.
Patch by Quentin Gallet-Gilles.
........
an exception being raised.
-.. method:: mmap.find(string[, start])
+.. method:: mmap.find(string[, start[, end]])
- Returns the lowest index in the object where the substring *string* is found.
- Returns ``-1`` on failure. *start* is the index at which the search begins, and
- defaults to zero.
+ Returns the lowest index in the object where the substring *string* is found,
+ such that *string* is contained in the range [*start*, *end*]. Optional
+ arguments *start* and *end* are interpreted as in slice notation.
+ Returns ``-1`` on failure.
.. method:: mmap.flush([offset, size])
:exc:`TypeError` exception.
+.. method:: mmap.rfind(string[, start[, end]])
+
+ Returns the highest index in the object where the substring *string* is
+ found, such that *string* is contained in the range [*start*,
+ *end*]. Optional arguments *start* and *end* are interpreted as in slice
+ notation. Returns ``-1`` on failure.
+
+
.. method:: mmap.seek(pos[, whence])
Set the file's current position. *whence* argument is optional and defaults to
not exit until all threads created by :class:`ThreadingMixIn` have exited.
Server classes have the same external methods and attributes, no matter what
-network protocol they use:
+network protocol they use.
Server Creation Notes
The type of socket used by the server; :const:`socket.SOCK_STREAM` and
:const:`socket.SOCK_DGRAM` are two possible values.
+.. data:: timeout
+
+ Timeout duration, measured in seconds, or :const:`None` if no timeout is desired.
+ If no incoming requests are received within the timeout period,
+ the :meth:`handle_timeout` method is called and then the server resumes waiting for
+ requests.
+
There are various server methods that can be overridden by subclasses of base
server classes like :class:`TCPServer`; these methods aren't useful to external
users of the server object.
method raises an exception. The default action is to print the traceback to
standard output and continue handling further requests.
+.. 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
+ 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.
.. function:: process_request(request, client_address)
When the *timeout* argument is present and not ``None``, it should be a floating
point number specifying a timeout for the operation in seconds (or fractions
- thereof). As :meth:`join` always returns ``None``, you must call
- :meth:`isAlive` to decide whether a timeout happened.
+ thereof). As :meth:`join` always returns ``None``, you must call :meth:`isAlive`
+ after :meth:`join` to decide whether a timeout happened -- if the thread is
+ still alive, the :meth:`join` call timed out.
When the *timeout* argument is not present or ``None``, the operation will block
until the thread terminates.
A thread can be :meth:`join`\ ed many times.
- :meth:`join` may throw a :exc:`RuntimeError`, if an attempt is made to join the
- current thread as that would cause a deadlock. It is also an error to
- :meth:`join` a thread before it has been started and attempts to do so raises
- same exception.
+ :meth:`join` raises a :exc:`RuntimeError` if an attempt is made to join
+ the current thread as that would cause a deadlock. It is also an error to
+ :meth:`join` a thread before it has been started and attempts to do so
+ raises the same exception.
.. method:: Thread.getName()
stdout for each file processed.
:option:`--ignore-module`
- Ignore the named module and its submodules (if it is a package). May be given
+ Accepts comma separated list of module names. Ignore each of the named
+ module and its submodules (if it is a package). May be given
multiple times.
:option:`--ignore-dir`
- Ignore all modules and packages in the named directory and subdirectories. May
- be given multiple times.
+ Ignore all modules and packages in the named directory and subdirectories
+ (multiple directories can be joined by os.pathsep). May be given multiple
+ times.
.. _trace-api:
.. Patch #1490190
+* :class:`mmap` objects now have a :meth:`rfind` method that finds
+ a substring, beginning at the end of the string and searching
+ backwards. The :meth:`find` method
+ also gained a *end* parameter containing the index at which to stop
+ the forward search.
+ (Contributed by John Lenton.)
+
* The :mod:`new` module has been removed from Python 3.0.
Importing it therefore
triggers a warning message when Python is running in 3.0-warning
(Contributed by Alberto Bertogli.)
.. Patch #1646
+
+* The base classes in the :mod:`SocketServer` module now support
+ calling a :meth:`handle_timeout` method after a span of inactivity
+ specified by the server's :attr:`timeout` attribute. (Contributed
+ by Michael Pomraning.)
+
+ .. Patch #742598
* A new variable in the :mod:`sys` module,
:attr:`float_info`, is an object
- server_bind()
- server_activate()
- get_request() -> request, client_address
+ - handle_timeout()
- verify_request(request, client_address)
- server_close()
- process_request(request, client_address)
Class variables that may be overridden by derived classes or
instances:
+ - timeout
- address_family
- socket_type
- allow_reuse_address
"""
+ timeout = None
+
def __init__(self, server_address, RequestHandlerClass):
"""Constructor. May be extended, do not override."""
self.server_address = server_address
# finishing a request is fairly arbitrary. Remember:
#
# - handle_request() is the top-level call. It calls
- # get_request(), verify_request() and process_request()
- # - get_request() is different for stream or datagram sockets
+ # await_request(), verify_request() and process_request()
+ # - get_request(), called by await_request(), is different for
+ # stream or datagram sockets
# - process_request() is the place that may fork a new process
# or create a new thread to finish the request
# - finish_request() instantiates the request handler class;
def handle_request(self):
"""Handle one request, possibly blocking."""
try:
- request, client_address = self.get_request()
+ request, client_address = self.await_request()
except socket.error:
return
if self.verify_request(request, client_address):
self.handle_error(request, client_address)
self.close_request(request)
+ def await_request(self):
+ """Call get_request or handle_timeout, observing self.timeout.
+
+ Returns value from get_request() or raises socket.timeout exception if
+ timeout was exceeded.
+ """
+ if self.timeout is not None:
+ # If timeout == 0, you're responsible for your own fd magic.
+ import select
+ fd_sets = select.select([self], [], [], self.timeout)
+ if not fd_sets[0]:
+ self.handle_timeout()
+ raise socket.timeout("Listening timed out")
+ return self.get_request()
+
+ def handle_timeout(self):
+ """Called if no new request arrives within self.timeout.
+
+ Overridden by ForkingMixIn.
+ """
+ pass
+
def verify_request(self, request, client_address):
"""Verify the request. May be overridden.
- server_bind()
- server_activate()
- get_request() -> request, client_address
+ - handle_timeout()
- verify_request(request, client_address)
- process_request(request, client_address)
- close_request(request)
Class variables that may be overridden by derived classes or
instances:
+ - timeout
- address_family
- socket_type
- request_queue_size (only for stream sockets)
"""Mix-in class to handle each request in a new process."""
+ timeout = 300
active_children = None
max_children = 40
def collect_children(self):
- """Internal routine to wait for died children."""
+ """Internal routine to wait for children that have exited."""
while self.active_children:
if len(self.active_children) < self.max_children:
options = os.WNOHANG
if not pid: break
self.active_children.remove(pid)
+ def handle_timeout(self):
+ """Wait for zombies after self.timeout seconds of inactivity.
+
+ May be extended, do not override.
+ """
+ self.collect_children()
+
def process_request(self, request, client_address):
"""Fork a new subprocess to process the request."""
self.collect_children()
self.assertEqual(int('0O123', 8), 83)
self.assertEqual(int('0B100', 2), 4)
+ # Bug 1679: "0x" is not a valid hex literal
+ self.assertRaises(ValueError, int, "0x", 16)
+ self.assertRaises(ValueError, int, "0x", 0)
+
+
# SF bug 1334662: int(string, base) wrong answers
# Various representations of 2**32 evaluated to 0
# rather than 2**32 in previous versions
self.assertEquals(0o377, 255)
self.assertEquals(2147483647, 0o17777777777)
self.assertEquals(0b1001, 9)
+ # "0x" is not a valid literal
+ self.assertRaises(SyntaxError, eval, "0x")
from sys import maxsize
if maxsize == 2147483647:
self.assertEquals(-2147483647-1, -0o20000000000)
self.assertEqual(m.find(slice + b'x'), -1)
m.close()
+ def test_find_end(self):
+ # test the new 'end' parameter works as expected
+ f = open(TESTFN, 'w+')
+ data = 'one two ones'
+ n = len(data)
+ f.write(data)
+ f.flush()
+ m = mmap.mmap(f.fileno(), n)
+ f.close()
+
+ self.assertEqual(m.find('one'), 0)
+ self.assertEqual(m.find('ones'), 8)
+ self.assertEqual(m.find('one', 0, -1), 0)
+ self.assertEqual(m.find('one', 1), 8)
+ self.assertEqual(m.find('one', 1, -1), 8)
+ self.assertEqual(m.find('one', 1, -2), -1)
+
+
+ def test_rfind(self):
+ # test the new 'end' parameter works as expected
+ f = open(TESTFN, 'w+')
+ data = 'one two ones'
+ n = len(data)
+ f.write(data)
+ f.flush()
+ m = mmap.mmap(f.fileno(), n)
+ f.close()
+
+ self.assertEqual(m.rfind('one'), 8)
+ self.assertEqual(m.rfind('one '), 0)
+ self.assertEqual(m.rfind('one', 0, -1), 8)
+ self.assertEqual(m.rfind('one', 0, -2), 0)
+ self.assertEqual(m.rfind('one', 1, -1), 8)
+ self.assertEqual(m.rfind('one', 1, -2), -1)
+
+
def test_double_close(self):
# make sure a double close doesn't crash on Solaris (Bug# 665913)
f = open(TESTFN, 'wb+')
def testRefCountGetNameInfo(self):
# Testing reference count for getnameinfo
- import sys
if hasattr(sys, "getrefcount"):
try:
# On some versions, this loses a reference
class BasicTests(unittest.TestCase):
+ def testSSLconnect(self):
+ if not test_support.is_resource_enabled('network'):
+ return
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_NONE)
+ s.connect(("svn.python.org", 443))
+ c = s.getpeercert()
+ if c:
+ raise test_support.TestFailed("Peer cert %s shouldn't be here!")
+ s.close()
+
+ # this should fail because we have no verification certs
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED)
+ try:
+ s.connect(("svn.python.org", 443))
+ except ssl.SSLError:
+ pass
+ finally:
+ s.close()
+
def testCrucialConstants(self):
ssl.PROTOCOL_SSLv2
ssl.PROTOCOL_SSLv23
class NetworkedTests(unittest.TestCase):
def testConnect(self):
-
s = ssl.wrap_socket(socket.socket(socket.AF_INET),
cert_reqs=ssl.CERT_NONE)
s.connect(("svn.python.org", 443))
' o'],
subsequent_indent = ' '*15)
+ # bug 1146. Prevent a long word to be wrongly wrapped when the
+ # preceding word is exactly one character shorter than the width
+ self.check_wrap(self.text, 12,
+ ['Did you say ',
+ '"supercalifr',
+ 'agilisticexp',
+ 'ialidocious?',
+ '" How *do*',
+ 'you spell',
+ 'that odd',
+ 'word,',
+ 'anyways?'])
+
def test_nobreak_long(self):
# Test with break_long_words disabled
self.wrapper.break_long_words = 0
# protocol error; provide additional information in test output
self.fail("%s\n%s" % (e, e.headers))
- def test_404(self):
+ # [ch] The test 404 is causing lots of false alarms.
+ def XXXtest_404(self):
# send POST with httplib, it should return 404 header and
# 'Not Found' message.
conn = httplib.HTTPConnection('localhost', PORT)
Handle a chunk of text (most likely a word, not whitespace) that
is too long to fit in any line.
"""
- space_left = max(width - cur_len, 1)
+ # Figure out when indent is larger than the specified width, and make
+ # sure at least one character is stripped off on every pass
+ if width < 1:
+ space_left = 1
+ else:
+ space_left = width - cur_len
# If we're allowed to break long words, then do so: put as much
# of the next chunk onto the current line as will fit.
Ignore = Whitespace + any(r'\\\r?\n' + Whitespace) + maybe(Comment)
Name = r'[a-zA-Z_]\w*'
-Hexnumber = r'0[xX][\da-fA-F]*'
-Binnumber = r'0[bB][01]*'
-Octnumber = r'0[oO][0-7]*'
+Hexnumber = r'0[xX][\da-fA-F]+'
+Binnumber = r'0[bB][01]+'
+Octnumber = r'0[oO][0-7]+'
Decnumber = r'(?:0+|[1-9]\d*)'
Intnumber = group(Hexnumber, Binnumber, Octnumber, Decnumber)
Exponent = r'[eE][-+]?\d+'
(Can only be used with --count or --report.)
Filters, may be repeated multiple times:
---ignore-module=<mod> Ignore the given module and its submodules
- (if it is a package).
+--ignore-module=<mod> Ignore the given module(s) and its submodules
+ (if it is a package). Accepts comma separated
+ list of module names
--ignore-dir=<dir> Ignore files in the given directory (multiple
directories can be joined by os.pathsep).
""" % sys.argv[0])
continue
if opt == "--ignore-module":
- ignore_modules.append(val)
+ for mod in val.split(","):
+ ignore_modules.append(mod.strip())
continue
if opt == "--ignore-dir":
Brett Cannon
Mike Carlton
Terry Carroll
-Brian Leair
-Luke Kenneth Casson Leighton
Donn Cave
Per Cederqvist
Octavian Cerna
Ben Laurie
Simon Law
Chris Lawrence
+Brian Leair
Christopher Lee
Inyeol Lee
John J. Lee
Luc Lefebvre
Kip Lehman
Joerg Lehmann
+Luke Kenneth Casson Leighton
Marc-Andre Lemburg
+John Lenton
Mark Levinson
William Lewis
Robert van Liere
François Pinard
Zach Pincus
Michael Piotrowski
+Michael Pomraning
Iustin Pop
John Popplewell
Amrit Prem
}
static PyObject *
-mmap_find_method(mmap_object *self,
- PyObject *args)
+mmap_gfind(mmap_object *self,
+ PyObject *args,
+ int reverse)
{
Py_ssize_t start = self->pos;
+ Py_ssize_t end = self->size;
char *needle;
Py_ssize_t len;
CHECK_VALID(NULL);
- if (!PyArg_ParseTuple(args, "s#|n:find", &needle, &len, &start)) {
+ if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
+ &needle, &len, &start, &end)) {
return NULL;
} else {
char *p;
- char *e = self->data + self->size;
+ char sign = reverse ? -1 : 1;
if (start < 0)
start += self->size;
else if ((size_t)start > self->size)
start = self->size;
- for (p = self->data + start; p + len <= e; ++p) {
+ if (end < 0)
+ end += self->size;
+ if (end < 0)
+ end = 0;
+ else if ((size_t)end > self->size)
+ end = self->size;
+
+ start += (Py_ssize_t)self->data;
+ end += (Py_ssize_t)self->data;
+
+ for (p = (char *)(reverse ? end - len : start);
+ p >= (char *)start && p + len <= (char *)end; p+=sign) {
Py_ssize_t i;
for (i = 0; i < len && needle[i] == p[i]; ++i)
/* nothing */;
}
}
+static PyObject *
+mmap_find_method(mmap_object *self,
+ PyObject *args)
+{
+ return mmap_gfind(self, args, 0);
+}
+
+static PyObject *
+mmap_rfind_method(mmap_object *self,
+ PyObject *args)
+{
+ return mmap_gfind(self, args, 1);
+}
+
static int
is_writable(mmap_object *self)
{
static struct PyMethodDef mmap_object_methods[] = {
{"close", (PyCFunction) mmap_close_method, METH_NOARGS},
{"find", (PyCFunction) mmap_find_method, METH_VARARGS},
+ {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
{"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
{"move", (PyCFunction) mmap_move_method, METH_VARARGS},
{"read", (PyCFunction) mmap_read_method, METH_VARARGS},
goto imaginary;
#endif
if (c == 'x' || c == 'X') {
+
/* Hex */
+ c = tok_nextc(tok);
+ if (!isxdigit(c)) {
+ tok->done = E_TOKEN;
+ tok_backup(tok, c);
+ return ERRORTOKEN;
+ }
do {
c = tok_nextc(tok);
} while (isxdigit(c));
}
else if (c == 'o' || c == 'O') {
/* Octal */
+ c = tok_nextc(tok);
+ if (c < '0' || c > '8') {
+ tok->done = E_TOKEN;
+ tok_backup(tok, c);
+ return ERRORTOKEN;
+ }
do {
c = tok_nextc(tok);
} while ('0' <= c && c < '8');
}
else if (c == 'b' || c == 'B') {
/* Binary */
+ c = tok_nextc(tok);
+ if (c != '0' && c != '1') {
+ tok->done = E_TOKEN;
+ tok_backup(tok, c);
+ return ERRORTOKEN;
+ }
do {
c = tok_nextc(tok);
} while (c == '0' || c == '1');
int
PyModule_AddIntConstant(PyObject *m, const char *name, long value)
{
- return PyModule_AddObject(m, name, PyLong_FromLong(value));
+ PyObject *o = PyLong_FromLong(value);
+ if (!o)
+ return -1;
+ if (PyModule_AddObject(m, name, o) == 0)
+ return 0;
+ Py_DECREF(o);
+ return -1;
}
int
PyModule_AddStringConstant(PyObject *m, const char *name, const char *value)
{
- return PyModule_AddObject(m, name, PyUnicode_FromString(value));
+ PyObject *o = PyUnicode_FromString(value);
+ if (!o)
+ return -1;
+ if (PyModule_AddObject(m, name, o) == 0)
+ return 0;
+ Py_DECREF(o);
+ return -1;
}
if (*str == '0') {
++str;
if (*str == 'x' || *str == 'X') {
+ /* there must be at least one digit after 0x */
+ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
++str;
base = 16;
} else if (*str == 'o' || *str == 'O') {
+ /* there must be at least one digit after 0o */
+ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
++str;
base = 8;
} else if (*str == 'b' || *str == 'B') {
+ /* there must be at least one digit after 0b */
+ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
++str;
base = 2;
} else {
case 16:
if (*str == '0') {
++str;
- if (*str == 'x' || *str == 'X')
+ if (*str == 'x' || *str == 'X') {
+ /* there must be at least one digit after 0x */
+ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
++str;
+ }
}
break;
case 8:
if (*str == '0') {
++str;
- if (*str == 'o' || *str == 'O')
+ if (*str == 'o' || *str == 'O') {
+ /* there must be at least one digit after 0o */
+ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
++str;
+ }
}
break;
case 2:
if(*str == '0') {
++str;
- if (*str == 'b' || *str == 'B')
+ if (*str == 'b' || *str == 'B') {
+ /* there must be at least one digit after 0b */
+ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
+ if (ptr)
+ *ptr = str;
+ return 0;
+ }
++str;
+ }
}
break;
}