From dae2a8939df14692b59d66b13c587a0a4197700e Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sat, 19 Apr 2008 00:55:37 +0000 Subject: Merged revisions 62350-62355,62358-62359,62364-62365,62370,62372-62375,62378-62379,62381 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r62350 | nick.coghlan | 2008-04-15 12:25:31 +0200 (Tue, 15 Apr 2008) | 1 line Issue 2439: add pkgutils.get_data() as a convenience wrapper for the PEP 302 get_data() API (contributed by Paul Moore) ........ r62351 | nick.coghlan | 2008-04-15 12:28:14 +0200 (Tue, 15 Apr 2008) | 1 line Add test file missing from rev 62350 ........ r62352 | benjamin.peterson | 2008-04-15 13:58:46 +0200 (Tue, 15 Apr 2008) | 2 lines Add myself to Doc/ACKS.txt ........ r62353 | andrew.kuchling | 2008-04-15 15:10:07 +0200 (Tue, 15 Apr 2008) | 6 lines Add *,**,@ to index, as suggested by http://farmdev.com/thoughts/24/what-does-the-def-star-variable-or-def-asterisk-parameter-syntax-do-in-python-/ The right entry type to use isn't clear; operator seems wrong, because *,**,@ aren't being used in expressions here. I put them as 'statement'; 'syntax' might be better. ........ r62354 | andrew.kuchling | 2008-04-15 15:10:41 +0200 (Tue, 15 Apr 2008) | 1 line Typo fix ........ r62355 | mark.dickinson | 2008-04-15 22:51:18 +0200 (Tue, 15 Apr 2008) | 3 lines Fix for possible signed overflow: the behaviour of -LONG_MIN is undefined in ANSI C. ........ r62358 | jeroen.ruigrok | 2008-04-16 14:47:01 +0200 (Wed, 16 Apr 2008) | 2 lines Reformat to 80 columns prior to adding documentation. ........ r62359 | jeroen.ruigrok | 2008-04-16 14:57:43 +0200 (Wed, 16 Apr 2008) | 2 lines Add details about the return value for mmap.flush(). ........ r62364 | raymond.hettinger | 2008-04-17 12:48:31 +0200 (Thu, 17 Apr 2008) | 1 line Issue 2648: Add leading zero to money format recipe in the docs. ........ r62365 | jeroen.ruigrok | 2008-04-17 14:39:45 +0200 (Thu, 17 Apr 2008) | 2 lines Be consistent in the use of read-only. ........ r62370 | andrew.kuchling | 2008-04-17 22:44:06 +0200 (Thu, 17 Apr 2008) | 1 line Typo fixes ........ r62372 | andrew.kuchling | 2008-04-18 04:40:47 +0200 (Fri, 18 Apr 2008) | 1 line Use correct parameter name ........ r62373 | andrew.kuchling | 2008-04-18 18:53:09 +0200 (Fri, 18 Apr 2008) | 1 line #2654: fix typo ........ r62374 | andrew.kuchling | 2008-04-18 20:28:23 +0200 (Fri, 18 Apr 2008) | 4 lines Remove personal note from Jim Roskind; it no longer applies, and the e-mail address is for a previous employer. Can we move the big long copyright statement into a sidebar or something? ........ r62375 | andrew.kuchling | 2008-04-18 20:39:55 +0200 (Fri, 18 Apr 2008) | 1 line Rewrite introductory section, and remove old section. (It was already commented-out, but why keep it?) ........ r62378 | skip.montanaro | 2008-04-18 22:35:46 +0200 (Fri, 18 Apr 2008) | 1 line resolve issue 2014 ........ r62379 | benjamin.peterson | 2008-04-18 22:45:33 +0200 (Fri, 18 Apr 2008) | 2 lines Fix indentation in sysmodule.c ........ r62381 | amaury.forgeotdarc | 2008-04-19 01:31:33 +0200 (Sat, 19 Apr 2008) | 3 lines Some tests did not pass on repeated calls (regrtest -R::) Perform additional cleanup, mostly deleting from sys.modules, or clearing the warnings registry. ........ --- Doc/ACKS.txt | 1 + Doc/howto/doanddont.rst | 2 +- Doc/library/decimal.rst | 4 +- Doc/library/itertools.rst | 14 ++- Doc/library/mmap.rst | 184 +++++++++++++++++++++------------------ Doc/library/pkgutil.rst | 23 ++++- Doc/library/profile.rst | 86 +++++------------- Doc/library/ssl.rst | 2 +- Doc/reference/compound_stmts.rst | 9 +- Doc/tutorial/controlflow.rst | 8 +- Lib/pkgutil.py | 37 ++++++++ Lib/test/regrtest.py | 5 ++ Lib/test/test_frozen.py | 12 +++ Lib/test/test_pkg.py | 10 +++ Lib/test/test_pkgutil.py | 127 +++++++++++++++++++++++++++ Lib/test/test_profile.py | 5 +- Lib/test/test_structmembers.py | 6 -- Lib/test/test_warnings.py | 2 + Lib/test/test_xmlrpc.py | 11 +++ Lib/xmlrpclib.py | 30 ++++--- Objects/longobject.c | 25 ++++-- Python/sysmodule.c | 6 +- 22 files changed, 416 insertions(+), 193 deletions(-) create mode 100644 Lib/test/test_pkgutil.py diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt index 9eae6a3..764a65b 100644 --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -145,6 +145,7 @@ docs@python.org), and we'll be glad to correct the problem. * Harri Pasanen * Bo Peng * Tim Peters + * Benjamin Peterson * Christopher Petrilli * Justin D. Pettit * Chris Phoenix diff --git a/Doc/howto/doanddont.rst b/Doc/howto/doanddont.rst index d263df3..5bd2eac 100644 --- a/Doc/howto/doanddont.rst +++ b/Doc/howto/doanddont.rst @@ -4,7 +4,7 @@ :Author: Moshe Zadka -This document is placed in the public doman. +This document is placed in the public domain. .. topic:: Abstract diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index 04433c1..33aa42c 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -1374,7 +1374,7 @@ to work with the :class:`Decimal` class:: >>> moneyfmt(Decimal(123456789), sep=' ') '123 456 789.00' >>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>') - '<.02>' + '<0.02>' """ q = Decimal(10) ** -places # 2 places --> '0.01' @@ -1387,6 +1387,8 @@ to work with the :class:`Decimal` class:: for i in range(places): build(next() if digits else '0') build(dp) + if not digits: + build('0') i = 0 while digits: build(next()) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 0d20410..c9d4c60b 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -96,7 +96,7 @@ loops that truncate the stream. .. function:: combinations(iterable, r) - Return successive *r* length combinations of elements in the *iterable*. + Return *r* length subsequences of elements from the input *iterable*. Combinations are emitted in lexicographic sort order. So, if the input *iterable* is sorted, the combination tuples will be produced @@ -106,9 +106,6 @@ loops that truncate the stream. value. So if the input elements are unique, there will be no repeat values in each combination. - Each result tuple is ordered to match the input order. So, every - combination is a subsequence of the input *iterable*. - Equivalent to:: def combinations(iterable, r): @@ -375,11 +372,10 @@ loops that truncate the stream. Equivalent to nested for-loops in a generator expression. For example, ``product(A, B)`` returns the same as ``((x,y) for x in A for y in B)``. - The leftmost iterators correspond to the outermost for-loop, so the output - tuples cycle like an odometer (with the rightmost element changing on every - iteration). This results in a lexicographic ordering so that if the - inputs iterables are sorted, the product tuples are emitted - in sorted order. + The nested loops cycle like an odometer with the rightmost element advancing + on every iteration. This pattern creates a lexicographic ordering so that if + the input's iterables are sorted, the product tuples are emitted in sorted + order. To compute the product of an iterable with itself, specify the number of repetitions with the optional *repeat* keyword argument. For example, diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst index 8ec9885..0361320 100644 --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -8,54 +8,55 @@ Memory-mapped file objects behave like both strings and like file objects. Unlike normal string objects, however, these are mutable. You can use mmap -objects in most places where strings are expected; for example, you can use the -:mod:`re` module to search through a memory-mapped file. Since they're mutable, -you can change a single character by doing ``obj[index] = 'a'``, or change a -substring by assigning to a slice: ``obj[i1:i2] = '...'``. You can also read -and write data starting at the current file position, and :meth:`seek` through -the file to different positions. - -A memory-mapped file is created by the :class:`mmap` constructor, which is different -on Unix and on Windows. In either case you must provide a file descriptor for a -file opened for update. If you wish to map an existing Python file object, use -its :meth:`fileno` method to obtain the correct value for the *fileno* -parameter. Otherwise, you can open the file using the :func:`os.open` function, -which returns a file descriptor directly (the file still needs to be closed when -done). +objects in most places where strings are expected; for example, you can use +the :mod:`re` module to search through a memory-mapped file. Since they're +mutable, you can change a single character by doing ``obj[index] = 'a'``, or +change a substring by assigning to a slice: ``obj[i1:i2] = '...'``. You can +also read and write data starting at the current file position, and +:meth:`seek` through the file to different positions. + +A memory-mapped file is created by the :class:`mmap` constructor, which is +different on Unix and on Windows. In either case you must provide a file +descriptor for a file opened for update. If you wish to map an existing Python +file object, use its :meth:`fileno` method to obtain the correct value for the +*fileno* parameter. Otherwise, you can open the file using the +:func:`os.open` function, which returns a file descriptor directly (the file +still needs to be closed when done). For both the Unix and Windows versions of the constructor, *access* may be specified as an optional keyword parameter. *access* accepts one of three -values: :const:`ACCESS_READ`, :const:`ACCESS_WRITE`, or :const:`ACCESS_COPY` to -specify readonly, write-through or copy-on-write memory respectively. *access* -can be used on both Unix and Windows. If *access* is not specified, Windows -mmap returns a write-through mapping. The initial memory values for all three -access types are taken from the specified file. Assignment to an -:const:`ACCESS_READ` memory map raises a :exc:`TypeError` exception. Assignment -to an :const:`ACCESS_WRITE` memory map affects both memory and the underlying -file. Assignment to an :const:`ACCESS_COPY` memory map affects memory but does -not update the underlying file. +values: :const:`ACCESS_READ`, :const:`ACCESS_WRITE`, or :const:`ACCESS_COPY` +to specify read-only, write-through or copy-on-write memory respectively. +*access* can be used on both Unix and Windows. If *access* is not specified, +Windows mmap returns a write-through mapping. The initial memory values for +all three access types are taken from the specified file. Assignment to an +:const:`ACCESS_READ` memory map raises a :exc:`TypeError` exception. +Assignment to an :const:`ACCESS_WRITE` memory map affects both memory and the +underlying file. Assignment to an :const:`ACCESS_COPY` memory map affects +memory but does not update the underlying file. To map anonymous memory, -1 should be passed as the fileno along with the length. .. class:: mmap(fileno, length[, tagname[, access[, offset]]]) - **(Windows version)** Maps *length* bytes from the file specified by the file - handle *fileno*, and creates a mmap object. If *length* is larger than the - current size of the file, the file is extended to contain *length* bytes. If - *length* is ``0``, the maximum length of the map is the current size of the - file, except that if the file is empty Windows raises an exception (you cannot - create an empty mapping on Windows). + **(Windows version)** Maps *length* bytes from the file specified by the + file handle *fileno*, and creates a mmap object. If *length* is larger + than the current size of the file, the file is extended to contain *length* + bytes. If *length* is ``0``, the maximum length of the map is the current + size of the file, except that if the file is empty Windows raises an + exception (you cannot create an empty mapping on Windows). - *tagname*, if specified and not ``None``, is a string giving a tag name for the - mapping. Windows allows you to have many different mappings against the same - file. If you specify the name of an existing tag, that tag is opened, otherwise - a new tag of this name is created. If this parameter is omitted or ``None``, - the mapping is created without a name. Avoiding the use of the tag parameter - will assist in keeping your code portable between Unix and Windows. + *tagname*, if specified and not ``None``, is a string giving a tag name for + the mapping. Windows allows you to have many different mappings against + the same file. If you specify the name of an existing tag, that tag is + opened, otherwise a new tag of this name is created. If this parameter is + omitted or ``None``, the mapping is created without a name. Avoiding the + use of the tag parameter will assist in keeping your code portable between + Unix and Windows. - *offset* may be specified as a non-negative integer offset. mmap references will - be relative to the offset from the beginning of the file. *offset* defaults to 0. - *offset* must be a multiple of the ALLOCATIONGRANULARITY. + *offset* may be specified as a non-negative integer offset. mmap references + will be relative to the offset from the beginning of the file. *offset* + defaults to 0. *offset* must be a multiple of the ALLOCATIONGRANULARITY. .. class:: mmap(fileno, length[, flags[, prot[, access[, offset]]]]) @@ -63,26 +64,29 @@ To map anonymous memory, -1 should be passed as the fileno along with the length **(Unix version)** Maps *length* bytes from the file specified by the file descriptor *fileno*, and returns a mmap object. If *length* is ``0``, the - maximum length of the map will be the current size of the file when :class:`mmap` - is called. + maximum length of the map will be the current size of the file when + :class:`mmap` is called. *flags* specifies the nature of the mapping. :const:`MAP_PRIVATE` creates a - private copy-on-write mapping, so changes to the contents of the mmap object - will be private to this process, and :const:`MAP_SHARED` creates a mapping - that's shared with all other processes mapping the same areas of the file. The - default value is :const:`MAP_SHARED`. - - *prot*, if specified, gives the desired memory protection; the two most useful - values are :const:`PROT_READ` and :const:`PROT_WRITE`, to specify that the pages - may be read or written. *prot* defaults to :const:`PROT_READ \| PROT_WRITE`. - - *access* may be specified in lieu of *flags* and *prot* as an optional keyword - parameter. It is an error to specify both *flags*, *prot* and *access*. See - the description of *access* above for information on how to use this parameter. - - *offset* may be specified as a non-negative integer offset. mmap references will - be relative to the offset from the beginning of the file. *offset* defaults to 0. - *offset* must be a multiple of the PAGESIZE or ALLOCATIONGRANULARITY. + private copy-on-write mapping, so changes to the contents of the mmap + object will be private to this process, and :const:`MAP_SHARED` creates a + mapping that's shared with all other processes mapping the same areas of + the file. The default value is :const:`MAP_SHARED`. + + *prot*, if specified, gives the desired memory protection; the two most + useful values are :const:`PROT_READ` and :const:`PROT_WRITE`, to specify + that the pages may be read or written. *prot* defaults to + :const:`PROT_READ \| PROT_WRITE`. + + *access* may be specified in lieu of *flags* and *prot* as an optional + keyword parameter. It is an error to specify both *flags*, *prot* and + *access*. See the description of *access* above for information on how to + use this parameter. + + *offset* may be specified as a non-negative integer offset. mmap references + will be relative to the offset from the beginning of the file. *offset* + defaults to 0. *offset* must be a multiple of the PAGESIZE or + ALLOCATIONGRANULARITY. This example shows a simple way of using :class:`mmap`:: @@ -132,32 +136,38 @@ Memory-mapped file objects support the following methods: .. method:: mmap.close() - Close the file. Subsequent calls to other methods of the object will result in - an exception being raised. + Close the file. Subsequent calls to other methods of the object will + result in an exception being raised. .. method:: mmap.find(string[, start[, end]]) - Returns the lowest index in the object where the substring *string* is found, - such that *string* is contained in the range [*start*, *end*]. Optional - arguments *start* and *end* are interpreted as in slice notation. + Returns the lowest index in the object where the substring *string* is + found, such that *string* is contained in the range [*start*, *end*]. + Optional arguments *start* and *end* are interpreted as in slice notation. Returns ``-1`` on failure. .. method:: mmap.flush([offset, size]) - Flushes changes made to the in-memory copy of a file back to disk. Without use - of this call there is no guarantee that changes are written back before the - object is destroyed. If *offset* and *size* are specified, only changes to the - given range of bytes will be flushed to disk; otherwise, the whole extent of the - mapping is flushed. + Flushes changes made to the in-memory copy of a file back to disk. Without + use of this call there is no guarantee that changes are written back before + the object is destroyed. If *offset* and *size* are specified, only + changes to the given range of bytes will be flushed to disk; otherwise, the + whole extent of the mapping is flushed. + + **(Windows version)** A nonzero value returned indicates success; zero + indicates failure. + + **(Unix version)** A zero value is returned to indicate success. An + exception is raised when the call failed. .. method:: mmap.move(dest, src, count) - Copy the *count* bytes starting at offset *src* to the destination index *dest*. - If the mmap was created with :const:`ACCESS_READ`, then calls to move will throw - a :exc:`TypeError` exception. + Copy the *count* bytes starting at offset *src* to the destination index + *dest*. If the mmap was created with :const:`ACCESS_READ`, then calls to + move will throw a :exc:`TypeError` exception. .. method:: mmap.read(num) @@ -175,31 +185,31 @@ Memory-mapped file objects support the following methods: .. method:: mmap.readline() - Returns a single line, starting at the current file position and up to the next - newline. + Returns a single line, starting at the current file position and up to the + next newline. .. method:: mmap.resize(newsize) - Resizes the map and the underlying file, if any. If the mmap was created with - :const:`ACCESS_READ` or :const:`ACCESS_COPY`, resizing the map will throw a - :exc:`TypeError` exception. + Resizes the map and the underlying file, if any. If the mmap was created + with :const:`ACCESS_READ` or :const:`ACCESS_COPY`, resizing the map will + throw a :exc:`TypeError` exception. .. method:: mmap.rfind(string[, start[, end]]) Returns the highest index in the object where the substring *string* is - found, such that *string* is contained in the range [*start*, - *end*]. Optional arguments *start* and *end* are interpreted as in slice - notation. Returns ``-1`` on failure. + found, such that *string* is contained in the range [*start*, *end*]. + Optional arguments *start* and *end* are interpreted as in slice notation. + Returns ``-1`` on failure. .. method:: mmap.seek(pos[, whence]) - Set the file's current position. *whence* argument is optional and defaults to - ``os.SEEK_SET`` or ``0`` (absolute file positioning); other values are - ``os.SEEK_CUR`` or ``1`` (seek relative to the current position) and - ``os.SEEK_END`` or ``2`` (seek relative to the file's end). + Set the file's current position. *whence* argument is optional and + defaults to ``os.SEEK_SET`` or ``0`` (absolute file positioning); other + values are ``os.SEEK_CUR`` or ``1`` (seek relative to the current position) + and ``os.SEEK_END`` or ``2`` (seek relative to the file's end). .. method:: mmap.size() @@ -217,15 +227,15 @@ Memory-mapped file objects support the following methods: Write the bytes in *string* into memory at the current position of the file pointer; the file position is updated to point after the bytes that were - written. If the mmap was created with :const:`ACCESS_READ`, then writing to it - will throw a :exc:`TypeError` exception. + written. If the mmap was created with :const:`ACCESS_READ`, then writing to + it will throw a :exc:`TypeError` exception. .. method:: mmap.write_byte(byte) - Write the single-character string *byte* into memory at the current position of - the file pointer; the file position is advanced by ``1``. If the mmap was - created with :const:`ACCESS_READ`, then writing to it will throw a - :exc:`TypeError` exception. + Write the single-character string *byte* into memory at the current + position of the file pointer; the file position is advanced by ``1``. If + the mmap was created with :const:`ACCESS_READ`, then writing to it will + throw a :exc:`TypeError` exception. diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst index 1a84338..72daa84 100644 --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -6,7 +6,7 @@ :synopsis: Utilities to support extension of packages. -This module provides a single function: +This module provides functions to manipulate packages: .. function:: extend_path(path, name) @@ -38,3 +38,24 @@ This module provides a single function: ``sys.path`` that cause errors when used as filenames may cause this function to raise an exception (in line with :func:`os.path.isdir` behavior). +.. function:: get_data(package, resource) + + Get a resource from a package. + + This is a wrapper round the PEP 302 loader :func:`get_data` API. The package + argument should be the name of a package, in standard module format + (foo.bar). The resource argument should be in the form of a relative + filename, using ``/`` as the path separator. The parent directory name + ``..`` is not allowed, and nor is a rooted name (starting with a ``/``). + + The function returns a binary string, which is the contents of the + specified resource. + + For packages located in the filesystem, which have already been imported, + this is the rough equivalent of:: + + d = os.path.dirname(sys.modules[package].__file__) + data = open(os.path.join(d, resource), 'rb').read() + + If the package cannot be located or loaded, or it uses a PEP 302 loader + which does not support :func:`get_data`, then None is returned. diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst index 2d46033..c5c69a4 100644 --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -32,15 +32,6 @@ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -The profiler was written after only programming in Python for 3 weeks. As a -result, it is probably clumsy code, but I don't know for sure yet 'cause I'm a -beginner :-). I did work hard to make the code run fast, so that profiling -would be a reasonable thing to do. I tried not to repeat code fragments, but -I'm sure I did some stuff in really awkward ways at times. Please send -suggestions for improvements to: jar@netscape.com. I won't promise *any* -support. ...but I'd appreciate the feedback. - - .. _profiler-introduction: Introduction to the profilers @@ -50,69 +41,38 @@ Introduction to the profilers single: deterministic profiling single: profiling, deterministic -A :dfn:`profiler` is a program that describes the run time performance of a -program, providing a variety of statistics. This documentation describes the -profiler functionality provided in the modules :mod:`profile` and :mod:`pstats`. -This profiler provides :dfn:`deterministic profiling` of any Python programs. -It also provides a series of report generation tools to allow users to rapidly +A :dfn:`profiler` is a program that describes the run time performance +of a program, providing a variety of statistics. This documentation +describes the profiler functionality provided in the modules +:mod:`cProfile`, :mod:`profile` and :mod:`pstats`. This profiler +provides :dfn:`deterministic profiling` of Python programs. It also +provides a series of report generation tools to allow users to rapidly examine the results of a profile operation. The Python standard library provides two different profilers: -#. :mod:`profile`, a pure Python module, described in the sequel. Copyright © - 1994, by InfoSeek Corporation. +#. :mod:`cProfile` is recommended for most users; it's a C extension + with reasonable overhead + that makes it suitable for profiling long-running programs. + Based on :mod:`lsprof`, + contributed by Brett Rosen and Ted Czotter. -#. :mod:`cProfile`, a module written in C, with a reasonable overhead that makes - it suitable for profiling long-running programs. Based on :mod:`lsprof`, - contributed by Brett Rosen and Ted Czotter. +#. :mod:`profile`, a pure Python module whose interface is imitated by + :mod:`cProfile`. Adds significant overhead to profiled programs. + If you're trying to extend + the profiler in some way, the task might be easier with this module. + Copyright © 1994, by InfoSeek Corporation. The :mod:`profile` and :mod:`cProfile` modules export the same interface, so -they are mostly interchangeables; :mod:`cProfile` has a much lower overhead but -is not so far as well-tested and might not be available on all systems. +they are mostly interchangeable; :mod:`cProfile` has a much lower overhead but +is newer and might not be available on all systems. :mod:`cProfile` is really a compatibility layer on top of the internal +<<<<<<< .working :mod:`_lsprof` module. - -.. \section{How Is This Profiler Different From The Old Profiler?} - \nodename{Profiler Changes} - - (This section is of historical importance only; the old profiler - discussed here was last seen in Python 1.1.) - - The big changes from old profiling module are that you get more - information, and you pay less CPU time. It's not a trade-off, it's a - trade-up. - - To be specific: - - \begin{description} - - \item[Bugs removed:] - Local stack frame is no longer molested, execution time is now charged - to correct functions. - - \item[Accuracy increased:] - Profiler execution time is no longer charged to user's code, - calibration for platform is supported, file reads are not done \emph{by} - profiler \emph{during} profiling (and charged to user's code!). - - \item[Speed increased:] - Overhead CPU cost was reduced by more than a factor of two (perhaps a - factor of five), lightweight profiler module is all that must be - loaded, and the report generating module (\module{pstats}) is not needed - during profiling. - - \item[Recursive functions support:] - Cumulative times in recursive functions are correctly calculated; - recursive entries are counted. - - \item[Large growth in report generating UI:] - Distinct profiles runs can be added together forming a comprehensive - report; functions that import statistics take arbitrary lists of - files; sorting criteria is now based on keywords (instead of 4 integer - options); reports shows what functions were profiled as well as what - profile file was referenced; output format has been improved. - - \end{description} +======= +:mod:`_lsprof` module. The :mod:`hotshot` module is reserved for specialized +usage. +>>>>>>> .merge-right.r62379 .. _profile-instant: diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 2fd651e..f60620c 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -543,7 +543,7 @@ end, and use :func:`wrap_socket` to create a server-side SSL context for it:: server_side=True, certfile="mycertfile", keyfile="mykeyfile", - ssl_protocol=ssl.PROTOCOL_TLSv1) + ssl_version=ssl.PROTOCOL_TLSv1) deal_with_client(connstream) Then you'd read data from the ``connstream`` and do something with it till you are finished with the client (or the client is finished with you):: diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index d60ee56f..c81c75f 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -446,6 +446,9 @@ when the function is called. The function definition does not execute the function body; this gets executed only when the function is called. +.. index:: + statement: @ + A function definition may be wrapped by one or more :term:`decorator` expressions. Decorator expressions are evaluated when the function is defined, in the scope that contains the function definition. The result must be a callable, which is @@ -486,7 +489,11 @@ as the default, and explicitly test for it in the body of the function, e.g.:: penguin.append("property of the zoo") return penguin -Function call semantics are described in more detail in section :ref:`calls`. A +.. index:: + statement: * + statement: ** + +Function call semantics are described in more detail in section :ref:`calls`. A function call always assigns values to all parameters mentioned in the parameter list, either from position arguments, from keyword arguments, or from default values. If the form "``*identifier``" is present, it is initialized to a tuple diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 3d011d1..4404ab2 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -467,6 +467,9 @@ if this is not done, the order in which the arguments are printed is undefined. Arbitrary Argument Lists ------------------------ +.. index:: + statement: * + Finally, the least frequently used option is to specify that a function can be called with an arbitrary number of arguments. These arguments will be wrapped up in a tuple. Before the variable number of arguments, zero or more normal @@ -508,6 +511,9 @@ or tuple:: >>> list(range(*args)) # call with arguments unpacked from a list [3, 4, 5] +.. index:: + statement: ** + In the same fashion, dictionaries can deliver keyword arguments with the ``**``\ -operator:: @@ -610,7 +616,7 @@ concise, *formatted*) in different styles; some are more readable than others. Making it easy for others to read your code is always a good idea, and adopting a nice coding style helps tremendously for that. -For Python, :pep:`8` has emerged as the style guide that most projects adher to; +For Python, :pep:`8` has emerged as the style guide that most projects adhere to; it promotes a very readable and eye-pleasing coding style. Every Python developer should read it at some point; here are the most important points extracted for you: diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py index 9c1d07c..ff3467a 100644 --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -542,3 +542,40 @@ def extend_path(path, name): f.close() return path + +def get_data(package, resource): + """Get a resource from a package. + + This is a wrapper round the PEP 302 loader get_data API. The package + argument should be the name of a package, in standard module format + (foo.bar). The resource argument should be in the form of a relative + filename, using '/' as the path separator. The parent directory name '..' + is not allowed, and nor is a rooted name (starting with a '/'). + + The function returns a binary string, which is the contents of the + specified resource. + + For packages located in the filesystem, which have already been imported, + this is the rough equivalent of + + d = os.path.dirname(sys.modules[package].__file__) + data = open(os.path.join(d, resource), 'rb').read() + + If the package cannot be located or loaded, or it uses a PEP 302 loader + which does not support get_data(), then None is returned. + """ + + loader = get_loader(package) + if loader is None or not hasattr(loader, 'get_data'): + return None + mod = sys.modules.get(package) or loader.load_module(package) + if mod is None or not hasattr(mod, '__file__'): + return None + + # Modify the resource name to be compatible with the loader.get_data + # signature - an os.path format "filename" starting with the dirname of + # the package's __file__ + parts = resource.split('/') + parts.insert(0, os.path.dirname(mod.__file__)) + resource_name = os.path.join(*parts) + return loader.get_data(resource_name) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index 000f241..675cea3 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -731,6 +731,11 @@ def dash_R_cleanup(fs, ps, pic, abcs): from distutils.dir_util import _path_created from weakref import WeakSet + # Clear the warnings registry, so they can be displayed again + for mod in sys.modules.values(): + if hasattr(mod, '__warningregistry__'): + del mod.__warningregistry__ + # Restore some original values. warnings.filters[:] = fs copy_reg.dispatch_table.clear() diff --git a/Lib/test/test_frozen.py b/Lib/test/test_frozen.py index 99f499d..c86a24d 100644 --- a/Lib/test/test_frozen.py +++ b/Lib/test/test_frozen.py @@ -39,6 +39,18 @@ class FrozenTests(unittest.TestCase): else: self.fail("import __phello__.foo should have failed") + if sys.platform != "mac": # On the Mac this import does succeed. + try: + import __phello__.foo + except ImportError: + pass + else: + self.fail("import __phello__.foo should have failed") + + del sys.modules['__hello__'] + del sys.modules['__phello__'] + del sys.modules['__phello__.spam'] + def test_main(): run_unittest(FrozenTests) diff --git a/Lib/test/test_pkg.py b/Lib/test/test_pkg.py index dcc7433..db8e844 100644 --- a/Lib/test/test_pkg.py +++ b/Lib/test/test_pkg.py @@ -46,6 +46,7 @@ class TestPkg(unittest.TestCase): def setUp(self): self.root = None + self.pkgname = None self.syspath = list(sys.path) self.sysmodules = sys.modules.copy() @@ -56,6 +57,13 @@ class TestPkg(unittest.TestCase): del self.sysmodules cleanout(self.root) + # delete all modules concerning the tested hiearchy + if self.pkgname: + modules = [name for name in sys.modules + if self.pkgname in name.split('.')] + for name in modules: + del sys.modules[name] + def run_code(self, code): exec(textwrap.dedent(code), globals(), {"self": self}) @@ -78,6 +86,8 @@ class TestPkg(unittest.TestCase): f.write('\n') f.close() self.root = root + # package name is the name of the first item + self.pkgname = descr[0][0] def test_1(self): hier = [("t1", None), ("t1 __init__.py", "")] diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py new file mode 100644 index 0000000..c9ec060 --- /dev/null +++ b/Lib/test/test_pkgutil.py @@ -0,0 +1,127 @@ +from test.test_support import run_unittest +import unittest +import sys +import imp +import pkgutil +import os +import os.path +import tempfile +import shutil +import zipfile + + + +class PkgutilTests(unittest.TestCase): + + def setUp(self): + self.dirname = tempfile.mkdtemp() + sys.path.insert(0, self.dirname) + + def tearDown(self): + del sys.path[0] + shutil.rmtree(self.dirname) + + def test_getdata_filesys(self): + pkg = 'test_getdata_filesys' + + # Include a LF and a CRLF, to test that binary data is read back + RESOURCE_DATA = b'Hello, world!\nSecond line\r\nThird line' + + # Make a package with some resources + package_dir = os.path.join(self.dirname, pkg) + os.mkdir(package_dir) + # Empty init.py + f = open(os.path.join(package_dir, '__init__.py'), "wb") + f.close() + # Resource files, res.txt, sub/res.txt + f = open(os.path.join(package_dir, 'res.txt'), "wb") + f.write(RESOURCE_DATA) + f.close() + os.mkdir(os.path.join(package_dir, 'sub')) + f = open(os.path.join(package_dir, 'sub', 'res.txt'), "wb") + f.write(RESOURCE_DATA) + f.close() + + # Check we can read the resources + res1 = pkgutil.get_data(pkg, 'res.txt') + self.assertEqual(res1, RESOURCE_DATA) + res2 = pkgutil.get_data(pkg, 'sub/res.txt') + self.assertEqual(res2, RESOURCE_DATA) + + del sys.modules[pkg] + + def test_getdata_zipfile(self): + zip = 'test_getdata_zipfile.zip' + pkg = 'test_getdata_zipfile' + + # Include a LF and a CRLF, to test that binary data is read back + RESOURCE_DATA = b'Hello, world!\nSecond line\r\nThird line' + + # Make a package with some resources + zip_file = os.path.join(self.dirname, zip) + z = zipfile.ZipFile(zip_file, 'w') + + # Empty init.py + z.writestr(pkg + '/__init__.py', "") + # Resource files, res.txt, sub/res.txt + z.writestr(pkg + '/res.txt', RESOURCE_DATA) + z.writestr(pkg + '/sub/res.txt', RESOURCE_DATA) + z.close() + + # Check we can read the resources + sys.path.insert(0, zip_file) + res1 = pkgutil.get_data(pkg, 'res.txt') + self.assertEqual(res1, RESOURCE_DATA) + res2 = pkgutil.get_data(pkg, 'sub/res.txt') + self.assertEqual(res2, RESOURCE_DATA) + del sys.path[0] + + del sys.modules[pkg] + +class PkgutilPEP302Tests(unittest.TestCase): + + class MyTestLoader(object): + def load_module(self, fullname): + # Create an empty module + mod = sys.modules.setdefault(fullname, imp.new_module(fullname)) + mod.__file__ = "<%s>" % self.__class__.__name__ + mod.__loader__ = self + # Make it a package + mod.__path__ = [] + # Count how many times the module is reloaded + mod.__dict__['loads'] = mod.__dict__.get('loads',0) + 1 + return mod + + def get_data(self, path): + return "Hello, world!" + + class MyTestImporter(object): + def find_module(self, fullname, path=None): + return PkgutilPEP302Tests.MyTestLoader() + + def setUp(self): + sys.meta_path.insert(0, self.MyTestImporter()) + + def tearDown(self): + del sys.meta_path[0] + + def test_getdata_pep302(self): + # Use a dummy importer/loader + self.assertEqual(pkgutil.get_data('foo', 'dummy'), "Hello, world!") + del sys.modules['foo'] + + def test_alreadyloaded(self): + # Ensure that get_data works without reloading - the "loads" module + # variable in the example loader should count how many times a reload + # occurs. + import foo + self.assertEqual(foo.loads, 1) + self.assertEqual(pkgutil.get_data('foo', 'dummy'), "Hello, world!") + self.assertEqual(foo.loads, 1) + del sys.modules['foo'] + +def test_main(): + run_unittest(PkgutilTests, PkgutilPEP302Tests) + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py index 398ab86..9fea434 100755 --- a/Lib/test/test_profile.py +++ b/Lib/test/test_profile.py @@ -22,8 +22,9 @@ class ProfileTest(unittest.TestCase): def do_profiling(cls): results = [] prof = cls.profilerclass(timer, 0.001) + start_timer = timer() prof.runctx("testfunc()", globals(), locals()) - results.append(timer()) + results.append(timer() - start_timer) for methodname in cls.methodnames: s = StringIO() stats = pstats.Stats(prof, stream=s) @@ -40,7 +41,7 @@ class ProfileTest(unittest.TestCase): def test_cprofile(self): results = self.do_profiling() - self.assertEqual(results[0], 43000) + self.assertEqual(results[0], 1000) for i, method in enumerate(self.methodnames): if results[i+1] != self.expected_output[method]: print("Stats.%s output for %s doesn't fit expectation!" % diff --git a/Lib/test/test_structmembers.py b/Lib/test/test_structmembers.py index 27b4b70..97d7b23 100644 --- a/Lib/test/test_structmembers.py +++ b/Lib/test/test_structmembers.py @@ -101,12 +101,6 @@ class TestWarnings(unittest.TestCase): def test_main(verbose=None): - # Obscure hack so that this test passes after reloads or repeated calls - # to test_main (regrtest -R). - if '__warningregistry__' in globals(): - del globals()['__warningregistry__'] - if hasattr(sys, '__warningregistry__'): - del sys.__warningregistry__ test_support.run_unittest(__name__) if __name__ == "__main__": diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py index d8aee79..a6cbddf 100644 --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -391,6 +391,8 @@ class PyWarningsDisplayTests(BaseTest, WarningsDisplayTests): def test_main(): + py_warnings.onceregistry.clear() + c_warnings.onceregistry.clear() test_support.run_unittest(CFilterTests, PyFilterTests, CWarnTests, diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index e708927..a254eee 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -49,6 +49,17 @@ class XMLRPCTestCase(unittest.TestCase): (newdt,), m = xmlrpclib.loads(s, use_datetime=0) self.assertEquals(newdt, xmlrpclib.DateTime('20050210T11:41:23')) + def test_datetime_before_1900(self): + # same as before but with an date before 1900 + dt = datetime.datetime(1, 2, 10, 11, 41, 23) + s = xmlrpclib.dumps((dt,)) + (newdt,), m = xmlrpclib.loads(s, use_datetime=1) + self.assertEquals(newdt, dt) + self.assertEquals(m, None) + + (newdt,), m = xmlrpclib.loads(s, use_datetime=0) + self.assertEquals(newdt, xmlrpclib.DateTime('00010210T11:41:23')) + def test_cmp_datetime_DateTime(self): now = datetime.datetime.now() dt = xmlrpclib.DateTime(now.timetuple()) diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py index 2e68a1b..522df4d 100644 --- a/Lib/xmlrpclib.py +++ b/Lib/xmlrpclib.py @@ -287,6 +287,20 @@ boolean = Boolean = bool # @param value The time, given as an ISO 8601 string, a time # tuple, or a integer time value. +def _strftime(value): + if datetime: + if isinstance(value, datetime.datetime): + return "%04d%02d%02dT%02d:%02d:%02d" % ( + value.year, value.month, value.day, + value.hour, value.minute, value.second) + + if not isinstance(value, (tuple, time.struct_time)): + if value == 0: + value = time.time() + value = time.localtime(value) + + return "%04d%02d%02dT%02d:%02d:%02d" % value[:6] + class DateTime: """DateTime wrapper for an ISO 8601 string or time tuple or localtime integer value to generate 'dateTime.iso8601' XML-RPC @@ -294,16 +308,10 @@ class DateTime: """ def __init__(self, value=0): - if not isinstance(value, str): - if datetime and isinstance(value, datetime.datetime): - self.value = value.strftime("%Y%m%dT%H:%M:%S") - return - if not isinstance(value, (tuple, time.struct_time)): - if value == 0: - value = time.time() - value = time.localtime(value) - value = time.strftime("%Y%m%dT%H:%M:%S", value) - self.value = value + if isinstance(value, str): + self.value = value + else: + self.value = _strftime(value) def make_comparable(self, other): if isinstance(other, DateTime): @@ -700,7 +708,7 @@ class Marshaller: if datetime: def dump_datetime(self, value, write): write("") - write(value.strftime("%Y%m%dT%H:%M:%S")) + write(_strftime(value)) write("\n") dispatch[datetime.datetime] = dump_datetime diff --git a/Objects/longobject.c b/Objects/longobject.c index d88a13e..fa0142f 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -160,6 +160,7 @@ PyObject * PyLong_FromLong(long ival) { PyLongObject *v; + unsigned long abs_ival; unsigned long t; /* unsigned so >> doesn't propagate sign bit */ int ndigits = 0; int sign = 1; @@ -167,9 +168,15 @@ PyLong_FromLong(long ival) CHECK_SMALL_INT(ival); if (ival < 0) { - ival = -ival; + /* if LONG_MIN == -LONG_MAX-1 (true on most platforms) then + ANSI C says that the result of -ival is undefined when ival + == LONG_MIN. Hence the following workaround. */ + abs_ival = (unsigned long)(-1-ival) + 1; sign = -1; } + else { + abs_ival = (unsigned long)ival; + } /* Fast path for single-digits ints */ if (!(ival>>PyLong_SHIFT)) { @@ -193,7 +200,7 @@ PyLong_FromLong(long ival) } /* Larger numbers: loop to determine number of digits */ - t = (unsigned long)ival; + t = abs_ival; while (t) { ++ndigits; t >>= PyLong_SHIFT; @@ -202,7 +209,7 @@ PyLong_FromLong(long ival) if (v != NULL) { digit *p = v->ob_digit; Py_SIZE(v) = ndigits*sign; - t = (unsigned long)ival; + t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); t >>= PyLong_SHIFT; @@ -1033,21 +1040,27 @@ PyObject * PyLong_FromLongLong(PY_LONG_LONG ival) { PyLongObject *v; + unsigned PY_LONG_LONG abs_ival; unsigned PY_LONG_LONG t; /* unsigned so >> doesn't propagate sign bit */ int ndigits = 0; int negative = 0; CHECK_SMALL_INT(ival); if (ival < 0) { - ival = -ival; + /* avoid signed overflow on negation; see comments + in PyLong_FromLong above. */ + abs_ival = (unsigned PY_LONG_LONG)(-1-ival) + 1; negative = 1; } + else { + abs_ival = (unsigned PY_LONG_LONG)ival; + } /* Count the number of Python digits. We used to pick 5 ("big enough for anything"), but that's a waste of time and space given that 5*15 = 75 bits are rarely needed. */ - t = (unsigned PY_LONG_LONG)ival; + t = abs_ival; while (t) { ++ndigits; t >>= PyLong_SHIFT; @@ -1056,7 +1069,7 @@ PyLong_FromLongLong(PY_LONG_LONG ival) if (v != NULL) { digit *p = v->ob_digit; Py_SIZE(v) = negative ? -ndigits : ndigits; - t = (unsigned PY_LONG_LONG)ival; + t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); t >>= PyLong_SHIFT; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 9337f5c..ec167f0 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1191,9 +1191,9 @@ _PySys_Init(void) /* stdin/stdout/stderr are now set by pythonrun.c */ PyDict_SetItemString(sysdict, "__displayhook__", - PyDict_GetItemString(sysdict, "displayhook")); + PyDict_GetItemString(sysdict, "displayhook")); PyDict_SetItemString(sysdict, "__excepthook__", - PyDict_GetItemString(sysdict, "excepthook")); + PyDict_GetItemString(sysdict, "excepthook")); SET_SYS_FROM_STRING("version", PyUnicode_FromString(Py_GetVersion())); SET_SYS_FROM_STRING("hexversion", @@ -1203,7 +1203,7 @@ _PySys_Init(void) Py_BuildValue("(UUU)", "CPython", branch, svn_revision)); SET_SYS_FROM_STRING("dont_write_bytecode", - PyBool_FromLong(Py_DontWriteBytecodeFlag)); + PyBool_FromLong(Py_DontWriteBytecodeFlag)); /* * These release level checks are mutually exclusive and cover * the field, so don't get too fancy with the pre-processor! -- cgit v0.12