]> granicus.if.org Git - python/commitdiff
Merged revisions 57221-57391 via svnmerge from
authorGuido van Rossum <guido@python.org>
Fri, 24 Aug 2007 16:32:05 +0000 (16:32 +0000)
committerGuido van Rossum <guido@python.org>
Fri, 24 Aug 2007 16:32:05 +0000 (16:32 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r57227 | facundo.batista | 2007-08-20 17:16:21 -0700 (Mon, 20 Aug 2007) | 5 lines

  Catch ProtocolError exceptions and include the header information in
  test output (to make it easier to debug test failures caused by
  problems in the server). [GSoC - Alan McIntyre]
........
  r57229 | mark.hammond | 2007-08-20 18:04:47 -0700 (Mon, 20 Aug 2007) | 5 lines

  [ 1761786 ] distutils.util.get_platform() return value on 64bit Windows
  As discussed on distutils-sig: Allows the generated installer name on
  64bit Windows platforms to be different than the name generated for
  32bit Windows platforms.
........
  r57230 | mark.hammond | 2007-08-20 18:05:16 -0700 (Mon, 20 Aug 2007) | 5 lines

  [ 1761786 ] distutils.util.get_platform() return value on 64bit Windows
  As discussed on distutils-sig: Allows the generated installer name on
  64bit Windows platforms to be different than the name generated for
  32bit Windows platforms.
........
  r57253 | georg.brandl | 2007-08-20 23:01:18 -0700 (Mon, 20 Aug 2007) | 2 lines

  Demand version 2.5.1 since 2.5 has a bug with codecs.open context managers.
........
  r57254 | georg.brandl | 2007-08-20 23:03:43 -0700 (Mon, 20 Aug 2007) | 2 lines

  Revert accidental checkins from last commit.
........
  r57255 | georg.brandl | 2007-08-20 23:07:08 -0700 (Mon, 20 Aug 2007) | 2 lines

  Bug #1777160: mention explicitly that e.g. -1**2 is -1.
........
  r57256 | georg.brandl | 2007-08-20 23:12:19 -0700 (Mon, 20 Aug 2007) | 3 lines

  Bug #1777168: replace operator names "opa"... with "op1"... and mark everything up as literal,
  to enhance readability.
........
  r57259 | facundo.batista | 2007-08-21 09:57:18 -0700 (Tue, 21 Aug 2007) | 8 lines

  Added test for behavior of operations on an unconnected SMTP object,
  and tests for NOOP, RSET, and VRFY. Corrected typo in a comment for
  testNonnumericPort. Added a check for constructing SMTP objects when
  non-numeric ports are included in the host name. Derived a server from
  SMTPServer to test various ESMTP/SMTP capabilities. Check that a
  second HELO to DebuggingServer returns an error. [GSoC - Alan McIntyre]
........
  r57279 | skip.montanaro | 2007-08-22 12:02:16 -0700 (Wed, 22 Aug 2007) | 2 lines

  Note that BeOS is unsupported as of Python 2.6.
........
  r57280 | skip.montanaro | 2007-08-22 12:05:21 -0700 (Wed, 22 Aug 2007) | 1 line

  whoops - need to check in configure as well
........
  r57284 | alex.martelli | 2007-08-22 14:14:17 -0700 (Wed, 22 Aug 2007) | 5 lines

  Fix compile.c so that it records 0.0 and -0.0 as separate constants in a code
  object's co_consts tuple; add a test to show that the previous behavior (where
  these two constants were "collapsed" into one) causes serious malfunctioning.
........
  r57286 | gregory.p.smith | 2007-08-22 14:32:34 -0700 (Wed, 22 Aug 2007) | 3 lines

  stop leaving log.0000001 __db.00* and xxx.db turds in developer
  sandboxes when bsddb3 tests are run.
........
  r57301 | jeffrey.yasskin | 2007-08-22 16:14:27 -0700 (Wed, 22 Aug 2007) | 3 lines

  When setup.py fails to find the necessary bits to build some modules, have it
  print a slightly more informative message.
........
  r57320 | brett.cannon | 2007-08-23 07:53:17 -0700 (Thu, 23 Aug 2007) | 2 lines

  Make test_runpy re-entrant.
........
  r57324 | georg.brandl | 2007-08-23 10:54:11 -0700 (Thu, 23 Aug 2007) | 2 lines

  Bug #1768121: fix wrong/missing opcode docs.
........
  r57326 | georg.brandl | 2007-08-23 10:57:05 -0700 (Thu, 23 Aug 2007) | 2 lines

  Bug #1766421: "return code" vs. "status code".
........
  r57328 | georg.brandl | 2007-08-23 11:08:06 -0700 (Thu, 23 Aug 2007) | 2 lines

  Second half of #1752175: #ifdef out references to PyImport_DynLoadFiletab if HAVE_DYNAMIC_LOADING is not defined.
........
  r57331 | georg.brandl | 2007-08-23 11:11:33 -0700 (Thu, 23 Aug 2007) | 2 lines

  Use try-except-finally in contextlib.
........
  r57343 | georg.brandl | 2007-08-23 13:35:00 -0700 (Thu, 23 Aug 2007) | 2 lines

  Bug #1697820: document that the old slice protocol is still used by builtin types.
........
  r57345 | georg.brandl | 2007-08-23 13:40:01 -0700 (Thu, 23 Aug 2007) | 2 lines

  Bug #1573854: fix docs for sqlite3 cursor rowcount attr.
........
  r57347 | georg.brandl | 2007-08-23 13:50:23 -0700 (Thu, 23 Aug 2007) | 2 lines

  Bug #1694833: fix imp.find_module() docs wrt. packages.
........
  r57348 | georg.brandl | 2007-08-23 13:53:28 -0700 (Thu, 23 Aug 2007) | 2 lines

  Bug #1594966: fix misleading usage example
........
  r57349 | georg.brandl | 2007-08-23 13:55:44 -0700 (Thu, 23 Aug 2007) | 2 lines

  Clarify wording a bit.
........
  r57351 | georg.brandl | 2007-08-23 14:18:44 -0700 (Thu, 23 Aug 2007) | 2 lines

  Bug #1752332: httplib no longer uses socket.getaddrinfo().
........
  r57352 | georg.brandl | 2007-08-23 14:21:36 -0700 (Thu, 23 Aug 2007) | 2 lines

  Bug #1734111: document struct.Struct.size.
........
  r57353 | georg.brandl | 2007-08-23 14:27:57 -0700 (Thu, 23 Aug 2007) | 2 lines

  Bug #1688564: document os.path.join's absolute path behavior in the docstring.
........
  r57354 | georg.brandl | 2007-08-23 14:36:05 -0700 (Thu, 23 Aug 2007) | 2 lines

  Bug #1625381: clarify match vs search introduction.
