Merged revisions 61003-61033 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r61004 | georg.brandl | 2008-02-23 19:47:04 +0100 (Sat, 23 Feb 2008) | 2 lines Documentation coverage builder, part 1. ........ r61006 | andrew.kuchling | 2008-02-23 20:02:33 +0100 (Sat, 23 Feb 2008) | 1 line #1389051: IMAP module tries to read entire message in one chunk. Patch by Fredrik Lundh. ........ r61008 | andrew.kuchling | 2008-02-23 20:28:58 +0100 (Sat, 23 Feb 2008) | 1 line #1389051, #1092502: fix excessively large allocations when using read() on a socket ........ r61011 | jeffrey.yasskin | 2008-02-23 20:40:54 +0100 (Sat, 23 Feb 2008) | 13 lines Prevent classes like: class RunSelfFunction(object): def __init__(self): self.thread = threading.Thread(target=self._run) self.thread.start() def _run(self): pass from creating a permanent cycle between the object and the thread by having the Thread delete its references to the object when it completes. As an example of the effect of this bug, paramiko.Transport inherits from Thread to avoid it. ........ r61013 | jeffrey.yasskin | 2008-02-23 21:40:35 +0100 (Sat, 23 Feb 2008) | 3 lines Followup to r61011: Also avoid the reference cycle when the Thread's target raises an exception. ........ r61017 | georg.brandl | 2008-02-23 22:59:11 +0100 (Sat, 23 Feb 2008) | 2 lines #2101: fix removeAttribute docs. ........ r61018 | georg.brandl | 2008-02-23 23:05:38 +0100 (Sat, 23 Feb 2008) | 2 lines Add examples to modulefinder docs. Written for GHOP by Josip Dzolonga. ........ r61019 | georg.brandl | 2008-02-23 23:09:24 +0100 (Sat, 23 Feb 2008) | 2 lines Use os.closerange() in popen2. ........ r61020 | georg.brandl | 2008-02-23 23:14:02 +0100 (Sat, 23 Feb 2008) | 2 lines Use os.closerange(). ........ r61021 | georg.brandl | 2008-02-23 23:35:33 +0100 (Sat, 23 Feb 2008) | 3 lines In test_heapq and test_bisect, test both the Python and the C implementation. Originally written for GHOP by Josip Dzolonga, heavily patched by me. ........ r61024 | facundo.batista | 2008-02-23 23:54:12 +0100 (Sat, 23 Feb 2008) | 3 lines Added simple test case. Thanks Benjamin Peterson. ........ r61025 | georg.brandl | 2008-02-23 23:55:18 +0100 (Sat, 23 Feb 2008) | 2 lines #1825: correctly document msilib.add_data. ........ r61027 | georg.brandl | 2008-02-24 00:02:23 +0100 (Sun, 24 Feb 2008) | 2 lines #1826: allow dotted attribute paths in operator.attrgetter. ........ r61028 | georg.brandl | 2008-02-24 00:04:35 +0100 (Sun, 24 Feb 2008) | 2 lines #1506171: added operator.methodcaller(). ........ r61029 | georg.brandl | 2008-02-24 00:25:26 +0100 (Sun, 24 Feb 2008) | 2 lines Document import ./. threading issues. #1720705. ........ r61032 | georg.brandl | 2008-02-24 00:43:01 +0100 (Sun, 24 Feb 2008) | 2 lines Specify what kind of warning -3 emits. ........ r61033 | christian.heimes | 2008-02-24 00:59:45 +0100 (Sun, 24 Feb 2008) | 1 line MS Windows doesn't have mode_t but stat.st_mode is defined as unsigned short. ........
This commit is contained in:
parent
05e8be17fd
commit
d3eb5a1581
|
@ -121,11 +121,7 @@ def spawn(prog, args):
|
|||
sys.stderr.write('popen2: bad write dup\n')
|
||||
if os.dup(c2pwrite) != 2:
|
||||
sys.stderr.write('popen2: bad write dup\n')
|
||||
for i in range(3, MAXFD):
|
||||
try:
|
||||
os.close(i)
|
||||
except:
|
||||
pass
|
||||
os.closerange(3, MAXFD)
|
||||
try:
|
||||
os.execvp(prog, args)
|
||||
finally:
|
||||
|
|
|
@ -12,7 +12,7 @@ PAPER =
|
|||
ALLSPHINXOPTS = -b $(BUILDER) -d build/doctrees -D latex_paper_size=$(PAPER) \
|
||||
$(SPHINXOPTS) . build/$(BUILDER)
|
||||
|
||||
.PHONY: help checkout update build html web htmlhelp clean
|
||||
.PHONY: help checkout update build html web htmlhelp clean coverage
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
|
@ -22,6 +22,7 @@ help:
|
|||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " changes to make an overview over all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " coverage to check documentation coverage for library and C API"
|
||||
|
||||
checkout:
|
||||
@if [ ! -d tools/sphinx ]; then \
|
||||
|
@ -74,9 +75,13 @@ changes: build
|
|||
|
||||
linkcheck: BUILDER = linkcheck
|
||||
linkcheck: build
|
||||
@echo "Link check complete; look for any errors in the above output "\
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in build/$(BUILDER)/output.txt"
|
||||
|
||||
coverage: BUILDER = coverage
|
||||
coverage: build
|
||||
@echo "Coverage finished; see c.txt and python.txt in build/coverage"
|
||||
|
||||
clean:
|
||||
-rm -rf build/*
|
||||
-rm -rf tools/sphinx
|
||||
|
|
|
@ -64,6 +64,9 @@ Available make targets are:
|
|||
deprecated items in the current version. This is meant as a help for the
|
||||
writer of the "What's New" document.
|
||||
|
||||
* "coverage", which builds a coverage overview for standard library modules
|
||||
and C API.
|
||||
|
||||
A "make update" updates the Subversion checkouts in `tools/`.
|
||||
|
||||
|
||||
|
|
38
Doc/conf.py
38
Doc/conf.py
|
@ -13,7 +13,7 @@ sys.path.append('tools/sphinxext')
|
|||
# General configuration
|
||||
# ---------------------
|
||||
|
||||
extensions = ['sphinx.addons.refcounting']
|
||||
extensions = ['sphinx.addons.refcounting', 'sphinx.addons.coverage']
|
||||
|
||||
# General substitutions.
|
||||
project = 'Python'
|
||||
|
@ -140,3 +140,39 @@ latex_preamble = r'''
|
|||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
latex_appendices = ['glossary', 'about', 'license', 'copyright']
|
||||
|
||||
# Options for the coverage checker
|
||||
# --------------------------------
|
||||
|
||||
# The coverage checker will ignore all modules/functions/classes whose names
|
||||
# match any of the following regexes (using re.match).
|
||||
coverage_ignore_modules = [
|
||||
r'[T|t][k|K]',
|
||||
r'Tix',
|
||||
r'distutils.*',
|
||||
]
|
||||
|
||||
coverage_ignore_functions = [
|
||||
'test($|_)',
|
||||
]
|
||||
|
||||
coverage_ignore_classes = [
|
||||
]
|
||||
|
||||
# Glob patterns for C source files for C API coverage, relative to this directory.
|
||||
coverage_c_path = [
|
||||
'../Include/*.h',
|
||||
]
|
||||
|
||||
# Regexes to find C items in the source files.
|
||||
coverage_c_regexes = {
|
||||
'cfunction': (r'^PyAPI_FUNC\(.*\)\s+([^_][\w_]+)'),
|
||||
'data': (r'^PyAPI_DATA\(.*\)\s+([^_][\w_]+)'),
|
||||
'macro': (r'^#define ([^_][\w_]+)\(.*\)[\s|\\]'),
|
||||
}
|
||||
|
||||
# The coverage checker will ignore all C items whose names match these regexes
|
||||
# (using re.match) -- the keys must be the same as in coverage_c_regexes.
|
||||
coverage_ignore_c_items = {
|
||||
# 'cfunction': [...]
|
||||
}
|
||||
|
|
|
@ -48,3 +48,65 @@ report of the imported modules will be printed.
|
|||
|
||||
Analyze the contents of the *pathname* file, which must contain Python code.
|
||||
|
||||
.. attribute:: ModuleFinder.modules
|
||||
|
||||
A dictionary mapping module names to modules. See :ref:`modulefinder-example`
|
||||
|
||||
|
||||
.. _modulefinder-example:
|
||||
|
||||
Example usage of :class:`ModuleFinder`
|
||||
--------------------------------------
|
||||
|
||||
The script that is going to get analyzed later on (bacon.py)::
|
||||
|
||||
import re, itertools
|
||||
|
||||
try:
|
||||
import baconhameggs
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import guido.python.ham
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
The script that will output the report of bacon.py::
|
||||
|
||||
from modulefinder import ModuleFinder
|
||||
|
||||
finder = ModuleFinder()
|
||||
finder.run_script('bacon.py')
|
||||
|
||||
print 'Loaded modules:'
|
||||
for name, mod in finder.modules.iteritems():
|
||||
print '%s: ' % name,
|
||||
print ','.join(mod.globalnames.keys()[:3])
|
||||
|
||||
print '-'*50
|
||||
print 'Modules not imported:'
|
||||
print '\n'.join(finder.badmodules.iterkeys())
|
||||
|
||||
Sample output (may vary depending on the architecture)::
|
||||
|
||||
Loaded modules:
|
||||
_types:
|
||||
copy_reg: _inverted_registry,_slotnames,__all__
|
||||
sre_compile: isstring,_sre,_optimize_unicode
|
||||
_sre:
|
||||
sre_constants: REPEAT_ONE,makedict,AT_END_LINE
|
||||
sys:
|
||||
re: __module__,finditer,_expand
|
||||
itertools:
|
||||
__main__: re,itertools,baconhameggs
|
||||
sre_parse: __getslice__,_PATTERNENDERS,SRE_FLAG_UNICODE
|
||||
array:
|
||||
types: __module__,IntType,TypeType
|
||||
---------------------------------------------------
|
||||
Modules not imported:
|
||||
guido.python.ham
|
||||
baconhameggs
|
||||
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ structures.
|
|||
|
||||
.. function:: init_database(name, schema, ProductName, ProductCode, ProductVersion, Manufacturer)
|
||||
|
||||
Create and return a new database *name*, initialize it with *schema*, and set
|
||||
Create and return a new database *name*, initialize it with *schema*, and set
|
||||
the properties *ProductName*, *ProductCode*, *ProductVersion*, and
|
||||
*Manufacturer*.
|
||||
|
||||
|
@ -77,13 +77,20 @@ structures.
|
|||
function returns.
|
||||
|
||||
|
||||
.. function:: add_data(database, records)
|
||||
.. function:: add_data(database, table, records)
|
||||
|
||||
Add all *records* to *database*. *records* should be a list of tuples, each one
|
||||
containing all fields of a record according to the schema of the table. For
|
||||
optional fields, ``None`` can be passed.
|
||||
Add all *records* to the table named *table* in *database*.
|
||||
|
||||
Field values can be integers, strings, or instances of the Binary class.
|
||||
The *table* argument must be one of the predefined tables in the MSI schema,
|
||||
e.g. ``'Feature'``, ``'File'``, ``'Component'``, ``'Dialog'``, ``'Control'``,
|
||||
etc.
|
||||
|
||||
*records* should be a list of tuples, each one containing all fields of a
|
||||
record according to the schema of the table. For optional fields,
|
||||
``None`` can be passed.
|
||||
|
||||
Field values can be int or long numbers, strings, or instances of the Binary
|
||||
class.
|
||||
|
||||
|
||||
.. class:: Binary(filename)
|
||||
|
|
|
@ -419,10 +419,12 @@ expect a function argument.
|
|||
|
||||
Return a callable object that fetches *attr* from its operand. If more than one
|
||||
attribute is requested, returns a tuple of attributes. After,
|
||||
``f=attrgetter('name')``, the call ``f(b)`` returns ``b.name``. After,
|
||||
``f=attrgetter('name', 'date')``, the call ``f(b)`` returns ``(b.name,
|
||||
``f = attrgetter('name')``, the call ``f(b)`` returns ``b.name``. After,
|
||||
``f = attrgetter('name', 'date')``, the call ``f(b)`` returns ``(b.name,
|
||||
b.date)``.
|
||||
|
||||
The attribute names can also contain dots; after ``f = attrgetter('date.month')``,
|
||||
the call ``f(b)`` returns ``b.date.month``.
|
||||
|
||||
.. function:: itemgetter(item[, args...])
|
||||
|
||||
|
@ -443,6 +445,15 @@ Examples::
|
|||
[('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)]
|
||||
|
||||
|
||||
.. function:: methodcaller(name[, args...])
|
||||
|
||||
Return a callable object that calls the method *name* on its operand. If
|
||||
additional arguments and/or keyword arguments are given, they will be given
|
||||
to the method as well. After ``f = methodcaller('name')``, the call ``f(b)``
|
||||
returns ``b.name()``. After ``f = methodcaller('name', 'foo', bar=1)``, the
|
||||
call ``f(b)`` returns ``b.name('foo', bar=1)``.
|
||||
|
||||
|
||||
.. _operator-map:
|
||||
|
||||
Mapping Operators to Functions
|
||||
|
|
|
@ -147,6 +147,11 @@ In addition to these methods, lock objects can also be used via the
|
|||
exception will be received by an arbitrary thread. (When the :mod:`signal`
|
||||
module is available, interrupts always go to the main thread.)
|
||||
|
||||
* The import machinery is not thread safe. In general, an import may not
|
||||
have the side effect of importing a module, and only the main thread
|
||||
should import modules. Imports within or caused by a thread other than
|
||||
the main thread isn't safe.
|
||||
|
||||
* Calling :func:`sys.exit` or raising the :exc:`SystemExit` exception is
|
||||
equivalent to calling :func:`exit`.
|
||||
|
||||
|
@ -167,4 +172,3 @@ In addition to these methods, lock objects can also be used via the
|
|||
* When the main thread exits, it does not do any of its usual cleanup (except
|
||||
that :keyword:`try` ... :keyword:`finally` clauses are honored), and the
|
||||
standard I/O files are not flushed.
|
||||
|
||||
|
|
|
@ -555,6 +555,13 @@ the :meth:`setDaemon` method and retrieved with the :meth:`isDaemon` method.
|
|||
There is a "main thread" object; this corresponds to the initial thread of
|
||||
control in the Python program. It is not a daemon thread.
|
||||
|
||||
.. warning::
|
||||
|
||||
The import machinery is not thread safe. In general, an import may not
|
||||
have the side effect of importing a module, and only the main thread
|
||||
should import modules. Imports within or caused by a thread other than
|
||||
the main thread isn't safe.
|
||||
|
||||
There is the possibility that "dummy thread objects" are created. These are
|
||||
thread objects corresponding to "alien threads", which are threads of control
|
||||
started outside the threading module, such as directly from C code. Dummy
|
||||
|
|
|
@ -641,8 +641,8 @@ of that class.
|
|||
|
||||
.. method:: Element.removeAttribute(name)
|
||||
|
||||
Remove an attribute by name. No exception is raised if there is no matching
|
||||
attribute.
|
||||
Remove an attribute by name. If there is no matching attribute, a
|
||||
:exc:`NotFoundErr` is raised.
|
||||
|
||||
|
||||
.. method:: Element.removeAttributeNode(oldAttr)
|
||||
|
|
|
@ -1151,6 +1151,52 @@ else:
|
|||
self.file = self.sock.makefile('rb')
|
||||
|
||||
|
||||
def read(self, size):
|
||||
"""Read 'size' bytes from remote."""
|
||||
# sslobj.read() sometimes returns < size bytes
|
||||
chunks = []
|
||||
read = 0
|
||||
while read < size:
|
||||
data = self.sslobj.read(min(size-read, 16384))
|
||||
read += len(data)
|
||||
chunks.append(data)
|
||||
|
||||
return b''.join(chunks)
|
||||
|
||||
|
||||
def readline(self):
|
||||
"""Read line from remote."""
|
||||
line = []
|
||||
while 1:
|
||||
char = self.sslobj.read(1)
|
||||
line.append(char)
|
||||
if char == b"\n": return b''.join(line)
|
||||
|
||||
|
||||
def send(self, data):
|
||||
"""Send data to remote."""
|
||||
bytes = len(data)
|
||||
while bytes > 0:
|
||||
sent = self.sslobj.write(data)
|
||||
if sent == bytes:
|
||||
break # avoid copy
|
||||
data = data[sent:]
|
||||
bytes = bytes - sent
|
||||
|
||||
|
||||
def shutdown(self):
|
||||
"""Close I/O established in "open"."""
|
||||
self.sock.close()
|
||||
|
||||
|
||||
def socket(self):
|
||||
"""Return socket instance used to connect to IMAP4 server.
|
||||
|
||||
socket = <instance>.socket()
|
||||
"""
|
||||
return self.sock
|
||||
|
||||
|
||||
def ssl(self):
|
||||
"""Return SSLObject instance used to communicate with the IMAP4 server.
|
||||
|
||||
|
|
|
@ -1,91 +1,113 @@
|
|||
import sys
|
||||
import unittest
|
||||
from test import test_support
|
||||
from bisect import bisect_right, bisect_left, insort_left, insort_right, insort, bisect
|
||||
from collections import UserList
|
||||
|
||||
# We do a bit of trickery here to be able to test both the C implementation
|
||||
# and the Python implementation of the module.
|
||||
|
||||
# Make it impossible to import the C implementation anymore.
|
||||
sys.modules['_bisect'] = 0
|
||||
# We must also handle the case that bisect was imported before.
|
||||
if 'bisect' in sys.modules:
|
||||
del sys.modules['bisect']
|
||||
|
||||
# Now we can import the module and get the pure Python implementation.
|
||||
import bisect as py_bisect
|
||||
|
||||
# Restore everything to normal.
|
||||
del sys.modules['_bisect']
|
||||
del sys.modules['bisect']
|
||||
|
||||
# This is now the module with the C implementation.
|
||||
import bisect as c_bisect
|
||||
|
||||
|
||||
class TestBisect(unittest.TestCase):
|
||||
module = None
|
||||
|
||||
precomputedCases = [
|
||||
(bisect_right, [], 1, 0),
|
||||
(bisect_right, [1], 0, 0),
|
||||
(bisect_right, [1], 1, 1),
|
||||
(bisect_right, [1], 2, 1),
|
||||
(bisect_right, [1, 1], 0, 0),
|
||||
(bisect_right, [1, 1], 1, 2),
|
||||
(bisect_right, [1, 1], 2, 2),
|
||||
(bisect_right, [1, 1, 1], 0, 0),
|
||||
(bisect_right, [1, 1, 1], 1, 3),
|
||||
(bisect_right, [1, 1, 1], 2, 3),
|
||||
(bisect_right, [1, 1, 1, 1], 0, 0),
|
||||
(bisect_right, [1, 1, 1, 1], 1, 4),
|
||||
(bisect_right, [1, 1, 1, 1], 2, 4),
|
||||
(bisect_right, [1, 2], 0, 0),
|
||||
(bisect_right, [1, 2], 1, 1),
|
||||
(bisect_right, [1, 2], 1.5, 1),
|
||||
(bisect_right, [1, 2], 2, 2),
|
||||
(bisect_right, [1, 2], 3, 2),
|
||||
(bisect_right, [1, 1, 2, 2], 0, 0),
|
||||
(bisect_right, [1, 1, 2, 2], 1, 2),
|
||||
(bisect_right, [1, 1, 2, 2], 1.5, 2),
|
||||
(bisect_right, [1, 1, 2, 2], 2, 4),
|
||||
(bisect_right, [1, 1, 2, 2], 3, 4),
|
||||
(bisect_right, [1, 2, 3], 0, 0),
|
||||
(bisect_right, [1, 2, 3], 1, 1),
|
||||
(bisect_right, [1, 2, 3], 1.5, 1),
|
||||
(bisect_right, [1, 2, 3], 2, 2),
|
||||
(bisect_right, [1, 2, 3], 2.5, 2),
|
||||
(bisect_right, [1, 2, 3], 3, 3),
|
||||
(bisect_right, [1, 2, 3], 4, 3),
|
||||
(bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 0, 0),
|
||||
(bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1, 1),
|
||||
(bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1.5, 1),
|
||||
(bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2, 3),
|
||||
(bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2.5, 3),
|
||||
(bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3, 6),
|
||||
(bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3.5, 6),
|
||||
(bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 4, 10),
|
||||
(bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 5, 10),
|
||||
def setUp(self):
|
||||
self.precomputedCases = [
|
||||
(self.module.bisect_right, [], 1, 0),
|
||||
(self.module.bisect_right, [1], 0, 0),
|
||||
(self.module.bisect_right, [1], 1, 1),
|
||||
(self.module.bisect_right, [1], 2, 1),
|
||||
(self.module.bisect_right, [1, 1], 0, 0),
|
||||
(self.module.bisect_right, [1, 1], 1, 2),
|
||||
(self.module.bisect_right, [1, 1], 2, 2),
|
||||
(self.module.bisect_right, [1, 1, 1], 0, 0),
|
||||
(self.module.bisect_right, [1, 1, 1], 1, 3),
|
||||
(self.module.bisect_right, [1, 1, 1], 2, 3),
|
||||
(self.module.bisect_right, [1, 1, 1, 1], 0, 0),
|
||||
(self.module.bisect_right, [1, 1, 1, 1], 1, 4),
|
||||
(self.module.bisect_right, [1, 1, 1, 1], 2, 4),
|
||||
(self.module.bisect_right, [1, 2], 0, 0),
|
||||
(self.module.bisect_right, [1, 2], 1, 1),
|
||||
(self.module.bisect_right, [1, 2], 1.5, 1),
|
||||
(self.module.bisect_right, [1, 2], 2, 2),
|
||||
(self.module.bisect_right, [1, 2], 3, 2),
|
||||
(self.module.bisect_right, [1, 1, 2, 2], 0, 0),
|
||||
(self.module.bisect_right, [1, 1, 2, 2], 1, 2),
|
||||
(self.module.bisect_right, [1, 1, 2, 2], 1.5, 2),
|
||||
(self.module.bisect_right, [1, 1, 2, 2], 2, 4),
|
||||
(self.module.bisect_right, [1, 1, 2, 2], 3, 4),
|
||||
(self.module.bisect_right, [1, 2, 3], 0, 0),
|
||||
(self.module.bisect_right, [1, 2, 3], 1, 1),
|
||||
(self.module.bisect_right, [1, 2, 3], 1.5, 1),
|
||||
(self.module.bisect_right, [1, 2, 3], 2, 2),
|
||||
(self.module.bisect_right, [1, 2, 3], 2.5, 2),
|
||||
(self.module.bisect_right, [1, 2, 3], 3, 3),
|
||||
(self.module.bisect_right, [1, 2, 3], 4, 3),
|
||||
(self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 0, 0),
|
||||
(self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1, 1),
|
||||
(self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1.5, 1),
|
||||
(self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2, 3),
|
||||
(self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2.5, 3),
|
||||
(self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3, 6),
|
||||
(self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3.5, 6),
|
||||
(self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 4, 10),
|
||||
(self.module.bisect_right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 5, 10),
|
||||
|
||||
(bisect_left, [], 1, 0),
|
||||
(bisect_left, [1], 0, 0),
|
||||
(bisect_left, [1], 1, 0),
|
||||
(bisect_left, [1], 2, 1),
|
||||
(bisect_left, [1, 1], 0, 0),
|
||||
(bisect_left, [1, 1], 1, 0),
|
||||
(bisect_left, [1, 1], 2, 2),
|
||||
(bisect_left, [1, 1, 1], 0, 0),
|
||||
(bisect_left, [1, 1, 1], 1, 0),
|
||||
(bisect_left, [1, 1, 1], 2, 3),
|
||||
(bisect_left, [1, 1, 1, 1], 0, 0),
|
||||
(bisect_left, [1, 1, 1, 1], 1, 0),
|
||||
(bisect_left, [1, 1, 1, 1], 2, 4),
|
||||
(bisect_left, [1, 2], 0, 0),
|
||||
(bisect_left, [1, 2], 1, 0),
|
||||
(bisect_left, [1, 2], 1.5, 1),
|
||||
(bisect_left, [1, 2], 2, 1),
|
||||
(bisect_left, [1, 2], 3, 2),
|
||||
(bisect_left, [1, 1, 2, 2], 0, 0),
|
||||
(bisect_left, [1, 1, 2, 2], 1, 0),
|
||||
(bisect_left, [1, 1, 2, 2], 1.5, 2),
|
||||
(bisect_left, [1, 1, 2, 2], 2, 2),
|
||||
(bisect_left, [1, 1, 2, 2], 3, 4),
|
||||
(bisect_left, [1, 2, 3], 0, 0),
|
||||
(bisect_left, [1, 2, 3], 1, 0),
|
||||
(bisect_left, [1, 2, 3], 1.5, 1),
|
||||
(bisect_left, [1, 2, 3], 2, 1),
|
||||
(bisect_left, [1, 2, 3], 2.5, 2),
|
||||
(bisect_left, [1, 2, 3], 3, 2),
|
||||
(bisect_left, [1, 2, 3], 4, 3),
|
||||
(bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 0, 0),
|
||||
(bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1, 0),
|
||||
(bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1.5, 1),
|
||||
(bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2, 1),
|
||||
(bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2.5, 3),
|
||||
(bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3, 3),
|
||||
(bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3.5, 6),
|
||||
(bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 4, 6),
|
||||
(bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 5, 10)
|
||||
]
|
||||
(self.module.bisect_left, [], 1, 0),
|
||||
(self.module.bisect_left, [1], 0, 0),
|
||||
(self.module.bisect_left, [1], 1, 0),
|
||||
(self.module.bisect_left, [1], 2, 1),
|
||||
(self.module.bisect_left, [1, 1], 0, 0),
|
||||
(self.module.bisect_left, [1, 1], 1, 0),
|
||||
(self.module.bisect_left, [1, 1], 2, 2),
|
||||
(self.module.bisect_left, [1, 1, 1], 0, 0),
|
||||
(self.module.bisect_left, [1, 1, 1], 1, 0),
|
||||
(self.module.bisect_left, [1, 1, 1], 2, 3),
|
||||
(self.module.bisect_left, [1, 1, 1, 1], 0, 0),
|
||||
(self.module.bisect_left, [1, 1, 1, 1], 1, 0),
|
||||
(self.module.bisect_left, [1, 1, 1, 1], 2, 4),
|
||||
(self.module.bisect_left, [1, 2], 0, 0),
|
||||
(self.module.bisect_left, [1, 2], 1, 0),
|
||||
(self.module.bisect_left, [1, 2], 1.5, 1),
|
||||
(self.module.bisect_left, [1, 2], 2, 1),
|
||||
(self.module.bisect_left, [1, 2], 3, 2),
|
||||
(self.module.bisect_left, [1, 1, 2, 2], 0, 0),
|
||||
(self.module.bisect_left, [1, 1, 2, 2], 1, 0),
|
||||
(self.module.bisect_left, [1, 1, 2, 2], 1.5, 2),
|
||||
(self.module.bisect_left, [1, 1, 2, 2], 2, 2),
|
||||
(self.module.bisect_left, [1, 1, 2, 2], 3, 4),
|
||||
(self.module.bisect_left, [1, 2, 3], 0, 0),
|
||||
(self.module.bisect_left, [1, 2, 3], 1, 0),
|
||||
(self.module.bisect_left, [1, 2, 3], 1.5, 1),
|
||||
(self.module.bisect_left, [1, 2, 3], 2, 1),
|
||||
(self.module.bisect_left, [1, 2, 3], 2.5, 2),
|
||||
(self.module.bisect_left, [1, 2, 3], 3, 2),
|
||||
(self.module.bisect_left, [1, 2, 3], 4, 3),
|
||||
(self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 0, 0),
|
||||
(self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1, 0),
|
||||
(self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1.5, 1),
|
||||
(self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2, 1),
|
||||
(self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2.5, 3),
|
||||
(self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3, 3),
|
||||
(self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3.5, 6),
|
||||
(self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 4, 6),
|
||||
(self.module.bisect_left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 5, 10)
|
||||
]
|
||||
|
||||
def test_precomputed(self):
|
||||
for func, data, elem, expected in self.precomputedCases:
|
||||
|
@ -98,12 +120,12 @@ class TestBisect(unittest.TestCase):
|
|||
data = [randrange(0, n, 2) for j in range(i)]
|
||||
data.sort()
|
||||
elem = randrange(-1, n+1)
|
||||
ip = bisect_left(data, elem)
|
||||
ip = self.module.bisect_left(data, elem)
|
||||
if ip < len(data):
|
||||
self.failUnless(elem <= data[ip])
|
||||
if ip > 0:
|
||||
self.failUnless(data[ip-1] < elem)
|
||||
ip = bisect_right(data, elem)
|
||||
ip = self.module.bisect_right(data, elem)
|
||||
if ip < len(data):
|
||||
self.failUnless(elem < data[ip])
|
||||
if ip > 0:
|
||||
|
@ -117,32 +139,39 @@ class TestBisect(unittest.TestCase):
|
|||
hi = min(len(data), hi)
|
||||
ip = func(data, elem, lo, hi)
|
||||
self.failUnless(lo <= ip <= hi)
|
||||
if func is bisect_left and ip < hi:
|
||||
if func is self.module.bisect_left and ip < hi:
|
||||
self.failUnless(elem <= data[ip])
|
||||
if func is bisect_left and ip > lo:
|
||||
if func is self.module.bisect_left and ip > lo:
|
||||
self.failUnless(data[ip-1] < elem)
|
||||
if func is bisect_right and ip < hi:
|
||||
if func is self.module.bisect_right and ip < hi:
|
||||
self.failUnless(elem < data[ip])
|
||||
if func is bisect_right and ip > lo:
|
||||
if func is self.module.bisect_right and ip > lo:
|
||||
self.failUnless(data[ip-1] <= elem)
|
||||
self.assertEqual(ip, max(lo, min(hi, expected)))
|
||||
|
||||
def test_backcompatibility(self):
|
||||
self.assertEqual(bisect, bisect_right)
|
||||
self.assertEqual(self.module.bisect, self.module.bisect_right)
|
||||
|
||||
def test_keyword_args(self):
|
||||
data = [10, 20, 30, 40, 50]
|
||||
self.assertEqual(bisect_left(a=data, x=25, lo=1, hi=3), 2)
|
||||
self.assertEqual(bisect_right(a=data, x=25, lo=1, hi=3), 2)
|
||||
self.assertEqual(bisect(a=data, x=25, lo=1, hi=3), 2)
|
||||
insort_left(a=data, x=25, lo=1, hi=3)
|
||||
insort_right(a=data, x=25, lo=1, hi=3)
|
||||
insort(a=data, x=25, lo=1, hi=3)
|
||||
self.assertEqual(self.module.bisect_left(a=data, x=25, lo=1, hi=3), 2)
|
||||
self.assertEqual(self.module.bisect_right(a=data, x=25, lo=1, hi=3), 2)
|
||||
self.assertEqual(self.module.bisect(a=data, x=25, lo=1, hi=3), 2)
|
||||
self.module.insort_left(a=data, x=25, lo=1, hi=3)
|
||||
self.module.insort_right(a=data, x=25, lo=1, hi=3)
|
||||
self.module.insort(a=data, x=25, lo=1, hi=3)
|
||||
self.assertEqual(data, [10, 20, 25, 25, 25, 30, 40, 50])
|
||||
|
||||
class TestBisectPython(TestBisect):
|
||||
module = py_bisect
|
||||
|
||||
class TestBisectC(TestBisect):
|
||||
module = c_bisect
|
||||
|
||||
#==============================================================================
|
||||
|
||||
class TestInsort(unittest.TestCase):
|
||||
module = None
|
||||
|
||||
def test_vsBuiltinSort(self, n=500):
|
||||
from random import choice
|
||||
|
@ -150,14 +179,20 @@ class TestInsort(unittest.TestCase):
|
|||
for i in range(n):
|
||||
digit = choice("0123456789")
|
||||
if digit in "02468":
|
||||
f = insort_left
|
||||
f = self.module.insort_left
|
||||
else:
|
||||
f = insort_right
|
||||
f = self.module.insort_right
|
||||
f(insorted, digit)
|
||||
self.assertEqual(sorted(insorted), insorted)
|
||||
|
||||
def test_backcompatibility(self):
|
||||
self.assertEqual(insort, insort_right)
|
||||
self.assertEqual(self.module.insort, self.module.insort_right)
|
||||
|
||||
class TestInsortPython(TestInsort):
|
||||
module = py_bisect
|
||||
|
||||
class TestInsortC(TestInsort):
|
||||
module = c_bisect
|
||||
|
||||
#==============================================================================
|
||||
|
||||
|
@ -183,32 +218,44 @@ class CmpErr:
|
|||
__ne__ = __lt__
|
||||
|
||||
class TestErrorHandling(unittest.TestCase):
|
||||
module = None
|
||||
|
||||
def test_non_sequence(self):
|
||||
for f in (bisect_left, bisect_right, insort_left, insort_right):
|
||||
for f in (self.module.bisect_left, self.module.bisect_right,
|
||||
self.module.insort_left, self.module.insort_right):
|
||||
self.assertRaises(TypeError, f, 10, 10)
|
||||
|
||||
def test_len_only(self):
|
||||
for f in (bisect_left, bisect_right, insort_left, insort_right):
|
||||
for f in (self.module.bisect_left, self.module.bisect_right,
|
||||
self.module.insort_left, self.module.insort_right):
|
||||
self.assertRaises(TypeError, f, LenOnly(), 10)
|
||||
|
||||
def test_get_only(self):
|
||||
for f in (bisect_left, bisect_right, insort_left, insort_right):
|
||||
for f in (self.module.bisect_left, self.module.bisect_right,
|
||||
self.module.insort_left, self.module.insort_right):
|
||||
self.assertRaises(TypeError, f, GetOnly(), 10)
|
||||
|
||||
def test_cmp_err(self):
|
||||
seq = [CmpErr(), CmpErr(), CmpErr()]
|
||||
for f in (bisect_left, bisect_right, insort_left, insort_right):
|
||||
for f in (self.module.bisect_left, self.module.bisect_right,
|
||||
self.module.insort_left, self.module.insort_right):
|
||||
self.assertRaises(ZeroDivisionError, f, seq, 10)
|
||||
|
||||
def test_arg_parsing(self):
|
||||
for f in (bisect_left, bisect_right, insort_left, insort_right):
|
||||
for f in (self.module.bisect_left, self.module.bisect_right,
|
||||
self.module.insort_left, self.module.insort_right):
|
||||
self.assertRaises(TypeError, f, 10)
|
||||
|
||||
class TestErrorHandlingPython(TestErrorHandling):
|
||||
module = py_bisect
|
||||
|
||||
class TestErrorHandlingC(TestErrorHandling):
|
||||
module = c_bisect
|
||||
|
||||
#==============================================================================
|
||||
|
||||
libreftest = """
|
||||
Example from the Library Reference: Doc/lib/libbisect.tex
|
||||
Example from the Library Reference: Doc/library/bisect.rst
|
||||
|
||||
The bisect() function is generally useful for categorizing numeric data.
|
||||
This example uses bisect() to look up a letter grade for an exam total
|
||||
|
@ -234,12 +281,10 @@ __test__ = {'libreftest' : libreftest}
|
|||
|
||||
def test_main(verbose=None):
|
||||
from test import test_bisect
|
||||
from types import BuiltinFunctionType
|
||||
import sys
|
||||
|
||||
test_classes = [TestBisect, TestInsort]
|
||||
if isinstance(bisect_left, BuiltinFunctionType):
|
||||
test_classes.append(TestErrorHandling)
|
||||
test_classes = [TestBisectPython, TestBisectC,
|
||||
TestInsortPython, TestInsortC,
|
||||
TestErrorHandlingPython, TestErrorHandlingC]
|
||||
|
||||
test_support.run_unittest(*test_classes)
|
||||
test_support.run_doctest(test_bisect, verbose)
|
||||
|
|
|
@ -1,21 +1,32 @@
|
|||
"""Unittests for heapq."""
|
||||
|
||||
from heapq import heappush, heappop, heapify, heapreplace, merge, nlargest, nsmallest
|
||||
import random
|
||||
import unittest
|
||||
from test import test_support
|
||||
import sys
|
||||
|
||||
# We do a bit of trickery here to be able to test both the C implementation
|
||||
# and the Python implementation of the module.
|
||||
|
||||
# Make it impossible to import the C implementation anymore.
|
||||
sys.modules['_heapq'] = 0
|
||||
# We must also handle the case that heapq was imported before.
|
||||
if 'heapq' in sys.modules:
|
||||
del sys.modules['heapq']
|
||||
|
||||
# Now we can import the module and get the pure Python implementation.
|
||||
import heapq as py_heapq
|
||||
|
||||
# Restore everything to normal.
|
||||
del sys.modules['_heapq']
|
||||
del sys.modules['heapq']
|
||||
|
||||
# This is now the module with the C implementation.
|
||||
import heapq as c_heapq
|
||||
|
||||
def heapiter(heap):
|
||||
# An iterator returning a heap's elements, smallest-first.
|
||||
try:
|
||||
while 1:
|
||||
yield heappop(heap)
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
class TestHeap(unittest.TestCase):
|
||||
module = None
|
||||
|
||||
def test_push_pop(self):
|
||||
# 1) Push 256 random numbers and pop them off, verifying all's OK.
|
||||
|
@ -25,11 +36,11 @@ class TestHeap(unittest.TestCase):
|
|||
for i in range(256):
|
||||
item = random.random()
|
||||
data.append(item)
|
||||
heappush(heap, item)
|
||||
self.module.heappush(heap, item)
|
||||
self.check_invariant(heap)
|
||||
results = []
|
||||
while heap:
|
||||
item = heappop(heap)
|
||||
item = self.module.heappop(heap)
|
||||
self.check_invariant(heap)
|
||||
results.append(item)
|
||||
data_sorted = data[:]
|
||||
|
@ -38,10 +49,10 @@ class TestHeap(unittest.TestCase):
|
|||
# 2) Check that the invariant holds for a sorted array
|
||||
self.check_invariant(results)
|
||||
|
||||
self.assertRaises(TypeError, heappush, [])
|
||||
self.assertRaises(TypeError, self.module.heappush, [])
|
||||
try:
|
||||
self.assertRaises(TypeError, heappush, None, None)
|
||||
self.assertRaises(TypeError, heappop, None)
|
||||
self.assertRaises(TypeError, self.module.heappush, None, None)
|
||||
self.assertRaises(TypeError, self.module.heappop, None)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
@ -55,21 +66,29 @@ class TestHeap(unittest.TestCase):
|
|||
def test_heapify(self):
|
||||
for size in range(30):
|
||||
heap = [random.random() for dummy in range(size)]
|
||||
heapify(heap)
|
||||
self.module.heapify(heap)
|
||||
self.check_invariant(heap)
|
||||
|
||||
self.assertRaises(TypeError, heapify, None)
|
||||
self.assertRaises(TypeError, self.module.heapify, None)
|
||||
|
||||
def test_naive_nbest(self):
|
||||
data = [random.randrange(2000) for i in range(1000)]
|
||||
heap = []
|
||||
for item in data:
|
||||
heappush(heap, item)
|
||||
self.module.heappush(heap, item)
|
||||
if len(heap) > 10:
|
||||
heappop(heap)
|
||||
self.module.heappop(heap)
|
||||
heap.sort()
|
||||
self.assertEqual(heap, sorted(data)[-10:])
|
||||
|
||||
def heapiter(self, heap):
|
||||
# An iterator returning a heap's elements, smallest-first.
|
||||
try:
|
||||
while 1:
|
||||
yield self.module.heappop(heap)
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
def test_nbest(self):
|
||||
# Less-naive "N-best" algorithm, much faster (if len(data) is big
|
||||
# enough <wink>) than sorting all of data. However, if we had a max
|
||||
|
@ -78,15 +97,15 @@ class TestHeap(unittest.TestCase):
|
|||
# (10 log-time steps).
|
||||
data = [random.randrange(2000) for i in range(1000)]
|
||||
heap = data[:10]
|
||||
heapify(heap)
|
||||
self.module.heapify(heap)
|
||||
for item in data[10:]:
|
||||
if item > heap[0]: # this gets rarer the longer we run
|
||||
heapreplace(heap, item)
|
||||
self.assertEqual(list(heapiter(heap)), sorted(data)[-10:])
|
||||
self.module.heapreplace(heap, item)
|
||||
self.assertEqual(list(self.heapiter(heap)), sorted(data)[-10:])
|
||||
|
||||
self.assertRaises(TypeError, heapreplace, None)
|
||||
self.assertRaises(TypeError, heapreplace, None, None)
|
||||
self.assertRaises(IndexError, heapreplace, [], None)
|
||||
self.assertRaises(TypeError, self.module.heapreplace, None)
|
||||
self.assertRaises(TypeError, self.module.heapreplace, None, None)
|
||||
self.assertRaises(IndexError, self.module.heapreplace, [], None)
|
||||
|
||||
def test_heapsort(self):
|
||||
# Exercise everything with repeated heapsort checks
|
||||
|
@ -95,12 +114,12 @@ class TestHeap(unittest.TestCase):
|
|||
data = [random.randrange(25) for i in range(size)]
|
||||
if trial & 1: # Half of the time, use heapify
|
||||
heap = data[:]
|
||||
heapify(heap)
|
||||
self.module.heapify(heap)
|
||||
else: # The rest of the time, use heappush
|
||||
heap = []
|
||||
for item in data:
|
||||
heappush(heap, item)
|
||||
heap_sorted = [heappop(heap) for i in range(size)]
|
||||
self.module.heappush(heap, item)
|
||||
heap_sorted = [self.module.heappop(heap) for i in range(size)]
|
||||
self.assertEqual(heap_sorted, sorted(data))
|
||||
|
||||
def test_merge(self):
|
||||
|
@ -108,8 +127,8 @@ class TestHeap(unittest.TestCase):
|
|||
for i in range(random.randrange(5)):
|
||||
row = sorted(random.randrange(1000) for j in range(random.randrange(10)))
|
||||
inputs.append(row)
|
||||
self.assertEqual(sorted(chain(*inputs)), list(merge(*inputs)))
|
||||
self.assertEqual(list(merge()), [])
|
||||
self.assertEqual(sorted(chain(*inputs)), list(self.module.merge(*inputs)))
|
||||
self.assertEqual(list(self.module.merge()), [])
|
||||
|
||||
def test_merge_stability(self):
|
||||
class Int(int):
|
||||
|
@ -123,26 +142,33 @@ class TestHeap(unittest.TestCase):
|
|||
inputs[stream].append(obj)
|
||||
for stream in inputs:
|
||||
stream.sort()
|
||||
result = [i.pair for i in merge(*inputs)]
|
||||
result = [i.pair for i in self.module.merge(*inputs)]
|
||||
self.assertEqual(result, sorted(result))
|
||||
|
||||
def test_nsmallest(self):
|
||||
data = [(random.randrange(2000), i) for i in range(1000)]
|
||||
for f in (None, lambda x: x[0] * 547 % 2000):
|
||||
for n in (0, 1, 2, 10, 100, 400, 999, 1000, 1100):
|
||||
self.assertEqual(list(nsmallest(n, data)), sorted(data)[:n])
|
||||
self.assertEqual(list(nsmallest(n, data, key=f)),
|
||||
self.assertEqual(list(self.module.nsmallest(n, data)),
|
||||
sorted(data)[:n])
|
||||
self.assertEqual(list(self.module.nsmallest(n, data, key=f)),
|
||||
sorted(data, key=f)[:n])
|
||||
|
||||
def test_nlargest(self):
|
||||
data = [(random.randrange(2000), i) for i in range(1000)]
|
||||
for f in (None, lambda x: x[0] * 547 % 2000):
|
||||
for n in (0, 1, 2, 10, 100, 400, 999, 1000, 1100):
|
||||
self.assertEqual(list(nlargest(n, data)),
|
||||
self.assertEqual(list(self.module.nlargest(n, data)),
|
||||
sorted(data, reverse=True)[:n])
|
||||
self.assertEqual(list(nlargest(n, data, key=f)),
|
||||
self.assertEqual(list(self.module.nlargest(n, data, key=f)),
|
||||
sorted(data, key=f, reverse=True)[:n])
|
||||
|
||||
class TestHeapPython(TestHeap):
|
||||
module = py_heapq
|
||||
|
||||
class TestHeapC(TestHeap):
|
||||
module = c_heapq
|
||||
|
||||
|
||||
#==============================================================================
|
||||
|
||||
|
@ -240,44 +266,49 @@ def L(seqn):
|
|||
return chain(imap(lambda x:x, R(Ig(G(seqn)))))
|
||||
|
||||
class TestErrorHandling(unittest.TestCase):
|
||||
# only for C implementation
|
||||
module = c_heapq
|
||||
|
||||
def test_non_sequence(self):
|
||||
for f in (heapify, heappop):
|
||||
for f in (self.module.heapify, self.module.heappop):
|
||||
self.assertRaises(TypeError, f, 10)
|
||||
for f in (heappush, heapreplace, nlargest, nsmallest):
|
||||
for f in (self.module.heappush, self.module.heapreplace,
|
||||
self.module.nlargest, self.module.nsmallest):
|
||||
self.assertRaises(TypeError, f, 10, 10)
|
||||
|
||||
def test_len_only(self):
|
||||
for f in (heapify, heappop):
|
||||
for f in (self.module.heapify, self.module.heappop):
|
||||
self.assertRaises(TypeError, f, LenOnly())
|
||||
for f in (heappush, heapreplace):
|
||||
for f in (self.module.heappush, self.module.heapreplace):
|
||||
self.assertRaises(TypeError, f, LenOnly(), 10)
|
||||
for f in (nlargest, nsmallest):
|
||||
for f in (self.module.nlargest, self.module.nsmallest):
|
||||
self.assertRaises(TypeError, f, 2, LenOnly())
|
||||
|
||||
def test_get_only(self):
|
||||
for f in (heapify, heappop):
|
||||
for f in (self.module.heapify, self.module.heappop):
|
||||
self.assertRaises(TypeError, f, GetOnly())
|
||||
for f in (heappush, heapreplace):
|
||||
for f in (self.module.heappush, self.module.heapreplace):
|
||||
self.assertRaises(TypeError, f, GetOnly(), 10)
|
||||
for f in (nlargest, nsmallest):
|
||||
for f in (self.module.nlargest, self.module.nsmallest):
|
||||
self.assertRaises(TypeError, f, 2, GetOnly())
|
||||
|
||||
def test_get_only(self):
|
||||
seq = [CmpErr(), CmpErr(), CmpErr()]
|
||||
for f in (heapify, heappop):
|
||||
for f in (self.module.heapify, self.module.heappop):
|
||||
self.assertRaises(ZeroDivisionError, f, seq)
|
||||
for f in (heappush, heapreplace):
|
||||
for f in (self.module.heappush, self.module.heapreplace):
|
||||
self.assertRaises(ZeroDivisionError, f, seq, 10)
|
||||
for f in (nlargest, nsmallest):
|
||||
for f in (self.module.nlargest, self.module.nsmallest):
|
||||
self.assertRaises(ZeroDivisionError, f, 2, seq)
|
||||
|
||||
def test_arg_parsing(self):
|
||||
for f in (heapify, heappop, heappush, heapreplace, nlargest, nsmallest):
|
||||
for f in (self.module.heapify, self.module.heappop,
|
||||
self.module.heappush, self.module.heapreplace,
|
||||
self.module.nlargest, self.module.nsmallest):
|
||||
self.assertRaises(TypeError, f, 10)
|
||||
|
||||
def test_iterable_args(self):
|
||||
for f in (nlargest, nsmallest):
|
||||
for f in (self.module.nlargest, self.module.nsmallest):
|
||||
for s in ("123", "", range(1000), (1, 1.2), range(2000,2200,5)):
|
||||
for g in (G, I, Ig, L, R):
|
||||
self.assertEqual(list(f(2, g(s))), list(f(2,s)))
|
||||
|
@ -286,15 +317,14 @@ class TestErrorHandling(unittest.TestCase):
|
|||
self.assertRaises(TypeError, f, 2, N(s))
|
||||
self.assertRaises(ZeroDivisionError, f, 2, E(s))
|
||||
|
||||
|
||||
#==============================================================================
|
||||
|
||||
|
||||
def test_main(verbose=None):
|
||||
from types import BuiltinFunctionType
|
||||
|
||||
test_classes = [TestHeap]
|
||||
if isinstance(heapify, BuiltinFunctionType):
|
||||
test_classes.append(TestErrorHandling)
|
||||
test_classes = [TestHeapPython, TestHeapC, TestErrorHandling]
|
||||
test_support.run_unittest(*test_classes)
|
||||
|
||||
# verify reference counting
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import mutex
|
||||
|
||||
import unittest
|
||||
import test.test_support
|
||||
|
||||
class MutexTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.mutex = mutex.mutex()
|
||||
|
||||
def called_by_mutex(self, some_data):
|
||||
self.assert_(self.mutex.test(), "mutex not held")
|
||||
# Nested locking
|
||||
self.mutex.lock(self.called_by_mutex2, "eggs")
|
||||
|
||||
def called_by_mutex2(self, some_data):
|
||||
self.assert_(self.ready_for_2,
|
||||
"called_by_mutex2 called too soon")
|
||||
|
||||
def test_lock_and_unlock(self):
|
||||
self.read_for_2 = False
|
||||
self.mutex.lock(self.called_by_mutex, "spam")
|
||||
self.ready_for_2 = True
|
||||
# unlock both locks
|
||||
self.mutex.unlock()
|
||||
self.mutex.unlock()
|
||||
self.failIf(self.mutex.test(), "mutex still held")
|
||||
|
||||
def test_main():
|
||||
test.test_support.run_unittest(MutexTest)
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_main()
|
|
@ -368,6 +368,26 @@ class OperatorTestCase(unittest.TestCase):
|
|||
raise SyntaxError
|
||||
self.failUnlessRaises(SyntaxError, operator.attrgetter('foo'), C())
|
||||
|
||||
# recursive gets
|
||||
a = A()
|
||||
a.name = 'arthur'
|
||||
a.child = A()
|
||||
a.child.name = 'thomas'
|
||||
f = operator.attrgetter('child.name')
|
||||
self.assertEqual(f(a), 'thomas')
|
||||
self.assertRaises(AttributeError, f, a.child)
|
||||
f = operator.attrgetter('name', 'child.name')
|
||||
self.assertEqual(f(a), ('arthur', 'thomas'))
|
||||
f = operator.attrgetter('name', 'child.name', 'child.child.name')
|
||||
self.assertRaises(AttributeError, f, a)
|
||||
|
||||
a.child.child = A()
|
||||
a.child.child.name = 'johnson'
|
||||
f = operator.attrgetter('child.child.name')
|
||||
self.assertEqual(f(a), 'johnson')
|
||||
f = operator.attrgetter('name', 'child.name', 'child.child.name')
|
||||
self.assertEqual(f(a), ('arthur', 'thomas', 'johnson'))
|
||||
|
||||
def test_itemgetter(self):
|
||||
a = 'ABCDE'
|
||||
f = operator.itemgetter(2)
|
||||
|
@ -402,6 +422,24 @@ class OperatorTestCase(unittest.TestCase):
|
|||
self.assertEqual(operator.itemgetter(2,10,5)(data), ('2', '10', '5'))
|
||||
self.assertRaises(TypeError, operator.itemgetter(2, 'x', 5), data)
|
||||
|
||||
def test_methodcaller(self):
|
||||
self.assertRaises(TypeError, operator.methodcaller)
|
||||
class A:
|
||||
def foo(self, *args, **kwds):
|
||||
return args[0] + args[1]
|
||||
def bar(self, f=42):
|
||||
return f
|
||||
a = A()
|
||||
f = operator.methodcaller('foo')
|
||||
self.assertRaises(IndexError, f, a)
|
||||
f = operator.methodcaller('foo', 1, 2)
|
||||
self.assertEquals(f(a), 3)
|
||||
f = operator.methodcaller('bar')
|
||||
self.assertEquals(f(a), 42)
|
||||
self.assertRaises(TypeError, f, a, a)
|
||||
f = operator.methodcaller('bar', f=5)
|
||||
self.assertEquals(f(a), 5)
|
||||
|
||||
def test_inplace(self):
|
||||
class C(object):
|
||||
def __iadd__ (self, other): return "iadd"
|
||||
|
|
|
@ -8,6 +8,7 @@ import threading
|
|||
import thread
|
||||
import time
|
||||
import unittest
|
||||
import weakref
|
||||
|
||||
# A trivial mutable counter.
|
||||
class Counter(object):
|
||||
|
@ -253,6 +254,33 @@ class ThreadTests(unittest.TestCase):
|
|||
finally:
|
||||
sys.setcheckinterval(old_interval)
|
||||
|
||||
def test_no_refcycle_through_target(self):
|
||||
class RunSelfFunction(object):
|
||||
def __init__(self, should_raise):
|
||||
# The links in this refcycle from Thread back to self
|
||||
# should be cleaned up when the thread completes.
|
||||
self.should_raise = should_raise
|
||||
self.thread = threading.Thread(target=self._run,
|
||||
args=(self,),
|
||||
kwargs={'yet_another':self})
|
||||
self.thread.start()
|
||||
|
||||
def _run(self, other_ref, yet_another):
|
||||
if self.should_raise:
|
||||
raise SystemExit
|
||||
|
||||
cyclic_object = RunSelfFunction(should_raise=False)
|
||||
weak_cyclic_object = weakref.ref(cyclic_object)
|
||||
cyclic_object.thread.join()
|
||||
del cyclic_object
|
||||
self.assertEquals(None, weak_cyclic_object())
|
||||
|
||||
raising_cyclic_object = RunSelfFunction(should_raise=True)
|
||||
weak_raising_cyclic_object = weakref.ref(raising_cyclic_object)
|
||||
raising_cyclic_object.thread.join()
|
||||
del raising_cyclic_object
|
||||
self.assertEquals(None, weak_raising_cyclic_object())
|
||||
|
||||
|
||||
class ThreadingExceptionTests(unittest.TestCase):
|
||||
# A RuntimeError should be raised if Thread.start() is called
|
||||
|
|
|
@ -441,8 +441,13 @@ class Thread(_Verbose):
|
|||
_sleep(0.000001) # 1 usec, to let the thread run (Solaris hack)
|
||||
|
||||
def run(self):
|
||||
if self._target:
|
||||
self._target(*self._args, **self._kwargs)
|
||||
try:
|
||||
if self._target:
|
||||
self._target(*self._args, **self._kwargs)
|
||||
finally:
|
||||
# Avoid a refcycle if the thread is running a function with
|
||||
# an argument that has a member that points to the thread.
|
||||
del self._target, self._args, self._kwargs
|
||||
|
||||
def _bootstrap(self):
|
||||
# Wrapper around the real bootstrap code that ignores
|
||||
|
|
|
@ -485,6 +485,41 @@ attrgetter_traverse(attrgetterobject *ag, visitproc visit, void *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dotted_getattr(PyObject *obj, PyObject *attr)
|
||||
{
|
||||
char *s, *p;
|
||||
|
||||
if (!PyUnicode_Check(attr)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"attribute name must be a string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = PyUnicode_AsString(attr);
|
||||
Py_INCREF(obj);
|
||||
for (;;) {
|
||||
PyObject *newobj, *str;
|
||||
p = strchr(s, '.');
|
||||
str = p ? PyUnicode_FromStringAndSize(s, (p-s)) :
|
||||
PyUnicode_FromString(s);
|
||||
if (str == NULL) {
|
||||
Py_DECREF(obj);
|
||||
return NULL;
|
||||
}
|
||||
newobj = PyObject_GetAttr(obj, str);
|
||||
Py_DECREF(str);
|
||||
Py_DECREF(obj);
|
||||
if (newobj == NULL)
|
||||
return NULL;
|
||||
obj = newobj;
|
||||
if (p == NULL) break;
|
||||
s = p+1;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
attrgetter_call(attrgetterobject *ag, PyObject *args, PyObject *kw)
|
||||
{
|
||||
|
@ -494,7 +529,7 @@ attrgetter_call(attrgetterobject *ag, PyObject *args, PyObject *kw)
|
|||
if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &obj))
|
||||
return NULL;
|
||||
if (ag->nattrs == 1)
|
||||
return PyObject_GetAttr(obj, ag->attr);
|
||||
return dotted_getattr(obj, ag->attr);
|
||||
|
||||
assert(PyTuple_Check(ag->attr));
|
||||
assert(PyTuple_GET_SIZE(ag->attr) == nattrs);
|
||||
|
@ -506,7 +541,7 @@ attrgetter_call(attrgetterobject *ag, PyObject *args, PyObject *kw)
|
|||
for (i=0 ; i < nattrs ; i++) {
|
||||
PyObject *attr, *val;
|
||||
attr = PyTuple_GET_ITEM(ag->attr, i);
|
||||
val = PyObject_GetAttr(obj, attr);
|
||||
val = dotted_getattr(obj, attr);
|
||||
if (val == NULL) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
|
@ -521,7 +556,9 @@ PyDoc_STRVAR(attrgetter_doc,
|
|||
\n\
|
||||
Return a callable object that fetches the given attribute(s) from its operand.\n\
|
||||
After, f=attrgetter('name'), the call f(r) returns r.name.\n\
|
||||
After, g=attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).");
|
||||
After, g=attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).\n\
|
||||
After, h=attrgetter('name.first', 'name.last'), the call h(r) returns\n\
|
||||
(r.name.first, r.name.last).");
|
||||
|
||||
static PyTypeObject attrgetter_type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
|
@ -565,6 +602,139 @@ static PyTypeObject attrgetter_type = {
|
|||
attrgetter_new, /* tp_new */
|
||||
0, /* tp_free */
|
||||
};
|
||||
|
||||
|
||||
/* methodcaller object **********************************************************/
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *name;
|
||||
PyObject *args;
|
||||
PyObject *kwds;
|
||||
} methodcallerobject;
|
||||
|
||||
static PyTypeObject methodcaller_type;
|
||||
|
||||
static PyObject *
|
||||
methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
methodcallerobject *mc;
|
||||
PyObject *name, *newargs;
|
||||
|
||||
if (PyTuple_GET_SIZE(args) < 1) {
|
||||
PyErr_SetString(PyExc_TypeError, "methodcaller needs at least "
|
||||
"one argument, the method name");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create methodcallerobject structure */
|
||||
mc = PyObject_GC_New(methodcallerobject, &methodcaller_type);
|
||||
if (mc == NULL)
|
||||
return NULL;
|
||||
|
||||
newargs = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args));
|
||||
if (newargs == NULL) {
|
||||
Py_DECREF(mc);
|
||||
return NULL;
|
||||
}
|
||||
mc->args = newargs;
|
||||
|
||||
name = PyTuple_GET_ITEM(args, 0);
|
||||
Py_INCREF(name);
|
||||
mc->name = name;
|
||||
|
||||
Py_XINCREF(kwds);
|
||||
mc->kwds = kwds;
|
||||
|
||||
PyObject_GC_Track(mc);
|
||||
return (PyObject *)mc;
|
||||
}
|
||||
|
||||
static void
|
||||
methodcaller_dealloc(methodcallerobject *mc)
|
||||
{
|
||||
PyObject_GC_UnTrack(mc);
|
||||
Py_XDECREF(mc->name);
|
||||
Py_XDECREF(mc->args);
|
||||
Py_XDECREF(mc->kwds);
|
||||
PyObject_GC_Del(mc);
|
||||
}
|
||||
|
||||
static int
|
||||
methodcaller_traverse(methodcallerobject *mc, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(mc->args);
|
||||
Py_VISIT(mc->kwds);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
methodcaller_call(methodcallerobject *mc, PyObject *args, PyObject *kw)
|
||||
{
|
||||
PyObject *method, *obj, *result;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "methodcaller", 1, 1, &obj))
|
||||
return NULL;
|
||||
method = PyObject_GetAttr(obj, mc->name);
|
||||
if (method == NULL)
|
||||
return NULL;
|
||||
result = PyObject_Call(method, mc->args, mc->kwds);
|
||||
Py_DECREF(method);
|
||||
return result;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(methodcaller_doc,
|
||||
"methodcaller(name, ...) --> methodcaller object\n\
|
||||
\n\
|
||||
Return a callable object that calls the given method on its operand.\n\
|
||||
After, f = methodcaller('name'), the call f(r) returns r.name().\n\
|
||||
After, g = methodcaller('name', 'date', foo=1), the call g(r) returns\n\
|
||||
r.name('date', foo=1).");
|
||||
|
||||
static PyTypeObject methodcaller_type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"operator.methodcaller", /* tp_name */
|
||||
sizeof(methodcallerobject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor)methodcaller_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
(ternaryfunc)methodcaller_call, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
|
||||
methodcaller_doc, /* tp_doc */
|
||||
(traverseproc)methodcaller_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
methodcaller_new, /* tp_new */
|
||||
0, /* tp_free */
|
||||
};
|
||||
|
||||
|
||||
/* Initialization function for the module (*must* be called initoperator) */
|
||||
|
||||
PyMODINIT_FUNC
|
||||
|
@ -587,4 +757,9 @@ initoperator(void)
|
|||
return;
|
||||
Py_INCREF(&attrgetter_type);
|
||||
PyModule_AddObject(m, "attrgetter", (PyObject *)&attrgetter_type);
|
||||
|
||||
if (PyType_Ready(&methodcaller_type) < 0)
|
||||
return;
|
||||
Py_INCREF(&methodcaller_type);
|
||||
PyModule_AddObject(m, "methodcaller", (PyObject *)&methodcaller_type);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
|
||||
/*
|
||||
__version__ 60978.
|
||||
__version__ 57783.
|
||||
|
||||
This module must be committed separately after each AST grammar change;
|
||||
The __version__ number is set to the revision number of the commit
|
||||
|
@ -3171,7 +3171,7 @@ init_ast(void)
|
|||
if (PyDict_SetItemString(d, "AST", (PyObject*)AST_type) < 0) return;
|
||||
if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0)
|
||||
return;
|
||||
if (PyModule_AddStringConstant(m, "__version__", "60978") < 0)
|
||||
if (PyModule_AddStringConstant(m, "__version__", "57783") < 0)
|
||||
return;
|
||||
if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return;
|
||||
if (PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0)
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
/* for stat.st_mode */
|
||||
typedef unsigned short mode_t;
|
||||
#endif
|
||||
|
||||
extern time_t PyOS_GetLastModificationTime(char *, FILE *);
|
||||
/* In getmtime.c */
|
||||
|
||||
|
|
Loading…
Reference in New Issue