Commit 4ac9ce4f authored by Benjamin Peterson's avatar Benjamin Peterson

Merged revisions...

Merged revisions 74779-74786,74793,74795,74811,74860-74861,74863,74876,74886,74896,74901,74903,74908,74912,74930,74933,74943,74946,74952-74955,75015,75019,75032,75068,75076,75095,75098,75102,75129,75139,75230 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r74779 | michael.foord | 2009-09-13 11:13:36 -0500 (Sun, 13 Sep 2009) | 1 line

  Change to tutorial wording for reading text / binary files on Windows. Issue #6301.
........
  r74780 | michael.foord | 2009-09-13 11:40:02 -0500 (Sun, 13 Sep 2009) | 1 line

  Objects that compare equal automatically pass or fail assertAlmostEqual and assertNotAlmostEqual tests on unittest.TestCase. Issue 6567.
........
  r74781 | michael.foord | 2009-09-13 11:46:19 -0500 (Sun, 13 Sep 2009) | 1 line

  Note that sys._getframe is not guaranteed to exist in all implementations of Python, and a corresponding note in inspect.currentframe. Issue 6712.
........
  r74782 | michael.foord | 2009-09-13 12:07:46 -0500 (Sun, 13 Sep 2009) | 1 line

  Tutorial tweaks. Issue 6849.
........
  r74783 | michael.foord | 2009-09-13 12:28:35 -0500 (Sun, 13 Sep 2009) | 1 line

  unittest.TestLoader.loadTestsFromName honors the loader suiteClass attribute. Issue 6866.
........
  r74784 | georg.brandl | 2009-09-13 13:15:07 -0500 (Sun, 13 Sep 2009) | 1 line

  Typo fix.
........
  r74785 | michael.foord | 2009-09-13 14:07:03 -0500 (Sun, 13 Sep 2009) | 1 line

  Test discovery in unittest will only attempt to import modules that are importable; i.e. their names are valid Python identifiers. If an import fails during discovery this will be recorded as an error and test discovery will continue. Issue 6568.
........
  r74786 | michael.foord | 2009-09-13 14:08:18 -0500 (Sun, 13 Sep 2009) | 1 line

  Remove an extraneous space in unittest documentation.
........
  r74793 | georg.brandl | 2009-09-14 09:50:47 -0500 (Mon, 14 Sep 2009) | 1 line

  #6908: fix association of hashlib hash attributes.
........
  r74795 | benjamin.peterson | 2009-09-14 22:36:26 -0500 (Mon, 14 Sep 2009) | 1 line

  Py_SetPythonHome uses static storage #6913
........
  r74811 | georg.brandl | 2009-09-15 15:26:59 -0500 (Tue, 15 Sep 2009) | 1 line

  Add Armin Ronacher.
........
  r74860 | benjamin.peterson | 2009-09-16 21:46:54 -0500 (Wed, 16 Sep 2009) | 1 line

  kill bare except
........
  r74861 | benjamin.peterson | 2009-09-16 22:18:28 -0500 (Wed, 16 Sep 2009) | 1 line

  pep 8 defaults
........
  r74863 | benjamin.peterson | 2009-09-16 22:27:33 -0500 (Wed, 16 Sep 2009) | 1 line

  rationalize a bit
........
  r74876 | georg.brandl | 2009-09-17 11:15:53 -0500 (Thu, 17 Sep 2009) | 1 line

  #6932: remove paragraph that advises relying on __del__ being called.
........
  r74886 | benjamin.peterson | 2009-09-17 16:33:46 -0500 (Thu, 17 Sep 2009) | 1 line

  use macros
........
  r74896 | georg.brandl | 2009-09-18 02:22:41 -0500 (Fri, 18 Sep 2009) | 1 line

  #6936: for interactive use, quit() is just fine.
........
  r74901 | georg.brandl | 2009-09-18 04:14:52 -0500 (Fri, 18 Sep 2009) | 1 line

  #6905: use better exception messages in inspect when the argument is of the wrong type.
........
  r74903 | georg.brandl | 2009-09-18 04:18:27 -0500 (Fri, 18 Sep 2009) | 1 line

  #6938: "ident" is always a string, so use a format code which works.
........
  r74908 | georg.brandl | 2009-09-18 08:57:11 -0500 (Fri, 18 Sep 2009) | 1 line

  Use str.format() to fix beginner's mistake with %-style string formatting.
........
  r74912 | georg.brandl | 2009-09-18 11:19:56 -0500 (Fri, 18 Sep 2009) | 1 line

  Optimize optimization and fix method name in docstring.
........
  r74930 | georg.brandl | 2009-09-18 16:21:41 -0500 (Fri, 18 Sep 2009) | 1 line

  #6925: rewrite docs for locals() and vars() a bit.
........
  r74933 | georg.brandl | 2009-09-18 16:35:59 -0500 (Fri, 18 Sep 2009) | 1 line

  #6930: clarify description about byteorder handling in UTF decoder routines.
........
  r74943 | georg.brandl | 2009-09-19 02:35:07 -0500 (Sat, 19 Sep 2009) | 1 line

  #6944: the argument to PyArg_ParseTuple should be a tuple, otherwise a SystemError is set.  Also clean up another usage of PyArg_ParseTuple.
........
  r74946 | georg.brandl | 2009-09-19 03:43:16 -0500 (Sat, 19 Sep 2009) | 1 line

  Update bug tracker reference.
........
  r74952 | georg.brandl | 2009-09-19 05:42:34 -0500 (Sat, 19 Sep 2009) | 1 line

  #6946: fix duplicate index entries for datetime classes.
........
  r74953 | georg.brandl | 2009-09-19 07:04:16 -0500 (Sat, 19 Sep 2009) | 1 line

  Fix references to threading.enumerate().
........
  r74954 | georg.brandl | 2009-09-19 08:13:56 -0500 (Sat, 19 Sep 2009) | 1 line

  Add Doug.
........
  r74955 | georg.brandl | 2009-09-19 08:20:49 -0500 (Sat, 19 Sep 2009) | 1 line

  Add Mark Summerfield.
........
  r75015 | georg.brandl | 2009-09-22 05:55:08 -0500 (Tue, 22 Sep 2009) | 1 line

  Fix encoding name.
........
  r75019 | vinay.sajip | 2009-09-22 12:23:41 -0500 (Tue, 22 Sep 2009) | 1 line

  Fixed a typo, and added sections on optimization and using arbitrary objects as messages.
........
  r75032 | benjamin.peterson | 2009-09-22 17:15:28 -0500 (Tue, 22 Sep 2009) | 1 line

  fix typos/rephrase
........
  r75068 | benjamin.peterson | 2009-09-25 21:57:59 -0500 (Fri, 25 Sep 2009) | 1 line

  comment out ugly xxx
........
  r75076 | vinay.sajip | 2009-09-26 09:53:32 -0500 (Sat, 26 Sep 2009) | 1 line

  Tidied up name of parameter in StreamHandler
........
  r75095 | michael.foord | 2009-09-27 14:15:41 -0500 (Sun, 27 Sep 2009) | 1 line

  Test creation moved from TestProgram.parseArgs to TestProgram.createTests exclusively. Issue 6956.
........
  r75098 | michael.foord | 2009-09-27 15:08:23 -0500 (Sun, 27 Sep 2009) | 1 line

  Documentation improvement for load_tests protocol in unittest. Issue 6515.
........
  r75102 | skip.montanaro | 2009-09-27 21:12:27 -0500 (Sun, 27 Sep 2009) | 3 lines

  Patch from Thomas Barr so that csv.Sniffer will set doublequote property.
  Closes issue 6606.
........
  r75129 | vinay.sajip | 2009-09-29 02:08:54 -0500 (Tue, 29 Sep 2009) | 1 line

  Issue #7014: logging: Improved IronPython 2.6 compatibility.
........
  r75139 | raymond.hettinger | 2009-09-29 13:53:24 -0500 (Tue, 29 Sep 2009) | 3 lines

  Issue 7008: Better document str.title and show how to work around the apostrophe problem.
........
  r75230 | benjamin.peterson | 2009-10-04 08:38:38 -0500 (Sun, 04 Oct 2009) | 1 line

  test logging