........
  r57355 | georg.brandl | 2007-08-23 14:42:54 -0700 (Thu, 23 Aug 2007) | 2 lines

  Bug #1758696: more info about descriptors.
........
  r57357 | georg.brandl | 2007-08-23 14:55:57 -0700 (Thu, 23 Aug 2007) | 2 lines

  Patch #1779550: remove redundant code in logging.
........
  r57378 | gregory.p.smith | 2007-08-23 22:11:38 -0700 (Thu, 23 Aug 2007) | 2 lines

  Fix bug 1725856.
........
  r57382 | georg.brandl | 2007-08-23 23:10:01 -0700 (Thu, 23 Aug 2007) | 2 lines

  uuid creation is now threadsafe, backport from py3k rev. 57375.
........
  r57389 | georg.brandl | 2007-08-24 04:47:37 -0700 (Fri, 24 Aug 2007) | 2 lines

  Bug #1765375: fix stripping of unwanted LDFLAGS.
........
  r57391 | guido.van.rossum | 2007-08-24 07:53:14 -0700 (Fri, 24 Aug 2007) | 2 lines

  Fix silly typo in test name.
........

25 files changed:
Doc/library/dis.rst
Doc/library/doctest.rst
Doc/library/imp.rst
Doc/library/re.rst
Doc/library/socket.rst
Doc/library/sqlite3.rst
Doc/library/struct.rst
Doc/reference/datamodel.rst
Doc/reference/expressions.rst
Doc/tools/sphinx-build.py
Lib/contextlib.py
Lib/distutils/command/bdist_msi.py
Lib/distutils/util.py
Lib/logging/__init__.py
Lib/ntpath.py
Lib/posixpath.py
Lib/smtplib.py
Lib/test/test_datetime.py
Lib/test/test_float.py
Lib/test/test_runpy.py
Lib/test/test_smtplib.py
Lib/test/test_xmlrpc.py
Python/compile.c
Python/import.c
setup.py

index 5f2847305cb5b6940c4fa068bd84ebfa8233bacb..7ce864d6e434a665ae3c7403d51a409b4c98bd4a 100644 (file)
@@ -474,10 +474,29 @@ Miscellaneous opcodes.
    Creates a new class object.  TOS is the methods dictionary, TOS1 the tuple of
    the names of the base classes, and TOS2 the class name.
 
+
+.. opcode:: WITH_CLEANUP ()
+
+   Cleans up the stack when a :keyword:`with` statement block exits.  TOS is the
+   context manager's :meth:`__exit__` bound method.  Below that are 1--3 values
+   indicating how/why the finally clause was entered:
+
+   * SECOND = None
+   * (SECOND, THIRD) = (WHY_{RETURN,CONTINUE}), retval
+   * SECOND = WHY_\*; no retval below it
+   * (SECOND, THIRD, FOURTH) = exc_info()
+
+   In the last case, ``TOS(SECOND, THIRD, FOURTH)`` is called, otherwise
+   ``TOS(None, None, None)``.
+
+   In addition, if the stack represents an exception, *and* the function call
+   returns a 'true' value, this information is "zapped", to prevent ``END_FINALLY``
+   from re-raising the exception.  (But non-local gotos should still be resumed.)
+
+
 All of the following opcodes expect arguments.  An argument is two bytes, with
 the more significant byte last.
 
-
 .. opcode:: STORE_NAME (namei)
 
    Implements ``name = TOS``. *namei* is the index of *name* in the attribute
@@ -722,11 +741,10 @@ the more significant byte last.
 
 .. opcode:: MAKE_CLOSURE (argc)
 
-   Creates a new function object, sets its *__closure__* slot, and pushes it on the
-   stack.  TOS is the code associated with the function. If the code object has N
-   free variables, the next N items on the stack are the cells for these variables.
-   The function also has *argc* default parameters, where are found before the
-   cells.
+   Creates a new function object, sets its *__closure__* slot, and pushes it on
+   the stack.  TOS is the code associated with the function, TOS1 the tuple
+   containing cells for the closure's free variables.  The function also has
+   *argc* default parameters, which are found below the cells.
 
 
 .. opcode:: BUILD_SLICE (argc)
index 23f96e4ff27e2bc5df6459cca3365b1bbf3b7d0b..4f4f511e4264e846d6209b2cd1cadd48f59a0a04 100644 (file)
@@ -69,11 +69,6 @@ Here's a complete but small example module::
        OverflowError: n too large
        """
 
-
-.. % allow LaTeX to break here.
-
-::
-
        import math
        if not n >= 0:
            raise ValueError("n must be >= 0")
@@ -88,12 +83,10 @@ Here's a complete but small example module::
            factor += 1
        return result
 
-   def _test():
-       import doctest
-       doctest.testmod()
 
    if __name__ == "__main__":
-       _test()
+       import doctest
+       doctest.testmod()
 
 If you run :file:`example.py` directly from the command line, :mod:`doctest`
 works its magic::
@@ -131,12 +124,10 @@ And so on, eventually ending with::
            ...
        OverflowError: n too large
    ok
-   1 items had no tests:
-       __main__._test
    2 items passed all tests:
       1 tests in __main__
       8 tests in __main__.factorial
-   9 tests in 3 items.
+   9 tests in 2 items.
    9 passed and 0 failed.
    Test passed.
    $
@@ -156,13 +147,10 @@ Simple Usage: Checking Examples in Docstrings
 The simplest way to start using doctest (but not necessarily the way you'll
 continue to do it) is to end each module :mod:`M` with::
 
-   def _test():
+   if __name__ == "__main__":
        import doctest
        doctest.testmod()
 
-   if __name__ == "__main__":
-       _test()
-
 :mod:`doctest` then examines docstrings in module :mod:`M`.
 
 Running the module as a script causes the examples in the docstrings to get
index f80bea34dde26f790f39ef7fc8976625bdf3c63a..7943604a9f8713555d0f29be48c5a49f3cd8d3b8 100644 (file)
@@ -22,63 +22,73 @@ This module provides an interface to the mechanisms used to implement the
 
 .. function:: get_suffixes()
 
-   Return a list of triples, each describing a particular type of module. Each
-   triple has the form ``(suffix, mode, type)``, where *suffix* is a string to be
-   appended to the module name to form the filename to search for, *mode* is the
-   mode string to pass to the built-in :func:`open` function to open the file (this
-   can be ``'r'`` for text files or ``'rb'`` for binary files), and *type* is the
-   file type, which has one of the values :const:`PY_SOURCE`, :const:`PY_COMPILED`,
-   or :const:`C_EXTENSION`, described below.
+   Return a list of 3-element tuples, each describing a particular type of
+   module. Each triple has the form ``(suffix, mode, type)``, where *suffix* is
+   a string to be appended to the module name to form the filename to search
+   for, *mode* is the mode string to pass to the built-in :func:`open` function
+   to open the file (this can be ``'r'`` for text files or ``'rb'`` for binary
+   files), and *type* is the file type, which has one of the values
+   :const:`PY_SOURCE`, :const:`PY_COMPILED`, or :const:`C_EXTENSION`, described
+   below.
 
 
 .. function:: find_module(name[, path])
 
-   Try to find the module *name* on the search path *path*.  If *path* is a list of
-   directory names, each directory is searched for files with any of the suffixes
-   returned by :func:`get_suffixes` above.  Invalid names in the list are silently
-   ignored (but all list items must be strings).  If *path* is omitted or ``None``,
-   the list of directory names given by ``sys.path`` is searched, but first it
-   searches a few special places: it tries to find a built-in module with the given
-   name (:const:`C_BUILTIN`), then a frozen module (:const:`PY_FROZEN`), and on
-   some systems some other places are looked in as well (on the Mac, it looks for a
-   resource (:const:`PY_RESOURCE`); on Windows, it looks in the registry which may
-   point to a specific file).
-
-   If search is successful, the return value is a triple ``(file, pathname,
-   description)`` where *file* is an open file object positioned at the beginning,
-   *pathname* is the pathname of the file found, and *description* is a triple as
+   Try to find the module *name* on the search path *path*.  If *path* is a list
+   of directory names, each directory is searched for files with any of the
+   suffixes returned by :func:`get_suffixes` above.  Invalid names in the list
+   are silently ignored (but all list items must be strings).  If *path* is
+   omitted or ``None``, the list of directory names given by ``sys.path`` is
+   searched, but first it searches a few special places: it tries to find a
+   built-in module with the given name (:const:`C_BUILTIN`), then a frozen
+   module (:const:`PY_FROZEN`), and on some systems some other places are looked
+   in as well (on the Mac, it looks for a resource (:const:`PY_RESOURCE`); on
+   Windows, it looks in the registry which may point to a specific file).
+
+   If search is successful, the return value is a 3-element tuple ``(file,
+   pathname, description)``:
+
+   *file* is an open file object positioned at the beginning, *pathname* is the
+   pathname of the file found, and *description* is a 3-element tuple as
    contained in the list returned by :func:`get_suffixes` describing the kind of
-   module found. If the module does not live in a file, the returned *file* is
-   ``None``, *filename* is the empty string, and the *description* tuple contains
-   empty strings for its suffix and mode; the module type is as indicate in
-   parentheses above.  If the search is unsuccessful, :exc:`ImportError` is raised.
-   Other exceptions indicate problems with the arguments or environment.
-
-   This function does not handle hierarchical module names (names containing dots).
-   In order to find *P*.*M*, that is, submodule *M* of package *P*, use
+   module found.
+
+   If the module does not live in a file, the returned *file* is ``None``,
+   *pathname* is the empty string, and the *description* tuple contains empty
+   strings for its suffix and mode; the module type is indicated as given in
+   parentheses above.  If the search is unsuccessful, :exc:`ImportError` is
+   raised.  Other exceptions indicate problems with the arguments or
+   environment.
+
+   If the module is a package, *file* is ``None``, *pathname* is the package
+   path and the last item in the *description* tuple is :const:`PKG_DIRECTORY`.
+
+   This function does not handle hierarchical module names (names containing
+   dots).  In order to find *P*.*M*, that is, submodule *M* of package *P*, use
    :func:`find_module` and :func:`load_module` to find and load package *P*, and
    then use :func:`find_module` with the *path* argument set to ``P.__path__``.
    When *P* itself has a dotted name, apply this recipe recursively.
 
 
-.. function:: load_module(name, file, filename, description)
+.. function:: load_module(name, file, pathname, description)
 
    Load a module that was previously found by :func:`find_module` (or by an
    otherwise conducted search yielding compatible results).  This function does
    more than importing the module: if the module was already imported, it will
-   reload the module! The *name* argument indicates the full module name (including
-   the package name, if this is a submodule of a package).  The *file* argument is
-   an open file, and *filename* is the corresponding file name; these can be
-   ``None`` and ``''``, respectively, when the module is not being loaded from a
-   file.  The *description* argument is a tuple, as would be returned by
-   :func:`get_suffixes`, describing what kind of module must be loaded.
-
-   If the load is successful, the return value is the module object; otherwise, an
-   exception (usually :exc:`ImportError`) is raised.
-
-   **Important:** the caller is responsible for closing the *file* argument, if it
-   was not ``None``, even when an exception is raised.  This is best done using a
-   :keyword:`try` ... :keyword:`finally` statement.
+   reload the module!  The *name* argument indicates the full
+   module name (including the package name, if this is a submodule of a
+   package).  The *file* argument is an open file, and *pathname* is the
+   corresponding file name; these can be ``None`` and ``''``, respectively, when
+   the module is a package or not being loaded from a file.  The *description*
+   argument is a tuple, as would be returned by :func:`get_suffixes`, describing
+   what kind of module must be loaded.
+
+   If the load is successful, the return value is the module object; otherwise,
+   an exception (usually :exc:`ImportError`) is raised.
+
+   **Important:** the caller is responsible for closing the *file* argument, if
+   it was not ``None``, even when an exception is raised.  This is best done
+   using a :keyword:`try` ... :keyword:`finally` statement.
 
 
 .. function:: new_module(name)
index 027ff16a1ccd8fcecf60ea67dc03c2be1763f17b..d5abcdd2a270a2930bf43316b5e9d85a33081b6a 100644 (file)
@@ -393,12 +393,12 @@ Matching vs Searching
 
 
 Python offers two different primitive operations based on regular expressions:
-match and search.  If you are accustomed to Perl's semantics, the search
-operation is what you're looking for.  See the :func:`search` function and
-corresponding method of compiled regular expression objects.
+**match** checks for a match only at the beginning of the string, while
+**search** checks for a match anywhere in the string (this is what Perl does
+by default).
 
-Note that match may differ from search using a regular expression beginning with
-``'^'``: ``'^'`` matches only at the start of the string, or in
+Note that match may differ from search even when using a regular expression
+beginning with ``'^'``: ``'^'`` matches only at the start of the string, or in
 :const:`MULTILINE` mode also immediately following a newline.  The "match"
 operation succeeds only if the pattern matches at the start of the string
 regardless of mode, or at the starting position given by the optional *pos*
index 68a32fe851f9ee9a398c3b120c5a701f597718b3..46774a3589b8018d760edc7ef3603ff6c90353f5 100644 (file)
@@ -197,7 +197,7 @@ The module :mod:`socket` exports the following constants and functions:
    :func:`socket` function. *canonname* is a string representing the canonical name
    of the *host*. It can be a numeric IPv4/v6 address when :const:`AI_CANONNAME` is
    specified for a numeric *host*. *sockaddr* is a tuple describing a socket
-   address, as described above. See the source for the :mod:`httplib` and other
+   address, as described above. See the source for :mod:`socket` and other
    library modules for a typical usage of the function.
 
    .. versionadded:: 2.2
index 707092b027f1a50160e036c04aea1df3ddbd296e..bee32e67bf158784daec2d6f39ad1a81fd582942 100644 (file)
@@ -440,9 +440,6 @@ A :class:`Cursor` instance has the following attributes and methods:
    attribute, the database engine's own support for the determination of "rows
    affected"/"rows selected" is quirky.
 
-   For ``SELECT`` statements, :attr:`rowcount` is always None because we cannot
-   determine the number of rows a query produced until all rows were fetched.
-
    For ``DELETE`` statements, SQLite reports :attr:`rowcount` as 0 if you make a
    ``DELETE FROM table`` without any condition.
 
@@ -453,6 +450,9 @@ A :class:`Cursor` instance has the following attributes and methods:
    case no executeXX() has been performed on the cursor or the rowcount of the last
    operation is not determinable by the interface".
 
+   This includes ``SELECT`` statements because we cannot determine the number of
+   rows a query produced until all rows were fetched.
+
 
 .. _sqlite3-types:
 
index 2f27d13ca7b7f127066839565c8ced9a8e30bf38..9cf4eb2945a62e692defbc7cc1d01e14aded96d0 100644 (file)
@@ -290,3 +290,8 @@ Compiled Struct objects support the following methods and attributes:
 
    The format string used to construct this Struct object.
 
+.. attribute:: Struct.size
+
+   The calculated size of the struct (and hence of the string) corresponding
+   to :attr:`format`.
+
index 2f6013e48ea0b8882c2e5dc831bee432a316202f..baa6eaa9828ae236830119376acf4852eccada4e 100644 (file)
@@ -1544,11 +1544,11 @@ Super Binding
    ``A.__dict__['m'].__get__(obj, A)``.
 
 For instance bindings, the precedence of descriptor invocation depends on the
-which descriptor methods are defined.  Data descriptors define both
-:meth:`__get__` and :meth:`__set__`.  Non-data descriptors have just the
+which descriptor methods are defined.  Normally, data descriptors define both
+:meth:`__get__` and :meth:`__set__`, while non-data descriptors have just the
 :meth:`__get__` method.  Data descriptors always override a redefinition in an
 instance dictionary.  In contrast, non-data descriptors can be overridden by
-instances.
+instances. [#]_
 
 Python methods (including :func:`staticmethod` and :func:`classmethod`) are
 implemented as non-data descriptors.  Accordingly, instances can redefine and
@@ -1817,6 +1817,9 @@ objects.  Immutable sequences methods should at most only define
 
    .. deprecated:: 2.0
       Support slice objects as parameters to the :meth:`__getitem__` method.
+      (However, built-in types in CPython currently still implement
+      :meth:`__getslice__`.  Therefore, you have to override it in derived
+      classes when implementing slicing.)
 
    Called to implement evaluation of ``self[i:j]``. The returned object should be
    of the same type as *self*.  Note that missing *i* or *j* in the slice
@@ -2112,6 +2115,13 @@ For more information on context managers, see :ref:`typecontextmanager`.
 .. [#] This, and other statements, are only roughly true for instances of new-style
    classes.
 
+.. [#] A descriptor can define any combination of :meth:`__get__`,
+   :meth:`__set__` and :meth:`__delete__`.  If it does not define :meth:`__get__`,
+   then accessing the attribute even on an instance will return the descriptor
+   object itself.  If the descriptor defines :meth:`__set__` and/or
+   :meth:`__delete__`, it is a data descriptor; if it defines neither, it is a
+   non-data descriptor.
+
 .. [#] For operands of the same type, it is assumed that if the non-reflected method
    (such as :meth:`__add__`) fails the operation is not supported, which is why the
    reflected method is not called.
index 476c82df4bb59684cc2a9a50db9232d5f39b3525..ef71a80f14584643a34e1b77bb1fecee20e44183 100644 (file)
@@ -741,7 +741,7 @@ less tightly than unary operators on its right.  The syntax is:
 
 Thus, in an unparenthesized sequence of power and unary operators, the operators
 are evaluated from right to left (this does not constrain the evaluation order
-for the operands).
+for the operands): ``-1**2`` results in ``-1``.
 
 The power operator has the same semantics as the built-in :func:`pow` function,
 when called with two arguments: it yields its left argument raised to the power
@@ -959,12 +959,12 @@ Comparisons can be chained arbitrarily, e.g., ``x < y <= z`` is equivalent to
 ``x < y and y <= z``, except that ``y`` is evaluated only once (but in both
 cases ``z`` is not evaluated at all when ``x < y`` is found to be false).
 
-Formally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *opa*, *opb*, ...,
-*opy* are comparison operators, then *a opa b opb c* ...*y opy z* is equivalent
-to *a opa b* :keyword:`and` *b opb c* :keyword:`and` ... *y opy z*, except that
-each expression is evaluated at most once.
+Formally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*, *op2*, ...,
+*opN* are comparison operators, then ``a op1 b op2 c ... y opN z`` is equivalent
+to ``a op1 b and b op2 c and ... y opN z``, except that each expression is
+evaluated at most once.
 
-Note that *a opa b opb c* doesn't imply any kind of comparison between *a* and
+Note that ``a op1 b op2 c`` doesn't imply any kind of comparison between *a* and
 *c*, so that, e.g., ``x < y > z`` is perfectly legal (though perhaps not
 pretty).
 
index e19b10a04a86f3d5b91ac8a8cde7fdc45f363984..8f952be22bc00e7624139034b6011982375e3ad6 100644 (file)
@@ -11,9 +11,9 @@ import sys
 
 if __name__ == '__main__':
 
-    if sys.version_info[:3] < (2, 5, 0):
+    if sys.version_info[:3] < (2, 5, 1):
         print >>sys.stderr, """\
-Error: Sphinx needs to be executed with Python 2.5 or newer
+Error: Sphinx needs to be executed with Python 2.5.1 or newer
 (If you run this from the Makefile, you can set the PYTHON variable
 to the path of an alternative interpreter executable, e.g.,
 ``make html PYTHON=python2.5``).
index 6605bea23789f527eb01cb11a42e0af460c77051..bc810b0bc83e04c8c1eda941b50951647f0a92da 100644 (file)
@@ -105,15 +105,14 @@ def nested(*managers):
     vars = []
     exc = (None, None, None)
     try:
-        try:
-            for mgr in managers:
-                exit = mgr.__exit__
-                enter = mgr.__enter__
-                vars.append(enter())
-                exits.append(exit)
-            yield vars
-        except:
-            exc = sys.exc_info()
+        for mgr in managers:
+            exit = mgr.__exit__
+            enter = mgr.__enter__
+            vars.append(enter())
+            exits.append(exit)
+        yield vars
+    except:
+        exc = sys.exc_info()
     finally:
         while exits:
             exit = exits.pop()
index 012d06ea69e332a1f131481320aedb8f5866eca8..5225bed1b2c1870e889561fa05e549f672dc7f8b 100644 (file)
@@ -633,7 +633,8 @@ class bdist_msi (Command):
 
     def get_installer_filename(self, fullname):
         # Factored out to allow overriding in subclasses
+        plat = get_platform()
         installer_name = os.path.join(self.dist_dir,
-                                      "%s.win32-py%s.msi" %
-                                       (fullname, self.target_version))
+                                      "%s.%s-py%s.msi" %
+                                       (fullname, plat, self.target_version))
         return installer_name
index 6f15ce8b5ed77d98cf0d15b56bbfc751fdca18d9..9aa857052a3abe1527b8b56720d2183b7f0c1cbb 100644 (file)
@@ -29,8 +29,27 @@ def get_platform ():
        irix-5.3
        irix64-6.2
 
-    For non-POSIX platforms, currently just returns 'sys.platform'.
+    Windows will return one of:
+       win-x86_64 (64bit Windows on x86_64 (AMD64))
+       win-ia64 (64bit Windows on Itanium)
+       win32 (all others - specifically, sys.platform is returned)
+
+    For other non-POSIX platforms, currently just returns 'sys.platform'.
     """
+    if os.name == 'nt':
+        # sniff sys.version for architecture.
+        prefix = " bit ("
+        i = string.find(sys.version, prefix)
+        if i == -1:
+            return sys.platform
+        j = string.find(sys.version, ")", i)
+        look = sys.version[i+len(prefix):j].lower()
+        if look=='amd64':
+            return 'win-x86_64'
+        if look=='itanium':
+            return 'win-ia64'
+        return sys.platform
+
     if os.name != "posix" or not hasattr(os, 'uname'):
         # XXX what about the architecture? NT is Intel or Alpha,
         # Mac OS is M68k or PPC, etc.
index 229be69b12a68dffcea24ad1f354b23b5c255cf4..ef7842222726dfc141e9f2f0dc9ad8d4a69392e7 100644 (file)
@@ -975,9 +975,7 @@ class Logger(Filterer):
 
         logger.debug("Houston, we have a %s", "thorny problem", exc_info=1)
         """
-        if self.manager.disable >= DEBUG:
-            return
-        if DEBUG >= self.getEffectiveLevel():
+        if self.isEnabledFor(DEBUG):
             self._log(DEBUG, msg, args, **kwargs)
 
     def info(self, msg, *args, **kwargs):
@@ -989,9 +987,7 @@ class Logger(Filterer):
 
         logger.info("Houston, we have a %s", "interesting problem", exc_info=1)
         """
-        if self.manager.disable >= INFO:
-            return
-        if INFO >= self.getEffectiveLevel():
+        if self.isEnabledFor(INFO):
             self._log(INFO, msg, args, **kwargs)
 
     def warning(self, msg, *args, **kwargs):
@@ -1003,8 +999,6 @@ class Logger(Filterer):
 
         logger.warning("Houston, we have a %s", "bit of a problem", exc_info=1)
         """
-        if self.manager.disable >= WARNING:
-            return
         if self.isEnabledFor(WARNING):
             self._log(WARNING, msg, args, **kwargs)
 
@@ -1019,8 +1013,6 @@ class Logger(Filterer):
 
         logger.error("Houston, we have a %s", "major problem", exc_info=1)
         """
-        if self.manager.disable >= ERROR:
-            return
         if self.isEnabledFor(ERROR):
             self._log(ERROR, msg, args, **kwargs)
 
@@ -1039,9 +1031,7 @@ class Logger(Filterer):
 
         logger.critical("Houston, we have a %s", "major disaster", exc_info=1)
         """
-        if self.manager.disable >= CRITICAL:
-            return
-        if CRITICAL >= self.getEffectiveLevel():
+        if self.isEnabledFor(CRITICAL):
             self._log(CRITICAL, msg, args, **kwargs)
 
     fatal = critical
@@ -1060,8 +1050,6 @@ class Logger(Filterer):
                 raise TypeError, "level must be an integer"
             else:
                 return
-        if self.manager.disable >= level:
-            return
         if self.isEnabledFor(level):
             self._log(level, msg, args, **kwargs)
 
index 99d7a4a8cdcf73dabfb40caa605d3e468ae5b43c..06b2293293ee1cb179cb04aa50a8b4dcb2392d64 100644 (file)
@@ -59,7 +59,9 @@ def isabs(s):
 # Join two (or more) paths.
 
 def join(a, *p):
-    """Join two or more pathname components, inserting "\\" as needed"""
+    """Join two or more pathname components, inserting "\\" as needed.
+    If any component is an absolute path, all previous path components
+    will be discarded."""
     path = a
     for b in p:
         b_wins = 0  # set to 1 iff b makes path irrelevant
index 6f15d48f127aac820741711edbe2fece1f96672d..6d4a9e2111bd5d4631bc081f215266daa34a3745 100644 (file)
@@ -56,7 +56,9 @@ def isabs(s):
 # Insert a '/' unless the first part is empty or already ends in '/'.
 
 def join(a, *p):
-    """Join two or more pathname components, inserting '/' as needed"""
+    """Join two or more pathname components, inserting '/' as needed.
+    If any component is an absolute path, all previous path components
+    will be discarded."""
     path = a
     for b in p:
         if b.startswith('/'):
index 0d61f50142fc7ba1b9441a539d9ac05c9648a5ea..301f4fe9b3fc842875f20807f34e538a179f3982 100755 (executable)
@@ -401,7 +401,8 @@ class SMTP:
             return (code,msg)
         self.does_esmtp=1
         #parse the ehlo response -ddm
-        resp=self.ehlo_resp.split('\n')
+        assert isinstance(self.ehlo_resp, bytes), repr(self.ehlo_resp)
+        resp=self.ehlo_resp.decode("latin-1").split('\n')
         del resp[0]
         for each in resp:
             # To be able to communicate with as many SMTP servers as possible,
index c0a96efdc97e0a9846ea2e1269e8c7b7f5fc5b51..b26c92e21e3fb1f73a58b4646d7808de5aa38e76 100644 (file)
@@ -1003,7 +1003,7 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase):
         self.failUnless(self.theclass.min)
         self.failUnless(self.theclass.max)
 
-    def test_srftime_out_of_range(self):
+    def test_strftime_out_of_range(self):
         # For nasty technical reasons, we can't handle years before 1900.
         cls = self.theclass
         self.assertEqual(cls(1900, 1, 1).strftime("%Y"), "1900")
index 4f4cffd2012de3c05244bdcec328cc92093384e0..48abec95f560f37d0d5595cd90bee60ff3cebd01 100644 (file)
@@ -81,6 +81,7 @@ class UnknownFormatTestCase(unittest.TestCase):
 # on an IEEE platform, all we guarantee is that bit patterns
 # representing infinities or NaNs do not raise an exception; all else
 # is accident (today).
+# let's also try to guarantee that -0.0 and 0.0 don't get confused.
 
 class IEEEFormatTestCase(unittest.TestCase):
     if float.__getformat__("double").startswith("IEEE"):
@@ -99,6 +100,20 @@ class IEEEFormatTestCase(unittest.TestCase):
                               ('<f', LE_FLOAT_NAN)]:
                 struct.unpack(fmt, data)
 
+    if float.__getformat__("double").startswith("IEEE"):
+        def test_negative_zero(self):
+            import math
+            def pos_pos():
+                return 0.0, math.atan2(0.0, -1)
+            def pos_neg():
+                return 0.0, math.atan2(-0.0, -1)
+            def neg_pos():
+                return -0.0, math.atan2(0.0, -1)
+            def neg_neg():
+                return -0.0, math.atan2(-0.0, -1)
+            self.assertEquals(pos_pos(), neg_pos())
+            self.assertEquals(pos_neg(), neg_neg())
+
 
 def test_main():
     test_support.run_unittest(
index 0fcec1e9c6f7c3fda4b116d20dce103e7afbaf15..b628d771d01c6103f4f8e8791636be37890369d6 100644 (file)
@@ -4,7 +4,7 @@ import os
 import os.path
 import sys
 import tempfile
-from test.test_support import verbose, run_unittest
+from test.test_support import verbose, run_unittest, forget
 from runpy import _run_module_code, run_module
 
 # Set up the test code and expected results
@@ -156,6 +156,7 @@ class RunModuleTest(unittest.TestCase):
     def _check_module(self, depth):
         pkg_dir, mod_fname, mod_name = (
                self._make_pkg("x=1\n", depth))
+        forget(mod_name)
         try:
             if verbose: print("Running from source:", mod_name)
             d1 = run_module(mod_name) # Read from source
index cf92662a4453b4c29e2a10ee5b2ba8e95d817108..c2bd1965ac7640665ab03a966967d9ca3ffd980a 100644 (file)
@@ -1,4 +1,5 @@
 import asyncore
+import email.utils
 import socket
 import threading
 import smtpd
@@ -75,6 +76,15 @@ class GeneralTests(TestCase):
         smtp = smtplib.SMTP("%s:%s" % (HOST, PORT))
         smtp.sock.close()
 
+    def testNotConnected(self):
+        # Test various operations on an unconnected SMTP object that
+        # should raise exceptions (at present the attempt in SMTP.send
+        # to reference the nonexistent 'sock' attribute of the SMTP object
+        # causes an AttributeError)
+        smtp = smtplib.SMTP()
+        self.assertRaises(AttributeError, smtp.ehlo)
+        self.assertRaises(AttributeError, smtp.send, 'test msg')
+
     def testLocalHostName(self):
         # check that supplied local_hostname is used
         smtp = smtplib.SMTP(HOST, PORT, local_hostname="testhost")
@@ -82,9 +92,11 @@ class GeneralTests(TestCase):
         smtp.sock.close()
 
     def testNonnumericPort(self):
-        # check that non-numeric port raises ValueError
+        # check that non-numeric port raises socket.error
         self.assertRaises(socket.error, smtplib.SMTP,
                           "localhost", "bogus")
+        self.assertRaises(socket.error, smtplib.SMTP,
+                          "localhost:bogus")
 
     def testTimeoutDefault(self):
         # default
@@ -110,9 +122,9 @@ class GeneralTests(TestCase):
         smtp.sock.close()
 
 
-# Test server using smtpd.DebuggingServer
-def debugging_server(serv_evt, client_evt):
-    serv = smtpd.DebuggingServer(("", 0), ('nowhere', -1))
+# Test server thread using the specified SMTP server class
+def debugging_server(server_class, serv_evt, client_evt):
+    serv = server_class(("", 0), ('nowhere', -1))
     global PORT
     PORT = serv.getsockname()[1]
 
@@ -148,11 +160,12 @@ def debugging_server(serv_evt, client_evt):
 MSG_BEGIN = '---------- MESSAGE FOLLOWS ----------\n'
 MSG_END = '------------ END MESSAGE ------------\n'
 
-# Test behavior of smtpd.DebuggingServer
-# NOTE: the SMTP objects are created with a non-default local_hostname
-# argument to the constructor, since (on some systems) the FQDN lookup
-# caused by the default local_hostname sometimes takes so long that the
+# NOTE: Some SMTP objects in the tests below are created with a non-default
+# local_hostname argument to the constructor, since (on some systems) the FQDN
+# lookup caused by the default local_hostname sometimes takes so long that the
 # test server times out, causing the test to fail.
+
+# Test behavior of smtpd.DebuggingServer
 class DebuggingServerTests(TestCase):
 
     def setUp(self):
@@ -163,7 +176,7 @@ class DebuggingServerTests(TestCase):
 
         self.serv_evt = threading.Event()
         self.client_evt = threading.Event()
-        serv_args = (self.serv_evt, self.client_evt)
+        serv_args = (smtpd.DebuggingServer, self.serv_evt, self.client_evt)
         threading.Thread(target=debugging_server, args=serv_args).start()
 
         # wait until server thread has assigned a port number
@@ -189,12 +202,42 @@ class DebuggingServerTests(TestCase):
         smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3)
         smtp.quit()
 
-    def testEHLO(self):
+    def testNOOP(self):
+        smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3)
+        expected = (250, b'Ok')
+        self.assertEqual(smtp.noop(), expected)
+        smtp.quit()
+
+    def testRSET(self):
+        smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3)
+        expected = (250, b'Ok')
+        self.assertEqual(smtp.rset(), expected)
+        smtp.quit()
+
+    def testNotImplemented(self):
+        # EHLO isn't implemented in DebuggingServer
         smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3)
         expected = (502, b'Error: command "EHLO" not implemented')
         self.assertEqual(smtp.ehlo(), expected)
         smtp.quit()
 
+    def testVRFY(self):
+        # VRFY isn't implemented in DebuggingServer
+        smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3)
+        expected = (502, b'Error: command "VRFY" not implemented')
+        self.assertEqual(smtp.vrfy('nobody@nowhere.com'), expected)
+        self.assertEqual(smtp.verify('nobody@nowhere.com'), expected)
+        smtp.quit()
+
+    def testSecondHELO(self):
+        # check that a second HELO returns a message that it's a duplicate
+        # (this behavior is specific to smtpd.SMTPChannel)
+        smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3)
+        smtp.helo()
+        expected = (503, b'Duplicate HELO/EHLO')
+        self.assertEqual(smtp.helo(), expected)
+        smtp.quit()
+
     def testHELP(self):
         smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3)
         self.assertEqual(smtp.help(), b'Error: command "HELP" not implemented')
@@ -214,6 +257,7 @@ class DebuggingServerTests(TestCase):
         self.assertEqual(self.output.getvalue(), mexpect)
 
 
+# test response of client to a non-successful HELO message
 class BadHELOServerTests(TestCase):
 
     def setUp(self):
@@ -243,9 +287,148 @@ class BadHELOServerTests(TestCase):
         self.assertRaises(smtplib.SMTPConnectError, smtplib.SMTP,
                             HOST, PORT, 'localhost', 3)
 
+
+sim_users = {'Mr.A@somewhere.com':'John A',
+             'Ms.B@somewhere.com':'Sally B',
+             'Mrs.C@somewhereesle.com':'Ruth C',
+            }
+
+sim_lists = {'list-1':['Mr.A@somewhere.com','Mrs.C@somewhereesle.com'],
+             'list-2':['Ms.B@somewhere.com',],
+            }
+
+# Simulated SMTP channel & server
+class SimSMTPChannel(smtpd.SMTPChannel):
+    def smtp_EHLO(self, arg):
+        resp = '250-testhost\r\n' \
+               '250-EXPN\r\n' \
+               '250-SIZE 20000000\r\n' \
+               '250-STARTTLS\r\n' \
+               '250-DELIVERBY\r\n' \
+               '250 HELP'
+        self.push(resp)
+
+    def smtp_VRFY(self, arg):
+#        print '\nsmtp_VRFY(%r)\n' % arg
+
+        raw_addr = email.utils.parseaddr(arg)[1]
+        quoted_addr = smtplib.quoteaddr(arg)
+        if raw_addr in sim_users:
+            self.push('250 %s %s' % (sim_users[raw_addr], quoted_addr))
+        else:
+            self.push('550 No such user: %s' % arg)
+
+    def smtp_EXPN(self, arg):
+#        print '\nsmtp_EXPN(%r)\n' % arg
+
+        list_name = email.utils.parseaddr(arg)[1].lower()
+        if list_name in sim_lists:
+            user_list = sim_lists[list_name]
+            for n, user_email in enumerate(user_list):
+                quoted_addr = smtplib.quoteaddr(user_email)
+                if n < len(user_list) - 1:
+                    self.push('250-%s %s' % (sim_users[user_email], quoted_addr))
+                else:
+                    self.push('250 %s %s' % (sim_users[user_email], quoted_addr))
+        else:
+            self.push('550 No access for you!')
+
+
+class SimSMTPServer(smtpd.SMTPServer):
+    def handle_accept(self):
+        conn, addr = self.accept()
+        channel = SimSMTPChannel(self, conn, addr)
+
+    def process_message(self, peer, mailfrom, rcpttos, data):
+        pass
+
+
+# Test various SMTP & ESMTP commands/behaviors that require a simulated server
+# (i.e., something with more features than DebuggingServer)
+class SMTPSimTests(TestCase):
+
+    def setUp(self):
+        self.serv_evt = threading.Event()
+        self.client_evt = threading.Event()
+        serv_args = (SimSMTPServer, self.serv_evt, self.client_evt)
+        threading.Thread(target=debugging_server, args=serv_args).start()
+
+        # wait until server thread has assigned a port number
+        n = 500
+        while PORT is None and n > 0:
+            time.sleep(0.01)
+            n -= 1
+
+        # wait a little longer (sometimes connections are refused
+        # on slow machines without this additional wait)
+        time.sleep(0.5)
+
+    def tearDown(self):
+        # indicate that the client is finished
+        self.client_evt.set()
+        # wait for the server thread to terminate
+        self.serv_evt.wait()
+
+    def testBasic(self):
+        # smoke test
+        smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3)
+        smtp.quit()
+
+    def testEHLO(self):
+        smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3)
+
+        # no features should be present before the EHLO
+        self.assertEqual(smtp.esmtp_features, {})
+
+        # features expected from the test server
+        expected_features = {'expn':'',
+                             'size': '20000000',
+                             'starttls': '',
+                             'deliverby': '',
+                             'help': '',
+                             }
+
+        smtp.ehlo()
+        self.assertEqual(smtp.esmtp_features, expected_features)
+        for k in expected_features:
+            self.assertTrue(smtp.has_extn(k))
+        self.assertFalse(smtp.has_extn('unsupported-feature'))
+        smtp.quit()
+
+    def testVRFY(self):
+        smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3)
+
+        for email, name in sim_users.items():
+            expected_known = (250, bytes('%s %s' %
+                                         (name, smtplib.quoteaddr(email))))
+            self.assertEqual(smtp.vrfy(email), expected_known)
+
+        u = 'nobody@nowhere.com'
+        expected_unknown = (550, bytes('No such user: %s'
+                                       % smtplib.quoteaddr(u)))
+        self.assertEqual(smtp.vrfy(u), expected_unknown)
+        smtp.quit()
+
+    def testEXPN(self):
+        smtp = smtplib.SMTP(HOST, PORT, local_hostname='localhost', timeout=3)
+
+        for listname, members in sim_lists.items():
+            users = []
+            for m in members:
+                users.append('%s %s' % (sim_users[m], smtplib.quoteaddr(m)))
+            expected_known = (250, bytes('\n'.join(users)))
+            self.assertEqual(smtp.expn(listname), expected_known)
+
+        u = 'PSU-Members-List'
+        expected_unknown = (550, b'No access for you!')
+        self.assertEqual(smtp.expn(u), expected_unknown)
+        smtp.quit()
+
+
+
 def test_main(verbose=None):
     test_support.run_unittest(GeneralTests, DebuggingServerTests,
-                              BadHELOServerTests)
+                              BadHELOServerTests, SMTPSimTests)
 
 if __name__ == '__main__':
     test_main()
index 7dfabcf415ff98018c6501840fe818258f76f39d..18e130da0f8676f8495ff93341e8587b53b206f8 100644 (file)
@@ -303,38 +303,58 @@ class SimpleServerTestCase(unittest.TestCase):
         SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
 
     def test_simple1(self):
-        p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
-        self.assertEqual(p.pow(6,8), 6**8)
+        try:
+            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
+            self.assertEqual(p.pow(6,8), 6**8)
+        except xmlrpclib.ProtocolError, e:
+            # protocol error; provide additional information in test output
+            self.fail("%s\n%s" % (e, e.headers))
 
     def test_introspection1(self):
-        p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
-        meth = p.system.listMethods()
-        expected_methods = set(['pow', 'div', 'add', 'system.listMethods',
-            'system.methodHelp', 'system.methodSignature', 'system.multicall'])
-        self.assertEqual(set(meth), expected_methods)
+        try:
+            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
+            meth = p.system.listMethods()
+            expected_methods = set(['pow', 'div', 'add', 'system.listMethods',
+                'system.methodHelp', 'system.methodSignature', 'system.multicall'])
+            self.assertEqual(set(meth), expected_methods)
+        except xmlrpclib.ProtocolError, e:
+            # protocol error; provide additional information in test output
+            self.fail("%s\n%s" % (e, e.headers))
 
     def test_introspection2(self):
-        p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
-        divhelp = p.system.methodHelp('div')
-        self.assertEqual(divhelp, 'This is the div function')
+        try:
+            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
+            divhelp = p.system.methodHelp('div')
+            self.assertEqual(divhelp, 'This is the div function')
+        except xmlrpclib.ProtocolError, e:
+            # protocol error; provide additional information in test output
+            self.fail("%s\n%s" % (e, e.headers))
 
     def test_introspection3(self):
         # the SimpleXMLRPCServer doesn't support signatures, but
         # at least check that we can try
-        p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
-        divsig = p.system.methodSignature('div')
-        self.assertEqual(divsig, 'signatures not supported')
+        try:
+            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
+            divsig = p.system.methodSignature('div')
+            self.assertEqual(divsig, 'signatures not supported')
+        except xmlrpclib.ProtocolError, e:
+            # protocol error; provide additional information in test output
+            self.fail("%s\n%s" % (e, e.headers))
 
     def test_multicall(self):
-        p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
-        multicall = xmlrpclib.MultiCall(p)
-        multicall.add(2,3)
-        multicall.pow(6,8)
-        multicall.div(127,42)
-        add_result, pow_result, div_result = multicall()
-        self.assertEqual(add_result, 2+3)
-        self.assertEqual(pow_result, 6**8)
-        self.assertEqual(div_result, 127//42)
+        try:
+            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
+            multicall = xmlrpclib.MultiCall(p)
+            multicall.add(2,3)
+            multicall.pow(6,8)
+            multicall.div(127,42)
+            add_result, pow_result, div_result = multicall()
+            self.assertEqual(add_result, 2+3)
+            self.assertEqual(pow_result, 6**8)
+            self.assertEqual(div_result, 127//42)
+        except xmlrpclib.ProtocolError, e:
+            # protocol error; provide additional information in test output
+            self.fail("%s\n%s" % (e, e.headers))
 
 
 # This is a contrived way to make a failure occur on the server side
@@ -375,9 +395,16 @@ class FailingServerTestCase(unittest.TestCase):
         flagval = SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header
         self.assertEqual(flagval, False)
 
-        # test a call that won't fail just as a smoke test
-        p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
-        self.assertEqual(p.pow(6,8), 6**8)
+        # enable traceback reporting
+        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
+
+        # test a call that shouldn't fail just as a smoke test
+        try:
+            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
+            self.assertEqual(p.pow(6,8), 6**8)
+        except xmlrpclib.ProtocolError, e:
+            # protocol error; provide additional information in test output
+            self.fail("%s\n%s" % (e, e.headers))
 
     def test_fail_no_info(self):
         # use the broken message class
index 77c6a775b7eb36ca6807717c00d49933ce313f99..8ae40368ec3050537258a0627e5aa5561ef1c399 100644 (file)
@@ -914,7 +914,20 @@ compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o)
        Py_ssize_t arg;
 
        /* necessary to make sure types aren't coerced (e.g., int and long) */
-       t = PyTuple_Pack(2, o, o->ob_type);
+        /* _and_ to distinguish 0.0 from -0.0 e.g. on IEEE platforms */
+        if (PyFloat_Check(o)) {
+            double d = PyFloat_AS_DOUBLE(o);
+            unsigned char* p = (unsigned char*) &d;
+            /* all we need is to make the tuple different in either the 0.0
+             * or -0.0 case from all others, just to avoid the "coercion".
+             */
+            if (*p==0 && p[sizeof(double)-1]==0)
+                t = PyTuple_Pack(3, o, o->ob_type, Py_None);
+            else
+               t = PyTuple_Pack(2, o, o->ob_type);
+        } else {
+           t = PyTuple_Pack(2, o, o->ob_type);
+        }
        if (t == NULL)
            return -1;
 
index 49a47bb314397f9a2f73a8cb08fcaab5a30de832..72138c2ea8bc6b8db29281fc2d7c12d4d95b80b5 100644 (file)
@@ -118,15 +118,19 @@ _PyImport_Init(void)
        /* prepare _PyImport_Filetab: copy entries from
           _PyImport_DynLoadFiletab and _PyImport_StandardFiletab.
         */
+#ifdef HAVE_DYNAMIC_LOADING
        for (scan = _PyImport_DynLoadFiletab; scan->suffix != NULL; ++scan)
                ++countD;
+#endif
        for (scan = _PyImport_StandardFiletab; scan->suffix != NULL; ++scan)
                ++countS;
        filetab = PyMem_NEW(struct filedescr, countD + countS + 1);
        if (filetab == NULL)
                Py_FatalError("Can't initialize import file table.");
+#ifdef HAVE_DYNAMIC_LOADING
        memcpy(filetab, _PyImport_DynLoadFiletab,
               countD * sizeof(struct filedescr));
+#endif
        memcpy(filetab + countD, _PyImport_StandardFiletab,
               countS * sizeof(struct filedescr));
        filetab[countD + countS].suffix = NULL;
@@ -1321,7 +1325,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf,
                saved_namelen = namelen;
 #endif /* PYOS_OS2 */
                for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) {
-#if defined(PYOS_OS2)
+#if defined(PYOS_OS2) && defined(HAVE_DYNAMIC_LOADING)
                        /* OS/2 limits DLLs to 8 character names (w/o
                           extension)
                         * so if the name is longer than that and its a
index 3d527fd8ab8375ef0795e72ac64892a0b5361f10..00245b57f4b2b6f106d5c3ef63cae1e615f89eb2 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -194,18 +194,21 @@ class PyBuildExt(build_ext):
             for e, f, g in zip(lst[::3], lst[1::3], lst[2::3]):
                 print("%-*s   %-*s   %-*s" % (longest, e, longest, f,
                                               longest, g))
-            print()
 
         if missing:
             print()
             print("Failed to find the necessary bits to build these modules:")
             print_three_column(missing)
+            print("To find the necessary bits, look in setup.py in"
+                  " detect_modules() for the module's name.")
+            print()
 
         if self.failed:
             failed = self.failed[:]
             print()
             print("Failed to build these modules:")
             print_three_column(failed)
+            print()
 
     def build_extension(self, ext):
 
@@ -299,7 +302,8 @@ class PyBuildExt(build_ext):
                 # strip out double-dashes first so that we don't end up with
                 # substituting "--Long" to "-Long" and thus lead to "ong" being
                 # used for a library directory.
-                env_val = re.sub(r'(^|\s+)-(-|(?!%s))' % arg_name[1], '', env_val)
+                env_val = re.sub(r'(^|\s+)-(-|(?!%s))' % arg_name[1],
+                                 ' ', env_val)
                 parser = optparse.OptionParser()
                 # Make sure that allowing args interspersed with options is
                 # allowed