........
parent bd27aef8
...@@ -371,6 +371,10 @@ Initialization, Finalization, and Threads ...@@ -371,6 +371,10 @@ Initialization, Finalization, and Threads
Set the default "home" directory, that is, the location of the standard Set the default "home" directory, that is, the location of the standard
Python libraries. The libraries are searched in Python libraries. The libraries are searched in
:file:`{home}/lib/python{version}` and :file:`{home}/lib/python{version}`. :file:`{home}/lib/python{version}` and :file:`{home}/lib/python{version}`.
The argument should point to a zero-terminated character string in static
storage whose contents will not change for the duration of the program's
execution. No code in the Python interpreter will change the contents of
this storage.
.. cfunction:: w_char* Py_GetPythonHome() .. cfunction:: w_char* Py_GetPythonHome()
......
...@@ -476,10 +476,13 @@ These are the UTF-32 codec APIs: ...@@ -476,10 +476,13 @@ These are the UTF-32 codec APIs:
*byteorder == 0: native order *byteorder == 0: native order
*byteorder == 1: big endian *byteorder == 1: big endian
and then switches if the first four bytes of the input data are a byte order mark If ``*byteorder`` is zero, and the first four bytes of the input data are a
(BOM) and the specified byte order is native order. This BOM is not copied into byte order mark (BOM), the decoder switches to this byte order and the BOM is
the resulting Unicode string. After completion, *\*byteorder* is set to the not copied into the resulting Unicode string. If ``*byteorder`` is ``-1`` or
current byte order at the end of input data. ``1``, any byte order mark is copied to the output.
After completion, *\*byteorder* is set to the current byte order at the end
of input data.
In a narrow build codepoints outside the BMP will be decoded as surrogate pairs. In a narrow build codepoints outside the BMP will be decoded as surrogate pairs.
...@@ -500,8 +503,7 @@ These are the UTF-32 codec APIs: ...@@ -500,8 +503,7 @@ These are the UTF-32 codec APIs:
.. cfunction:: PyObject* PyUnicode_EncodeUTF32(const Py_UNICODE *s, Py_ssize_t size, const char *errors, int byteorder) .. cfunction:: PyObject* PyUnicode_EncodeUTF32(const Py_UNICODE *s, Py_ssize_t size, const char *errors, int byteorder)
Return a Python bytes object holding the UTF-32 encoded value of the Unicode Return a Python bytes object holding the UTF-32 encoded value of the Unicode
data in *s*. If *byteorder* is not ``0``, output is written according to the data in *s*. Output is written according to the following byte order::
following byte order::
byteorder == -1: little endian byteorder == -1: little endian
byteorder == 0: native byte order (writes a BOM mark) byteorder == 0: native byte order (writes a BOM mark)
...@@ -541,10 +543,14 @@ These are the UTF-16 codec APIs: ...@@ -541,10 +543,14 @@ These are the UTF-16 codec APIs:
*byteorder == 0: native order *byteorder == 0: native order
*byteorder == 1: big endian *byteorder == 1: big endian
and then switches if the first two bytes of the input data are a byte order mark If ``*byteorder`` is zero, and the first two bytes of the input data are a
(BOM) and the specified byte order is native order. This BOM is not copied into byte order mark (BOM), the decoder switches to this byte order and the BOM is
the resulting Unicode string. After completion, *\*byteorder* is set to the not copied into the resulting Unicode string. If ``*byteorder`` is ``-1`` or
current byte order at the end of input data. ``1``, any byte order mark is copied to the output (where it will result in
either a ``\ufeff`` or a ``\ufffe`` character).
After completion, *\*byteorder* is set to the current byte order at the end
of input data.
If *byteorder* is *NULL*, the codec starts in native order mode. If *byteorder* is *NULL*, the codec starts in native order mode.
...@@ -563,8 +569,7 @@ These are the UTF-16 codec APIs: ...@@ -563,8 +569,7 @@ These are the UTF-16 codec APIs:
.. cfunction:: PyObject* PyUnicode_EncodeUTF16(const Py_UNICODE *s, Py_ssize_t size, const char *errors, int byteorder) .. cfunction:: PyObject* PyUnicode_EncodeUTF16(const Py_UNICODE *s, Py_ssize_t size, const char *errors, int byteorder)
Return a Python bytes object holding the UTF-16 encoded value of the Unicode Return a Python bytes object holding the UTF-16 encoded value of the Unicode
data in *s*. If *byteorder* is not ``0``, output is written according to the data in *s*. Output is written according to the following byte order::
following byte order::
byteorder == -1: little endian byteorder == -1: little endian
byteorder == 0: native byte order (writes a BOM mark) byteorder == 0: native byte order (writes a BOM mark)
......
...@@ -597,8 +597,10 @@ units as well as normal text: ...@@ -597,8 +597,10 @@ units as well as normal text:
An important bit of information about an API that a user should be aware of An important bit of information about an API that a user should be aware of
when using whatever bit of API the warning pertains to. The content of the when using whatever bit of API the warning pertains to. The content of the
directive should be written in complete sentences and include all appropriate directive should be written in complete sentences and include all appropriate
punctuation. This should only be chosen over ``note`` for information punctuation. In the interest of not scaring users away from pages filled
regarding the possibility of crashes, data loss, or security implications. with warnings, this directive should only be chosen over ``note`` for
information regarding the possibility of crashes, data loss, or security
implications.
.. describe:: versionadded .. describe:: versionadded
......
...@@ -988,7 +988,7 @@ particular, the following variants typically exist: ...@@ -988,7 +988,7 @@ particular, the following variants typically exist:
+-----------------+--------------------------------+--------------------------------+ +-----------------+--------------------------------+--------------------------------+
| cp1255 | windows-1255 | Hebrew | | cp1255 | windows-1255 | Hebrew |
+-----------------+--------------------------------+--------------------------------+ +-----------------+--------------------------------+--------------------------------+
| cp1256 | windows1256 | Arabic | | cp1256 | windows-1256 | Arabic |
+-----------------+--------------------------------+--------------------------------+ +-----------------+--------------------------------+--------------------------------+
| cp1257 | windows-1257 | Baltic languages | | cp1257 | windows-1257 | Baltic languages |
+-----------------+--------------------------------+--------------------------------+ +-----------------+--------------------------------+--------------------------------+
......
...@@ -63,6 +63,7 @@ Available Types ...@@ -63,6 +63,7 @@ Available Types
.. class:: date .. class:: date
:noindex:
An idealized naive date, assuming the current Gregorian calendar always was, and An idealized naive date, assuming the current Gregorian calendar always was, and
always will be, in effect. Attributes: :attr:`year`, :attr:`month`, and always will be, in effect. Attributes: :attr:`year`, :attr:`month`, and
...@@ -70,6 +71,7 @@ Available Types ...@@ -70,6 +71,7 @@ Available Types
.. class:: time .. class:: time
:noindex:
An idealized time, independent of any particular day, assuming that every day An idealized time, independent of any particular day, assuming that every day
has exactly 24\*60\*60 seconds (there is no notion of "leap seconds" here). has exactly 24\*60\*60 seconds (there is no notion of "leap seconds" here).
...@@ -78,6 +80,7 @@ Available Types ...@@ -78,6 +80,7 @@ Available Types
.. class:: datetime .. class:: datetime
:noindex:
A combination of a date and a time. Attributes: :attr:`year`, :attr:`month`, A combination of a date and a time. Attributes: :attr:`year`, :attr:`month`,
:attr:`day`, :attr:`hour`, :attr:`minute`, :attr:`second`, :attr:`microsecond`, :attr:`day`, :attr:`hour`, :attr:`minute`, :attr:`second`, :attr:`microsecond`,
...@@ -85,6 +88,7 @@ Available Types ...@@ -85,6 +88,7 @@ Available Types
.. class:: timedelta .. class:: timedelta
:noindex:
A duration expressing the difference between two :class:`date`, :class:`time`, A duration expressing the difference between two :class:`date`, :class:`time`,
or :class:`datetime` instances to microsecond resolution. or :class:`datetime` instances to microsecond resolution.
......
...@@ -600,16 +600,12 @@ are always available. They are listed here in alphabetical order. ...@@ -600,16 +600,12 @@ are always available. They are listed here in alphabetical order.
.. function:: locals() .. function:: locals()
Update and return a dictionary representing the current local symbol table. Update and return a dictionary representing the current local symbol table.
Free variables are returned by :func:`locals` when it is called in function
blocks, but not in class blocks.
.. note:: .. note::
The contents of this dictionary should not be modified; changes may not The contents of this dictionary should not be modified; changes may not
affect the values of local variables used by the interpreter. affect the values of local and free variables used by the interpreter.
Free variables are returned by :func:`locals` when it is called in a function
block. Modifications of free variables may not affect the values used by the
interpreter. Free variables are not returned in class blocks.
.. function:: map(function, iterable, ...) .. function:: map(function, iterable, ...)
...@@ -1176,10 +1172,10 @@ are always available. They are listed here in alphabetical order. ...@@ -1176,10 +1172,10 @@ are always available. They are listed here in alphabetical order.
.. function:: vars([object]) .. function:: vars([object])
Without arguments, return a dictionary corresponding to the current local symbol Without an argument, act like :func:`locals`.
table. With a module, class or class instance object as argument (or anything
else that has a :attr:`__dict__` attribute), returns a dictionary corresponding With a module, class or class instance object as argument (or anything else that
to the object's symbol table. has a :attr:`__dict__` attribute), return that attribute.
.. note:: .. note::
The returned dictionary should not be modified: The returned dictionary should not be modified:
......
...@@ -86,11 +86,11 @@ The following values are provided as constant attributes of the hash objects ...@@ -86,11 +86,11 @@ The following values are provided as constant attributes of the hash objects
returned by the constructors: returned by the constructors:
.. data:: digest_size .. data:: hash.digest_size
The size of the resulting hash in bytes. The size of the resulting hash in bytes.
.. data:: block_size .. data:: hash.block_size
The internal block size of the hash algorithm in bytes. The internal block size of the hash algorithm in bytes.
......
...@@ -508,6 +508,11 @@ line. ...@@ -508,6 +508,11 @@ line.
Return the frame object for the caller's stack frame. Return the frame object for the caller's stack frame.
This function relies on Python stack frame support in the interpreter, which
isn't guaranteed to exist in all implementations of Python. If running in
an implementation without Python stack frame support this function returns
``None``.
.. function:: stack(context=1) .. function:: stack(context=1)
......
...@@ -57,7 +57,7 @@ default handler so that debug messages are written to a file:: ...@@ -57,7 +57,7 @@ default handler so that debug messages are written to a file::
import logging import logging
LOG_FILENAME = '/tmp/logging_example.out' LOG_FILENAME = '/tmp/logging_example.out'
logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,) logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)
logging.debug('This message should go to the log file') logging.debug('This message should go to the log file')
...@@ -1493,6 +1493,55 @@ printed on the console; on the server side, you should see something like:: ...@@ -1493,6 +1493,55 @@ printed on the console; on the server side, you should see something like::
69 myapp.area2 WARNING Jail zesty vixen who grabbed pay from quack. 69 myapp.area2 WARNING Jail zesty vixen who grabbed pay from quack.
69 myapp.area2 ERROR The five boxing wizards jump quickly. 69 myapp.area2 ERROR The five boxing wizards jump quickly.
Using arbitrary objects as messages
-----------------------------------
In the preceding sections and examples, it has been assumed that the message
passed when logging the event is a string. However, this is not the only
possibility. You can pass an arbitrary object as a message, and its
:meth:`__str__` method will be called when the logging system needs to convert
it to a string representation. In fact, if you want to, you can avoid
computing a string representation altogether - for example, the
:class:`SocketHandler` emits an event by pickling it and sending it over the
wire.
Optimization
------------
Formatting of message arguments is deferred until it cannot be avoided.
However, computing the arguments passed to the logging method can also be
expensive, and you may want to avoid doing it if the logger will just throw
away your event. To decide what to do, you can call the :meth:`isEnabledFor`
method which takes a level argument and returns true if the event would be
created by the Logger for that level of call. You can write code like this::
if logger.isEnabledFor(logging.DEBUG):
logger.debug("Message with %s, %s", expensive_func1(),
expensive_func2())
so that if the logger's threshold is set above ``DEBUG``, the calls to
:func:`expensive_func1` and :func:`expensive_func2` are never made.
There are other optimizations which can be made for specific applications which
need more precise control over what logging information is collected. Here's a
list of things you can do to avoid processing during logging which you don't
need:
+-----------------------------------------------+----------------------------------------+
| What you don't want to collect | How to avoid collecting it |
+===============================================+========================================+
| Information about where calls were made from. | Set ``logging._srcfile`` to ``None``. |
+-----------------------------------------------+----------------------------------------+
| Threading information. | Set ``logging.logThreads`` to ``0``. |
+-----------------------------------------------+----------------------------------------+
| Process information. | Set ``logging.logProcesses`` to ``0``. |
+-----------------------------------------------+----------------------------------------+
Also note that the core logging module only includes the basic handlers. If
you don't import :mod:`logging.handlers` and :mod:`logging.config`, they won't
take up any memory.
.. _handler:
Handler Objects Handler Objects
--------------- ---------------
...@@ -1608,9 +1657,9 @@ file-like object (or, more precisely, any object which supports :meth:`write` ...@@ -1608,9 +1657,9 @@ file-like object (or, more precisely, any object which supports :meth:`write`
and :meth:`flush` methods). and :meth:`flush` methods).
.. class:: StreamHandler(strm=None) .. class:: StreamHandler(stream=None)
Returns a new instance of the :class:`StreamHandler` class. If *strm* is Returns a new instance of the :class:`StreamHandler` class. If *stream* is
specified, the instance will use it for logging output; otherwise, *sys.stderr* specified, the instance will use it for logging output; otherwise, *sys.stderr*
will be used. will be used.
......
...@@ -27,27 +27,39 @@ lots of shared sub-objects. The keys are ordinary strings. ...@@ -27,27 +27,39 @@ lots of shared sub-objects. The keys are ordinary strings.
Because of Python semantics, a shelf cannot know when a mutable Because of Python semantics, a shelf cannot know when a mutable
persistent-dictionary entry is modified. By default modified objects are persistent-dictionary entry is modified. By default modified objects are
written only when assigned to the shelf (see :ref:`shelve-example`). If written only when assigned to the shelf (see :ref:`shelve-example`). If the
the optional *writeback* parameter is set to *True*, all entries accessed optional *writeback* parameter is set to *True*, all entries accessed are
are cached in memory, and written back at close time; this can make it cached in memory, and written back on :meth:`sync` and :meth:`close`; this
handier to mutate mutable entries in the persistent dictionary, but, if can make it handier to mutate mutable entries in the persistent dictionary,
many entries are accessed, it can consume vast amounts of memory for the but, if many entries are accessed, it can consume vast amounts of memory for
cache, and it can make the close operation very slow since all accessed the cache, and it can make the close operation very slow since all accessed
entries are written back (there is no way to determine which accessed entries are written back (there is no way to determine which accessed entries
entries are mutable, nor which ones were actually mutated). are mutable, nor which ones were actually mutated).
.. note::
Do not rely on the shelf being closed automatically; always call
:meth:`close` explicitly when you don't need it any more, or use a
:keyword:`with` statement with :func:`contextlib.closing`.
Shelf objects support all methods supported by dictionaries. This eases the Shelf objects support all methods supported by dictionaries. This eases the
transition from dictionary based scripts to those requiring persistent storage. transition from dictionary based scripts to those requiring persistent storage.
One additional method is supported: Two additional methods are supported:
.. method:: Shelf.sync() .. method:: Shelf.sync()
Write back all entries in the cache if the shelf was opened with *writeback* set Write back all entries in the cache if the shelf was opened with *writeback*
to *True*. Also empty the cache and synchronize the persistent dictionary on set to :const:`True`. Also empty the cache and synchronize the persistent
disk, if feasible. This is called automatically when the shelf is closed with dictionary on disk, if feasible. This is called automatically when the shelf
:meth:`close`. is closed with :meth:`close`.
.. method:: Shelf.close()
Synchronize and close the persistent *dict* object. Operations on a closed
shelf will fail with a :exc:`ValueError`.
.. seealso:: .. seealso::
...@@ -71,11 +83,6 @@ Restrictions ...@@ -71,11 +83,6 @@ Restrictions
database should be fairly small, and in rare cases key collisions may cause database should be fairly small, and in rare cases key collisions may cause
the database to refuse updates. the database to refuse updates.
* Depending on the implementation, closing a persistent dictionary may or may
not be necessary to flush changes to disk. The :meth:`__del__` method of the
:class:`Shelf` class calls the :meth:`close` method, so the programmer generally
need not do this explicitly.
* The :mod:`shelve` module does not support *concurrent* read/write access to * The :mod:`shelve` module does not support *concurrent* read/write access to
shelved objects. (Multiple simultaneous read accesses are safe.) When a shelved objects. (Multiple simultaneous read accesses are safe.) When a
program has a shelf open for writing, no other program should have it open for program has a shelf open for writing, no other program should have it open for
......
...@@ -1149,6 +1149,8 @@ functions based on regular expressions. ...@@ -1149,6 +1149,8 @@ functions based on regular expressions.
>>> titlecase("they're bill's friends.") >>> titlecase("they're bill's friends.")
"They're Bill's Friends." "They're Bill's Friends."
For 8-bit strings, this method is locale-dependent.
.. method:: str.translate(map) .. method:: str.translate(map)
......
...@@ -337,12 +337,12 @@ always available. ...@@ -337,12 +337,12 @@ always available.
does not have to hold true for third-party extensions as it is implementation does not have to hold true for third-party extensions as it is implementation
specific. specific.
The *default* argument allows to define a value which will be returned If given, *default* will be returned if the object does not provide means to
if the object type does not provide means to retrieve the size and would retrieve the size. Otherwise a `TypeError` will be raised.
cause a `TypeError`.
:func:`getsizeof` calls the object's __sizeof__ method and adds an additional :func:`getsizeof` calls the object's ``__sizeof__`` method and adds an
garbage collector overhead if the object is managed by the garbage collector. additional garbage collector overhead if the object is managed by the garbage
collector.
.. function:: _getframe([depth]) .. function:: _getframe([depth])
...@@ -352,7 +352,8 @@ always available. ...@@ -352,7 +352,8 @@ always available.
that is deeper than the call stack, :exc:`ValueError` is raised. The default that is deeper than the call stack, :exc:`ValueError` is raised. The default
for *depth* is zero, returning the frame at the top of the call stack. for *depth* is zero, returning the frame at the top of the call stack.
This function should be used for internal and specialized purposes only. This function should be used for internal and specialized purposes only. It
is not guaranteed to exist in all implementations of Python.
.. function:: getprofile() .. function:: getprofile()
......
...@@ -89,7 +89,7 @@ technique using a separate :func:`tcgetattr` call and a :keyword:`try` ... ...@@ -89,7 +89,7 @@ technique using a separate :func:`tcgetattr` call and a :keyword:`try` ...
:keyword:`finally` statement to ensure that the old tty attributes are restored :keyword:`finally` statement to ensure that the old tty attributes are restored
exactly no matter what happens:: exactly no matter what happens::
def getpass(prompt = "Password: "): def getpass(prompt="Password: "):
import termios, sys import termios, sys
fd = sys.stdin.fileno() fd = sys.stdin.fileno()
old = termios.tcgetattr(fd) old = termios.tcgetattr(fd)
......
...@@ -23,7 +23,7 @@ This module defines the following functions and objects: ...@@ -23,7 +23,7 @@ This module defines the following functions and objects:
.. function:: active_count() .. function:: active_count()
Return the number of :class:`Thread` objects currently alive. The returned Return the number of :class:`Thread` objects currently alive. The returned
count is equal to the length of the list returned by :func:`enumerate`. count is equal to the length of the list returned by :func:`.enumerate`.
.. function:: Condition() .. function:: Condition()
...@@ -301,7 +301,7 @@ impossible to detect the termination of alien threads. ...@@ -301,7 +301,7 @@ impossible to detect the termination of alien threads.
Roughly, a thread is alive from the moment the :meth:`start` method Roughly, a thread is alive from the moment the :meth:`start` method
returns until its :meth:`run` method terminates. The module function returns until its :meth:`run` method terminates. The module function
:func:`enumerate` returns a list of all alive threads. :func:`.enumerate` returns a list of all alive threads.
.. attribute:: daemon .. attribute:: daemon
......
...@@ -728,6 +728,9 @@ Test cases ...@@ -728,6 +728,9 @@ Test cases
compare equal, the test will fail with the explanation given by *msg*, or compare equal, the test will fail with the explanation given by *msg*, or
:const:`None`. :const:`None`.
.. versionchanged:: 3.2
Objects that compare equal are automatically almost equal.
.. deprecated:: 3.1 .. deprecated:: 3.1
:meth:`failUnlessAlmostEqual`. :meth:`failUnlessAlmostEqual`.
...@@ -744,6 +747,9 @@ Test cases ...@@ -744,6 +747,9 @@ Test cases
compare equal, the test will fail with the explanation given by *msg*, or compare equal, the test will fail with the explanation given by *msg*, or
:const:`None`. :const:`None`.
.. versionchanged:: 3.2
Objects that compare equal automatically fail.
.. deprecated:: 3.1 .. deprecated:: 3.1
:meth:`failIfAlmostEqual`. :meth:`failIfAlmostEqual`.
...@@ -1244,12 +1250,17 @@ Loading and running tests ...@@ -1244,12 +1250,17 @@ Loading and running tests
Find and return all test modules from the specified start directory, Find and return all test modules from the specified start directory,
recursing into subdirectories to find them. Only test files that match recursing into subdirectories to find them. Only test files that match
*pattern* will be loaded. (Using shell style pattern matching.) *pattern* will be loaded. (Using shell style pattern matching.) Only
module names that are importable (i.e. are valid Python identifiers) will
be loaded.
All test modules must be importable from the top level of the project. If All test modules must be importable from the top level of the project. If
the start directory is not the top level directory then the top level the start directory is not the top level directory then the top level
directory must be specified separately. directory must be specified separately.
If importing a module fails, for example due to a syntax error, then this
will be recorded as a single error and discovery will continue.
If a test package name (directory with :file:`__init__.py`) matches the If a test package name (directory with :file:`__init__.py`) matches the
pattern then the package will be checked for a ``load_tests`` pattern then the package will be checked for a ``load_tests``
function. If this exists then it will be called with *loader*, *tests*, function. If this exists then it will be called with *loader*, *tests*,
...@@ -1263,6 +1274,7 @@ Loading and running tests ...@@ -1263,6 +1274,7 @@ Loading and running tests
``load_tests`` does not need to pass this argument in to ``load_tests`` does not need to pass this argument in to
``loader.discover()``. ``loader.discover()``.
.. versionadded:: 2.7
The following attributes of a :class:`TestLoader` can be configured either by The following attributes of a :class:`TestLoader` can be configured either by
subclassing or assignment on an instance: subclassing or assignment on an instance:
...@@ -1518,6 +1530,10 @@ Loading and running tests ...@@ -1518,6 +1530,10 @@ Loading and running tests
load_tests Protocol load_tests Protocol
################### ###################
.. versionadded:: 2.7
Modules or packages can customize how tests are loaded from them during normal Modules or packages can customize how tests are loaded from them during normal
test runs or test discovery by implementing a function called ``load_tests``. test runs or test discovery by implementing a function called ``load_tests``.
......
...@@ -31,7 +31,7 @@ command into the command prompt in a DOS box:: ...@@ -31,7 +31,7 @@ command into the command prompt in a DOS box::
Typing an end-of-file character (:kbd:`Control-D` on Unix, :kbd:`Control-Z` on Typing an end-of-file character (:kbd:`Control-D` on Unix, :kbd:`Control-Z` on
Windows) at the primary prompt causes the interpreter to exit with a zero exit Windows) at the primary prompt causes the interpreter to exit with a zero exit
status. If that doesn't work, you can exit the interpreter by typing the status. If that doesn't work, you can exit the interpreter by typing the
following commands: ``import sys; sys.exit()``. following command: ``quit()``.
The interpreter's line-editing features usually aren't very sophisticated. On The interpreter's line-editing features usually aren't very sophisticated. On
Unix, whoever installed the interpreter may have enabled support for the GNU Unix, whoever installed the interpreter may have enabled support for the GNU
......
...@@ -107,6 +107,10 @@ In most cases Python programmers do not use this facility since it introduces ...@@ -107,6 +107,10 @@ In most cases Python programmers do not use this facility since it introduces
an unknown set of names into the interpreter, possibly hiding some things an unknown set of names into the interpreter, possibly hiding some things
you have already defined. you have already defined.
Note that in general the practice of importing ``*`` from a module or package is
frowned upon, since it often causes poorly readable code. However, it is okay to
use it to save typing in interactive sessions.
.. note:: .. note::
For efficiency reasons, each module is only imported once per interpreter For efficiency reasons, each module is only imported once per interpreter
...@@ -445,14 +449,9 @@ Importing \* From a Package ...@@ -445,14 +449,9 @@ Importing \* From a Package
Now what happens when the user writes ``from sound.effects import *``? Ideally, Now what happens when the user writes ``from sound.effects import *``? Ideally,
one would hope that this somehow goes out to the filesystem, finds which one would hope that this somehow goes out to the filesystem, finds which
submodules are present in the package, and imports them all. Unfortunately, submodules are present in the package, and imports them all. This could take a
this operation does not work very well on Windows platforms, where the long time and importing sub-modules might have unwanted side-effects that should
filesystem does not always have accurate information about the case of a only happen when the sub-module is explicitly imported.
filename. On these platforms, there is no guaranteed way to know whether a file
:file:`ECHO.PY` should be imported as a module :mod:`echo`, :mod:`Echo` or
:mod:`ECHO`. (For example, Windows 95 has the annoying practice of showing all
file names with a capitalized first letter.) The DOS 8+3 filename restriction
adds another interesting problem for long module names.
The only solution is for the package author to provide an explicit index of the The only solution is for the package author to provide an explicit index of the
package. The :keyword:`import` statement uses the following convention: if a package's package. The :keyword:`import` statement uses the following convention: if a package's
...@@ -487,10 +486,9 @@ current namespace because they are defined in the :mod:`sound.effects` package ...@@ -487,10 +486,9 @@ current namespace because they are defined in the :mod:`sound.effects` package
when the ``from...import`` statement is executed. (This also works when when the ``from...import`` statement is executed. (This also works when
``__all__`` is defined.) ``__all__`` is defined.)
Note that in general the practice of importing ``*`` from a module or package is Although certain modules are designed to export only names that follow certain
frowned upon, since it often causes poorly readable code. However, it is okay to patterns when you use ``import *``, it is still considered bad practise in
use it to save typing in interactive sessions, and certain modules are designed production code.
to export only names that follow certain patterns.
Remember, there is nothing wrong with using ``from Package import Remember, there is nothing wrong with using ``from Package import
specific_submodule``! In fact, this is the recommended notation unless the specific_submodule``! In fact, this is the recommended notation unless the
......
...@@ -505,6 +505,13 @@ changes, or look through the Subversion logs for all the details. ...@@ -505,6 +505,13 @@ changes, or look through the Subversion logs for all the details.
differences. :meth:`assertDictContainsSubset` checks whether differences. :meth:`assertDictContainsSubset` checks whether
all of the key/value pairs in *first* are found in *second*. all of the key/value pairs in *first* are found in *second*.
* :meth:`assertAlmostEqual` and :meth:`assertNotAlmostEqual` short-circuit
(automatically pass or fail without checking decimal places) if the objects
are equal.
* :meth:`loadTestsFromName` properly honors the ``suiteClass`` attribute of
the :class:`TestLoader`. (Fixed by Mark Roddy; :issue:`6866`.)
* A new hook, :meth:`addTypeEqualityFunc` takes a type object and a * A new hook, :meth:`addTypeEqualityFunc` takes a type object and a
function. The :meth:`assertEqual` method will use the function function. The :meth:`assertEqual` method will use the function
when both of the objects being compared are of the specified type. when both of the objects being compared are of the specified type.
......
...@@ -165,7 +165,7 @@ class Sniffer: ...@@ -165,7 +165,7 @@ class Sniffer:
Returns a dialect (or None) corresponding to the sample Returns a dialect (or None) corresponding to the sample
""" """
quotechar, delimiter, skipinitialspace = \ quotechar, doublequote, delimiter, skipinitialspace = \
self._guess_quote_and_delimiter(sample, delimiters) self._guess_quote_and_delimiter(sample, delimiters)
if not delimiter: if not delimiter:
delimiter, skipinitialspace = self._guess_delimiter(sample, delimiter, skipinitialspace = self._guess_delimiter(sample,
...@@ -179,8 +179,8 @@ class Sniffer: ...@@ -179,8 +179,8 @@ class Sniffer:
lineterminator = '\r\n' lineterminator = '\r\n'
quoting = QUOTE_MINIMAL quoting = QUOTE_MINIMAL
# escapechar = '' # escapechar = ''
doublequote = False
dialect.doublequote = doublequote
dialect.delimiter = delimiter dialect.delimiter = delimiter
# _csv.reader won't accept a quotechar of '' # _csv.reader won't accept a quotechar of ''
dialect.quotechar = quotechar or '"' dialect.quotechar = quotechar or '"'
...@@ -212,8 +212,8 @@ class Sniffer: ...@@ -212,8 +212,8 @@ class Sniffer:
break break
if not matches: if not matches:
return ('', None, 0) # (quotechar, delimiter, skipinitialspace) # (quotechar, doublequote, delimiter, skipinitialspace)
return ('', False, None, 0)
quotes = {} quotes = {}
delims = {} delims = {}
spaces = 0 spaces = 0
...@@ -248,7 +248,19 @@ class Sniffer: ...@@ -248,7 +248,19 @@ class Sniffer:
delim = '' delim = ''
skipinitialspace = 0 skipinitialspace = 0
return (quotechar, delim, skipinitialspace) # if we see an extra quote between delimiters, we've got a
# double quoted format
dq_regexp = re.compile(r"((%(delim)s)|^)\W*%(quote)s[^%(delim)s\n]*%(quote)s[^%(delim)s\n]*%(quote)s\W*((%(delim)s)|$)" % \
{'delim':delim, 'quote':quotechar}, re.MULTILINE)
if dq_regexp.search(data):
doublequote = True
else:
doublequote = False
return (quotechar, doublequote, delim, skipinitialspace)
def _guess_delimiter(self, data, delimiters): def _guess_delimiter(self, data, delimiters):
......
...@@ -51,7 +51,7 @@ def unix_getpass(prompt='Password: ', stream=None): ...@@ -51,7 +51,7 @@ def unix_getpass(prompt='Password: ', stream=None):
# If that fails, see if stdin can be controlled. # If that fails, see if stdin can be controlled.
try: try:
fd = sys.stdin.fileno() fd = sys.stdin.fileno()
except: except (AttributeError, ValueError):
passwd = fallback_getpass(prompt, stream) passwd = fallback_getpass(prompt, stream)
input = sys.stdin input = sys.stdin
if not stream: if not stream:
......
...@@ -398,12 +398,12 @@ def getfile(object): ...@@ -398,12 +398,12 @@ def getfile(object):
if ismodule(object): if ismodule(object):
if hasattr(object, '__file__'): if hasattr(object, '__file__'):
return object.__file__ return object.__file__
raise TypeError('arg is a built-in module') raise TypeError('{!r} is a built-in module'.format(object))
if isclass(object): if isclass(object):
object = sys.modules.get(object.__module__) object = sys.modules.get(object.__module__)
if hasattr(object, '__file__'): if hasattr(object, '__file__'):
return object.__file__ return object.__file__
raise TypeError('arg is a built-in class') raise TypeError('{!r} is a built-in class'.format(object))
if ismethod(object): if ismethod(object):
object = object.__func__ object = object.__func__
if isfunction(object): if isfunction(object):
...@@ -414,8 +414,8 @@ def getfile(object): ...@@ -414,8 +414,8 @@ def getfile(object):
object = object.f_code object = object.f_code
if iscode(object): if iscode(object):
return object.co_filename return object.co_filename
raise TypeError('arg is not a module, class, method, ' raise TypeError('{!r} is not a module, class, method, '
'function, traceback, frame, or code object') 'function, traceback, frame, or code object'.format(object))
ModuleInfo = namedtuple('ModuleInfo', 'name suffix mode module_type') ModuleInfo = namedtuple('ModuleInfo', 'name suffix mode module_type')
...@@ -747,7 +747,7 @@ def _getfullargs(co): ...@@ -747,7 +747,7 @@ def _getfullargs(co):
names of the * and ** arguments or None.""" names of the * and ** arguments or None."""
if not iscode(co): if not iscode(co):
raise TypeError('arg is not a code object') raise TypeError('{!r} is not a code object'.format(co))
nargs = co.co_argcount nargs = co.co_argcount
names = co.co_varnames names = co.co_varnames
...@@ -811,7 +811,7 @@ def getfullargspec(func): ...@@ -811,7 +811,7 @@ def getfullargspec(func):
if ismethod(func): if ismethod(func):
func = func.__func__ func = func.__func__
if not isfunction(func): if not isfunction(func):
raise TypeError('arg is not a Python function') raise TypeError('{!r} is not a Python function'.format(func))
args, varargs, kwonlyargs, varkw = _getfullargs(func.__code__) args, varargs, kwonlyargs, varkw = _getfullargs(func.__code__)
return FullArgSpec(args, varargs, varkw, func.__defaults__, return FullArgSpec(args, varargs, varkw, func.__defaults__,
kwonlyargs, func.__kwdefaults__, func.__annotations__) kwonlyargs, func.__kwdefaults__, func.__annotations__)
...@@ -944,7 +944,7 @@ def getframeinfo(frame, context=1): ...@@ -944,7 +944,7 @@ def getframeinfo(frame, context=1):
else: else:
lineno = frame.f_lineno lineno = frame.f_lineno
if not isframe(frame): if not isframe(frame):
raise TypeError('arg is not a frame or traceback object') raise TypeError('{!r} is not a frame or traceback object'.format(frame))
filename = getsourcefile(frame) or getfile(frame) filename = getsourcefile(frame) or getfile(frame)
if context > 0: if context > 0:
......
...@@ -282,10 +282,13 @@ class LogRecord: ...@@ -282,10 +282,13 @@ class LogRecord:
else: else:
self.thread = None self.thread = None
self.threadName = None self.threadName = None
if logMultiprocessing: if not logMultiprocessing:
self.processName = None
else:
try:
from multiprocessing import current_process from multiprocessing import current_process
self.processName = current_process().name self.processName = current_process().name
else: except ImportError:
self.processName = None self.processName = None
if logProcesses and hasattr(os, 'getpid'): if logProcesses and hasattr(os, 'getpid'):
self.process = os.getpid() self.process = os.getpid()
...@@ -745,16 +748,16 @@ class StreamHandler(Handler): ...@@ -745,16 +748,16 @@ class StreamHandler(Handler):
sys.stdout or sys.stderr may be used. sys.stdout or sys.stderr may be used.
""" """
def __init__(self, strm=None): def __init__(self, stream=None):
""" """
Initialize the handler. Initialize the handler.
If strm is not specified, sys.stderr is used. If stream is not specified, sys.stderr is used.
""" """
Handler.__init__(self) Handler.__init__(self)
if strm is None: if stream is None:
strm = sys.stderr stream = sys.stderr
self.stream = strm self.stream = stream
def flush(self): def flush(self):
""" """
...@@ -1124,7 +1127,11 @@ class Logger(Filterer): ...@@ -1124,7 +1127,11 @@ class Logger(Filterer):
Find the stack frame of the caller so that we can note the source Find the stack frame of the caller so that we can note the source
file name, line number and function name. file name, line number and function name.
""" """
f = currentframe().f_back f = currentframe()
#On some versions of IronPython, currentframe() returns None if
#IronPython isn't run with -X:Frames.
if f is not None:
f = f.f_back
rv = "(unknown file)", 0, "(unknown function)" rv = "(unknown file)", 0, "(unknown function)"
while hasattr(f, "f_code"): while hasattr(f, "f_code"):
co = f.f_code co = f.f_code
...@@ -1156,7 +1163,8 @@ class Logger(Filterer): ...@@ -1156,7 +1163,8 @@ class Logger(Filterer):
""" """
if _srcfile: if _srcfile:
#IronPython doesn't track Python frames, so findCaller throws an #IronPython doesn't track Python frames, so findCaller throws an
#exception. We trap it here so that IronPython can use logging. #exception on some versions of IronPython. We trap it here so that
#IronPython can use logging.
try: try:
fn, lno, func = self.findCaller() fn, lno, func = self.findCaller()
except ValueError: except ValueError:
......
...@@ -413,7 +413,7 @@ class Server(object): ...@@ -413,7 +413,7 @@ class Server(object):
self.id_to_refcount[ident] -= 1 self.id_to_refcount[ident] -= 1
if self.id_to_refcount[ident] == 0: if self.id_to_refcount[ident] == 0:
del self.id_to_obj[ident], self.id_to_refcount[ident] del self.id_to_obj[ident], self.id_to_refcount[ident]
util.debug('disposing of obj with id %d', ident) util.debug('disposing of obj with id %r', ident)
finally: finally:
self.mutex.release() self.mutex.release()
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
""" """
# This module is maintained by Marc-Andre Lemburg <mal@egenix.com>. # This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
# If you find problems, please submit bug reports/patches via the # If you find problems, please submit bug reports/patches via the
# Python SourceForge Project Page and assign them to "lemburg". # Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
# #
# Still needed: # Still needed:
# * more support for WinCE # * more support for WinCE
......
...@@ -82,6 +82,7 @@ class AllTest(unittest.TestCase): ...@@ -82,6 +82,7 @@ class AllTest(unittest.TestCase):
self.check_all("keyword") self.check_all("keyword")
self.check_all("linecache") self.check_all("linecache")
self.check_all("locale") self.check_all("locale")
self.check_all("logging")
self.check_all("macpath") self.check_all("macpath")
self.check_all("macurl2path") self.check_all("macurl2path")
self.check_all("mailbox") self.check_all("mailbox")
......
...@@ -767,7 +767,7 @@ Stonecutters Seafood and Chop House, Lemont, IL, 12/19/02, Week Back ...@@ -767,7 +767,7 @@ Stonecutters Seafood and Chop House, Lemont, IL, 12/19/02, Week Back
'Harry''s':'Arlington Heights':'IL':'2/1/03':'Kimi Hayes' 'Harry''s':'Arlington Heights':'IL':'2/1/03':'Kimi Hayes'
'Shark City':'Glendale Heights':'IL':'12/28/02':'Prezence' 'Shark City':'Glendale Heights':'IL':'12/28/02':'Prezence'
'Tommy''s Place':'Blue Island':'IL':'12/28/02':'Blue Sunday/White Crow' 'Tommy''s Place':'Blue Island':'IL':'12/28/02':'Blue Sunday/White Crow'
'Stonecutters Seafood and Chop House':'Lemont':'IL':'12/19/02':'Week Back' 'Stonecutters ''Seafood'' and Chop House':'Lemont':'IL':'12/19/02':'Week Back'
""" """
header = '''\ header = '''\
"venue","city","state","date","performers" "venue","city","state","date","performers"
...@@ -826,6 +826,13 @@ Stonecutters Seafood and Chop House, Lemont, IL, 12/19/02, Week Back ...@@ -826,6 +826,13 @@ Stonecutters Seafood and Chop House, Lemont, IL, 12/19/02, Week Back
self.assertEqual(dialect.delimiter, "|") self.assertEqual(dialect.delimiter, "|")
self.assertEqual(dialect.quotechar, "'") self.assertEqual(dialect.quotechar, "'")
def test_doublequote(self):
sniffer = csv.Sniffer()
dialect = sniffer.sniff(self.header)
self.assertFalse(dialect.doublequote)
dialect = sniffer.sniff(self.sample2)
self.assertTrue(dialect.doublequote)
if not hasattr(sys, "gettotalrefcount"): if not hasattr(sys, "gettotalrefcount"):
if support.verbose: print("*** skipping leakage tests ***") if support.verbose: print("*** skipping leakage tests ***")
else: else:
......
...@@ -291,7 +291,7 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -291,7 +291,7 @@ class GeneralModuleTests(unittest.TestCase):
# On some versions, this loses a reference # On some versions, this loses a reference
orig = sys.getrefcount(__name__) orig = sys.getrefcount(__name__)
socket.getnameinfo(__name__,0) socket.getnameinfo(__name__,0)
except SystemError: except TypeError:
if sys.getrefcount(__name__) != orig: if sys.getrefcount(__name__) != orig:
self.fail("socket.getnameinfo loses a reference") self.fail("socket.getnameinfo loses a reference")
......
...@@ -554,6 +554,47 @@ class Test_TestLoader(TestCase): ...@@ -554,6 +554,47 @@ class Test_TestLoader(TestCase):
self.assertTrue(isinstance(suite, loader.suiteClass)) self.assertTrue(isinstance(suite, loader.suiteClass))
self.assertEqual(list(suite), [testcase_1]) self.assertEqual(list(suite), [testcase_1])
# "The specifier name is a ``dotted name'' that may resolve ... to
# ... a callable object which returns a TestCase ... instance"
#*****************************************************************
#Override the suiteClass attribute to ensure that the suiteClass
#attribute is used
def test_loadTestsFromName__callable__TestCase_instance_ProperSuiteClass(self):
class SubTestSuite(unittest.TestSuite):
pass
m = types.ModuleType('m')
testcase_1 = unittest.FunctionTestCase(lambda: None)
def return_TestCase():
return testcase_1
m.return_TestCase = return_TestCase
loader = unittest.TestLoader()
loader.suiteClass = SubTestSuite
suite = loader.loadTestsFromName('return_TestCase', m)
self.assertTrue(isinstance(suite, loader.suiteClass))
self.assertEqual(list(suite), [testcase_1])
# "The specifier name is a ``dotted name'' that may resolve ... to
# ... a test method within a test case class"
#*****************************************************************
#Override the suiteClass attribute to ensure that the suiteClass
#attribute is used
def test_loadTestsFromName__relative_testmethod_ProperSuiteClass(self):
class SubTestSuite(unittest.TestSuite):
pass
m = types.ModuleType('m')
class MyTestCase(unittest.TestCase):
def test(self):
pass
m.testcase_1 = MyTestCase
loader = unittest.TestLoader()
loader.suiteClass=SubTestSuite
suite = loader.loadTestsFromName('testcase_1.test', m)
self.assertTrue(isinstance(suite, loader.suiteClass))
self.assertEqual(list(suite), [MyTestCase('test')])
# "The specifier name is a ``dotted name'' that may resolve ... to # "The specifier name is a ``dotted name'' that may resolve ... to
# ... a callable object which returns a TestCase or TestSuite instance" # ... a callable object which returns a TestCase or TestSuite instance"
# #
...@@ -2953,6 +2994,11 @@ class Test_Assertions(TestCase): ...@@ -2953,6 +2994,11 @@ class Test_Assertions(TestCase):
self.assertRaises(self.failureException, self.assertRaises(self.failureException,
self.assertNotAlmostEqual, 0, .1+.1j, places=0) self.assertNotAlmostEqual, 0, .1+.1j, places=0)
self.assertAlmostEqual(float('inf'), float('inf'))
self.assertRaises(self.failureException, self.assertNotAlmostEqual,
float('inf'), float('inf'))
def test_assertRaises(self): def test_assertRaises(self):
def _raise(e): def _raise(e):
raise e raise e
...@@ -3387,31 +3433,18 @@ class Test_TextTestRunner(TestCase): ...@@ -3387,31 +3433,18 @@ class Test_TextTestRunner(TestCase):
class TestDiscovery(TestCase): class TestDiscovery(TestCase):
# Heavily mocked tests so I can avoid hitting the filesystem # Heavily mocked tests so I can avoid hitting the filesystem
def test_get_module_from_path(self): def test_get_name_from_path(self):
loader = unittest.TestLoader() loader = unittest.TestLoader()
old_import = __import__
def restore_import():
builtins.__import__ = old_import
builtins.__import__ = lambda *_: None
self.addCleanup(restore_import)
expected_module = object()
def del_module():
del sys.modules['bar.baz']
sys.modules['bar.baz'] = expected_module
self.addCleanup(del_module)
loader._top_level_dir = '/foo' loader._top_level_dir = '/foo'
module = loader._get_module_from_path('/foo/bar/baz.py') name = loader._get_name_from_path('/foo/bar/baz.py')
self.assertEqual(module, expected_module) self.assertEqual(name, 'bar.baz')
if not __debug__: if not __debug__:
# asserts are off # asserts are off
return return
with self.assertRaises(AssertionError): with self.assertRaises(AssertionError):
loader._get_module_from_path('/bar/baz.py') loader._get_name_from_path('/bar/baz.py')
def test_find_tests(self): def test_find_tests(self):
loader = unittest.TestLoader() loader = unittest.TestLoader()
...@@ -3427,7 +3460,7 @@ class TestDiscovery(TestCase): ...@@ -3427,7 +3460,7 @@ class TestDiscovery(TestCase):
os.path.isdir = original_isdir os.path.isdir = original_isdir
path_lists = [['test1.py', 'test2.py', 'not_a_test.py', 'test_dir', path_lists = [['test1.py', 'test2.py', 'not_a_test.py', 'test_dir',
'test.foo', 'another_dir'], 'test.foo', 'test-not-a-module.py', 'another_dir'],
['test3.py', 'test4.py', ]] ['test3.py', 'test4.py', ]]
os.listdir = lambda path: path_lists.pop(0) os.listdir = lambda path: path_lists.pop(0)
self.addCleanup(restore_listdir) self.addCleanup(restore_listdir)
...@@ -3443,16 +3476,16 @@ class TestDiscovery(TestCase): ...@@ -3443,16 +3476,16 @@ class TestDiscovery(TestCase):
os.path.isfile = isfile os.path.isfile = isfile
self.addCleanup(restore_isfile) self.addCleanup(restore_isfile)
loader._get_module_from_path = lambda path: path + ' module' loader._get_module_from_name = lambda path: path + ' module'
loader.loadTestsFromModule = lambda module: module + ' tests' loader.loadTestsFromModule = lambda module: module + ' tests'
loader._top_level_dir = '/foo' loader._top_level_dir = '/foo'
suite = list(loader._find_tests('/foo', 'test*.py')) suite = list(loader._find_tests('/foo', 'test*.py'))
expected = [os.path.join('/foo', name) + ' module tests' for name in expected = [name + ' module tests' for name in
('test1.py', 'test2.py')] ('test1', 'test2')]
expected.extend([os.path.join('/foo', 'test_dir', name) + ' module tests' for name in expected.extend([('test_dir.%s' % name) + ' module tests' for name in
('test3.py', 'test4.py')]) ('test3', 'test4')])
self.assertEqual(suite, expected) self.assertEqual(suite, expected)
def test_find_tests_with_package(self): def test_find_tests_with_package(self):
...@@ -3495,7 +3528,7 @@ class TestDiscovery(TestCase): ...@@ -3495,7 +3528,7 @@ class TestDiscovery(TestCase):
def __eq__(self, other): def __eq__(self, other):
return self.path == other.path return self.path == other.path
loader._get_module_from_path = lambda path: Module(path) loader._get_module_from_name = lambda name: Module(name)
def loadTestsFromModule(module, use_load_tests): def loadTestsFromModule(module, use_load_tests):
if use_load_tests: if use_load_tests:
raise self.failureException('use_load_tests should be False for packages') raise self.failureException('use_load_tests should be False for packages')
...@@ -3510,15 +3543,12 @@ class TestDiscovery(TestCase): ...@@ -3510,15 +3543,12 @@ class TestDiscovery(TestCase):
# We should have loaded tests from the test_directory package by calling load_tests # We should have loaded tests from the test_directory package by calling load_tests
# and directly from the test_directory2 package # and directly from the test_directory2 package
self.assertEqual(suite, self.assertEqual(suite,
['load_tests', ['load_tests', 'test_directory2' + ' module tests'])
os.path.join('/foo', 'test_directory2') + ' module tests']) self.assertEqual(Module.paths, ['test_directory', 'test_directory2'])
self.assertEqual(Module.paths, [os.path.join('/foo', 'test_directory'),
os.path.join('/foo', 'test_directory2')])
# load_tests should have been called once with loader, tests and pattern # load_tests should have been called once with loader, tests and pattern
self.assertEqual(Module.load_tests_args, self.assertEqual(Module.load_tests_args,
[(loader, os.path.join('/foo', 'test_directory') + ' module tests', [(loader, 'test_directory' + ' module tests', 'test*')])
'test*')])
def test_discover(self): def test_discover(self):
loader = unittest.TestLoader() loader = unittest.TestLoader()
...@@ -3558,6 +3588,25 @@ class TestDiscovery(TestCase): ...@@ -3558,6 +3588,25 @@ class TestDiscovery(TestCase):
self.assertEqual(loader._top_level_dir, top_level_dir) self.assertEqual(loader._top_level_dir, top_level_dir)
self.assertEqual(_find_tests_args, [(start_dir, 'pattern')]) self.assertEqual(_find_tests_args, [(start_dir, 'pattern')])
def test_discover_with_modules_that_fail_to_import(self):
loader = unittest.TestLoader()
listdir = os.listdir
os.listdir = lambda _: ['test_this_does_not_exist.py']
isfile = os.path.isfile
os.path.isfile = lambda _: True
def restore():
os.path.isfile = isfile
os.listdir = listdir
self.addCleanup(restore)
suite = loader.discover('.')
self.assertEqual(suite.countTestCases(), 1)
test = list(list(suite)[0])[0] # extract test from suite
with self.assertRaises(ImportError):
test.test_this_does_not_exist()
def test_command_line_handling_parseArgs(self): def test_command_line_handling_parseArgs(self):
# Haha - take that uninstantiable class # Haha - take that uninstantiable class
program = object.__new__(TestProgram) program = object.__new__(TestProgram)
......
...@@ -135,7 +135,7 @@ class TextWrapper: ...@@ -135,7 +135,7 @@ class TextWrapper:
"""_split(text : string) -> [string] """_split(text : string) -> [string]
Split the text to wrap into indivisible chunks. Chunks are Split the text to wrap into indivisible chunks. Chunks are
not quite the same as words; see wrap_chunks() for full not quite the same as words; see _wrap_chunks() for full
details. As an example, the text details. As an example, the text
Look, goof-ball -- use the -b option! Look, goof-ball -- use the -b option!
breaks into the following chunks: breaks into the following chunks:
...@@ -163,9 +163,9 @@ class TextWrapper: ...@@ -163,9 +163,9 @@ class TextWrapper:
space to two. space to two.
""" """
i = 0 i = 0
pat = self.sentence_end_re patsearch = self.sentence_end_re.search
while i < len(chunks)-1: while i < len(chunks)-1:
if chunks[i+1] == " " and pat.search(chunks[i]): if chunks[i+1] == " " and patsearch(chunks[i]):
chunks[i+1] = " " chunks[i+1] = " "
i += 2 i += 2
else: else:
......
...@@ -468,7 +468,13 @@ class TestCase(object): ...@@ -468,7 +468,13 @@ class TestCase(object):
Note that decimal places (from zero) are usually not the same Note that decimal places (from zero) are usually not the same
as significant digits (measured from the most signficant digit). as significant digits (measured from the most signficant digit).
If the two objects compare equal then they will automatically
compare almost equal.
""" """
if first == second:
# shortcut for ite
return
if round(abs(second-first), places) != 0: if round(abs(second-first), places) != 0:
standardMsg = '%r != %r within %r places' % (first, second, places) standardMsg = '%r != %r within %r places' % (first, second, places)
msg = self._formatMessage(msg, standardMsg) msg = self._formatMessage(msg, standardMsg)
...@@ -481,8 +487,10 @@ class TestCase(object): ...@@ -481,8 +487,10 @@ class TestCase(object):
Note that decimal places (from zero) are usually not the same Note that decimal places (from zero) are usually not the same
as significant digits (measured from the most signficant digit). as significant digits (measured from the most signficant digit).
Objects that are equal automatically fail.
""" """
if round(abs(second-first), places) == 0: if (first == second) or round(abs(second-first), places) == 0:
standardMsg = '%r == %r within %r places' % (first, second, places) standardMsg = '%r == %r within %r places' % (first, second, places)
msg = self._formatMessage(msg, standardMsg) msg = self._formatMessage(msg, standardMsg)
raise self.failureException(msg) raise self.failureException(msg)
......
"""Loading unittests.""" """Loading unittests."""
import os import os
import re
import sys import sys
import traceback
import types import types
from fnmatch import fnmatch from fnmatch import fnmatch
...@@ -9,6 +11,26 @@ from fnmatch import fnmatch ...@@ -9,6 +11,26 @@ from fnmatch import fnmatch
from . import case, suite, util from . import case, suite, util
# what about .pyc or .pyo (etc)
# we would need to avoid loading the same tests multiple times
# from '.py', '.pyc' *and* '.pyo'
VALID_MODULE_NAME = re.compile(r'[_a-z]\w*\.py$', re.IGNORECASE)
def _make_failed_import_test(name, suiteClass):
message = 'Failed to import test module: %s' % name
if hasattr(traceback, 'format_exc'):
# Python 2.3 compatibility
# format_exc returns two frames of discover.py as well
message += '\n%s' % traceback.format_exc()
def testImportFailure(self):
raise ImportError(message)
attrs = {name: testImportFailure}
ModuleImportFailure = type('ModuleImportFailure', (case.TestCase,), attrs)
return suiteClass((ModuleImportFailure(name),))
class TestLoader(object): class TestLoader(object):
""" """
This class is responsible for loading tests according to various criteria This class is responsible for loading tests according to various criteria
...@@ -79,7 +101,7 @@ class TestLoader(object): ...@@ -79,7 +101,7 @@ class TestLoader(object):
inst = parent(name) inst = parent(name)
# static methods follow a different path # static methods follow a different path
if not isinstance(getattr(inst, name), types.FunctionType): if not isinstance(getattr(inst, name), types.FunctionType):
return suite.TestSuite([inst]) return self.suiteClass([inst])
elif isinstance(obj, suite.TestSuite): elif isinstance(obj, suite.TestSuite):
return obj return obj
if hasattr(obj, '__call__'): if hasattr(obj, '__call__'):
...@@ -87,7 +109,7 @@ class TestLoader(object): ...@@ -87,7 +109,7 @@ class TestLoader(object):
if isinstance(test, suite.TestSuite): if isinstance(test, suite.TestSuite):
return test return test
elif isinstance(test, case.TestCase): elif isinstance(test, case.TestCase):
return suite.TestSuite([test]) return self.suiteClass([test])
else: else:
raise TypeError("calling %s returned %s, not a test" % raise TypeError("calling %s returned %s, not a test" %
(obj, test)) (obj, test))
...@@ -156,17 +178,17 @@ class TestLoader(object): ...@@ -156,17 +178,17 @@ class TestLoader(object):
tests = list(self._find_tests(start_dir, pattern)) tests = list(self._find_tests(start_dir, pattern))
return self.suiteClass(tests) return self.suiteClass(tests)
def _get_name_from_path(self, path):
def _get_module_from_path(self, path):
"""Load a module from a path relative to the top-level directory
of a project. Used by discovery."""
path = os.path.splitext(os.path.normpath(path))[0] path = os.path.splitext(os.path.normpath(path))[0]
relpath = os.path.relpath(path, self._top_level_dir) _relpath = os.path.relpath(path, self._top_level_dir)
assert not os.path.isabs(relpath), "Path must be within the project" assert not os.path.isabs(_relpath), "Path must be within the project"
assert not relpath.startswith('..'), "Path must be within the project" assert not _relpath.startswith('..'), "Path must be within the project"
name = relpath.replace(os.path.sep, '.') name = _relpath.replace(os.path.sep, '.')
return name
def _get_module_from_name(self, name):
__import__(name) __import__(name)
return sys.modules[name] return sys.modules[name]
...@@ -176,13 +198,19 @@ class TestLoader(object): ...@@ -176,13 +198,19 @@ class TestLoader(object):
for path in paths: for path in paths:
full_path = os.path.join(start_dir, path) full_path = os.path.join(start_dir, path)
# what about __init__.pyc or pyo (etc) if os.path.isfile(full_path):
# we would need to avoid loading the same tests multiple times if not VALID_MODULE_NAME.match(path):
# from '.py', '.pyc' *and* '.pyo' # valid Python identifiers only
if os.path.isfile(full_path) and path.lower().endswith('.py'): continue
if fnmatch(path, pattern): if fnmatch(path, pattern):
# if the test file matches, load it # if the test file matches, load it
module = self._get_module_from_path(full_path) name = self._get_name_from_path(full_path)
try:
module = self._get_module_from_name(name)
except:
yield _make_failed_import_test(name, self.suiteClass)
else:
yield self.loadTestsFromModule(module) yield self.loadTestsFromModule(module)
elif os.path.isdir(full_path): elif os.path.isdir(full_path):
if not os.path.isfile(os.path.join(full_path, '__init__.py')): if not os.path.isfile(os.path.join(full_path, '__init__.py')):
...@@ -192,7 +220,8 @@ class TestLoader(object): ...@@ -192,7 +220,8 @@ class TestLoader(object):
tests = None tests = None
if fnmatch(path, pattern): if fnmatch(path, pattern):
# only check load_tests if the package directory itself matches the filter # only check load_tests if the package directory itself matches the filter
package = self._get_module_from_path(full_path) name = self._get_name_from_path(full_path)
package = self._get_module_from_name(name)
load_tests = getattr(package, 'load_tests', None) load_tests = getattr(package, 'load_tests', None)
tests = self.loadTestsFromModule(package, use_load_tests=False) tests = self.loadTestsFromModule(package, use_load_tests=False)
......
...@@ -109,9 +109,9 @@ class TestProgram(object): ...@@ -109,9 +109,9 @@ class TestProgram(object):
if opt in ('-v','--verbose'): if opt in ('-v','--verbose'):
self.verbosity = 2 self.verbosity = 2
if len(args) == 0 and self.defaultTest is None: if len(args) == 0 and self.defaultTest is None:
self.test = self.testLoader.loadTestsFromModule(self.module) # createTests will load tests from self.module
return self.testNames = None
if len(args) > 0: elif len(args) > 0:
self.testNames = args self.testNames = args
if __name__ == '__main__': if __name__ == '__main__':
# to support python -m unittest ... # to support python -m unittest ...
...@@ -123,6 +123,9 @@ class TestProgram(object): ...@@ -123,6 +123,9 @@ class TestProgram(object):
self.usageExit(msg) self.usageExit(msg)
def createTests(self): def createTests(self):
if self.testNames is None:
self.test = self.testLoader.loadTestsFromModule(self.module)
else:
self.test = self.testLoader.loadTestsFromNames(self.testNames, self.test = self.testLoader.loadTestsFromNames(self.testNames,
self.module) self.module)
......
"""TestSuite""" """TestSuite"""
from . import case from . import case
from . import util
class TestSuite(object): class TestSuite(object):
...@@ -17,7 +18,7 @@ class TestSuite(object): ...@@ -17,7 +18,7 @@ class TestSuite(object):
self.addTests(tests) self.addTests(tests)
def __repr__(self): def __repr__(self):
return "<%s tests=%s>" % (_strclass(self.__class__), list(self)) return "<%s tests=%s>" % (util.strclass(self.__class__), list(self))
def __eq__(self, other): def __eq__(self, other):
if not isinstance(other, self.__class__): if not isinstance(other, self.__class__):
......
...@@ -20,6 +20,9 @@ for details. When the agreement is signed, please note it in this log. ...@@ -20,6 +20,9 @@ for details. When the agreement is signed, please note it in this log.
Permissions History Permissions History
------------------- -------------------
- Doug Hellmann was given SVN access on September 19 2009 by GFB, at
suggestion of Jesse Noller, for documentation work.
- Ezio Melotti was given SVN access on June 7 2009 by GFB, for work on and - Ezio Melotti was given SVN access on June 7 2009 by GFB, for work on and
fixes to the documentation. fixes to the documentation.
...@@ -109,6 +112,13 @@ Permissions History ...@@ -109,6 +112,13 @@ Permissions History
- Jeffrey Yasskin was given SVN access on 9 August 2007 by NCN, - Jeffrey Yasskin was given SVN access on 9 August 2007 by NCN,
for his work on PEPs and other general patches. for his work on PEPs and other general patches.
- Mark Summerfield was given SVN access on 1 August 2007 by GFB,
for work on documentation.
- Armin Ronacher was given SVN access on 23 July 2007 by GFB,
for work on the documentation toolset. He now maintains the
ast module.
- Senthil Kumaran was given SVN access on 16 June 2007 by MvL, - Senthil Kumaran was given SVN access on 16 June 2007 by MvL,
for his Summer-of-Code project, mentored by Skip Montanaro. for his Summer-of-Code project, mentored by Skip Montanaro.
......
...@@ -3909,6 +3909,11 @@ socket_getnameinfo(PyObject *self, PyObject *args) ...@@ -3909,6 +3909,11 @@ socket_getnameinfo(PyObject *self, PyObject *args)
flags = flowinfo = scope_id = 0; flags = flowinfo = scope_id = 0;
if (!PyArg_ParseTuple(args, "Oi:getnameinfo", &sa, &flags)) if (!PyArg_ParseTuple(args, "Oi:getnameinfo", &sa, &flags))
return NULL; return NULL;
if (!PyTuple_Check(sa)) {
PyErr_SetString(PyExc_TypeError,
"getnameinfo() argument 1 must be a tuple");
return NULL;
}
if (!PyArg_ParseTuple(sa, "si|ii", if (!PyArg_ParseTuple(sa, "si|ii",
&hostp, &port, &flowinfo, &scope_id)) &hostp, &port, &flowinfo, &scope_id))
return NULL; return NULL;
...@@ -3933,9 +3938,7 @@ socket_getnameinfo(PyObject *self, PyObject *args) ...@@ -3933,9 +3938,7 @@ socket_getnameinfo(PyObject *self, PyObject *args)
switch (res->ai_family) { switch (res->ai_family) {
case AF_INET: case AF_INET:
{ {
char *t1; if (PyTuple_GET_SIZE(sa) != 2) {
int t2;
if (PyArg_ParseTuple(sa, "si", &t1, &t2) == 0) {
PyErr_SetString(socket_error, PyErr_SetString(socket_error,
"IPv4 sockaddr must be 2 tuple"); "IPv4 sockaddr must be 2 tuple");
goto fail; goto fail;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment