]> granicus.if.org Git - python/commitdiff
Merged revisions 67245,67277,67289,67295,67301-67303,67307,67330,67332,67336,67355...
authorGeorg Brandl <georg@python.org>
Fri, 5 Dec 2008 08:51:30 +0000 (08:51 +0000)
committerGeorg Brandl <georg@python.org>
Fri, 5 Dec 2008 08:51:30 +0000 (08:51 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r67245 | benjamin.peterson | 2008-11-17 23:05:19 +0100 (Mon, 17 Nov 2008) | 1 line

  improve __hash__ docs
........
  r67277 | skip.montanaro | 2008-11-19 04:35:41 +0100 (Wed, 19 Nov 2008) | 1 line

  patch from issue 1108
........
  r67289 | brett.cannon | 2008-11-19 21:29:39 +0100 (Wed, 19 Nov 2008) | 2 lines

  Ignore .pyc and .pyo files.
........
  r67295 | benjamin.peterson | 2008-11-20 05:05:12 +0100 (Thu, 20 Nov 2008) | 1 line

  move useful sys.settrace information to the function's documentation from the debugger
........
  r67301 | benjamin.peterson | 2008-11-20 22:25:31 +0100 (Thu, 20 Nov 2008) | 1 line

  fix indentation and a sphinx warning
........
  r67302 | benjamin.peterson | 2008-11-20 22:44:23 +0100 (Thu, 20 Nov 2008) | 1 line

  oops! didn't mean to disable that test
........
  r67303 | benjamin.peterson | 2008-11-20 23:06:22 +0100 (Thu, 20 Nov 2008) | 1 line

  backport r67300
........
  r67307 | amaury.forgeotdarc | 2008-11-21 00:34:31 +0100 (Fri, 21 Nov 2008) | 9 lines

  Fixed issue #4233.
  Changed semantic of _fileio.FileIO's close()  method on file objects with closefd=False.
  The file descriptor is still kept open but the file object behaves like a closed file.
  The FileIO  object also got a new readonly attribute closefd.

  Approved by Barry

  Backport of r67106 from the py3k branch
........
  r67330 | georg.brandl | 2008-11-22 09:34:14 +0100 (Sat, 22 Nov 2008) | 2 lines

  #4364: fix attribute name on ctypes object.
........
  r67332 | georg.brandl | 2008-11-22 09:45:33 +0100 (Sat, 22 Nov 2008) | 2 lines

  Fix typo.
........
  r67336 | georg.brandl | 2008-11-22 11:08:50 +0100 (Sat, 22 Nov 2008) | 2 lines

  Fix error about "-*-" being mandatory in coding cookies.
........
  r67355 | georg.brandl | 2008-11-23 20:17:25 +0100 (Sun, 23 Nov 2008) | 2 lines

  #4392: fix parameter name.
........
  r67359 | georg.brandl | 2008-11-23 22:57:30 +0100 (Sun, 23 Nov 2008) | 2 lines

  #4399: fix typo.
........
  r67362 | gregory.p.smith | 2008-11-24 01:41:43 +0100 (Mon, 24 Nov 2008) | 2 lines

  Document PY_SSIZE_T_CLEAN for PyArg_ParseTuple.
........
  r67364 | benjamin.peterson | 2008-11-24 02:16:29 +0100 (Mon, 24 Nov 2008) | 2 lines

  replace reference to debugger-hooks
........
  r67367 | georg.brandl | 2008-11-24 17:16:07 +0100 (Mon, 24 Nov 2008) | 2 lines

  Fix typo.
........
  r67368 | georg.brandl | 2008-11-24 20:56:47 +0100 (Mon, 24 Nov 2008) | 2 lines

  #4404: make clear what "path" is.
........
  r67370 | jeremy.hylton | 2008-11-24 23:00:29 +0100 (Mon, 24 Nov 2008) | 8 lines

  Add unittests that verify documented behavior of public methods in Transport
  class.

  These methods can be overridden.  The tests verify that the overridden
  methods are called, and that changes to the connection have a visible
  effect on the request.
........

18 files changed:
Doc/howto/unicode.rst
Doc/library/bdb.rst
Doc/library/collections.rst
Doc/library/ctypes.rst
Doc/library/io.rst
Doc/library/multiprocessing.rst
Doc/library/os.rst
Doc/library/pdb.rst
Doc/library/sys.rst
Doc/reference/datamodel.rst
Lib/doctest.py
Lib/io.py
Lib/multiprocessing/pool.py
Lib/test/test_bytes.py
Lib/test/test_io.py
Lib/test/test_xmlrpc.py
Misc/NEWS
Modules/_fileio.c

index 21ae11108828f8b6402d1cd4af223fe9c83a1e87..561ce29f52ef002778563d3c1c3ae5746c5d6415 100644 (file)
@@ -410,9 +410,9 @@ either the first or second line of the source file::
     
 The syntax is inspired by Emacs's notation for specifying variables local to a
 file.  Emacs supports many different variables, but Python only supports
-'coding'.  The ``-*-`` symbols indicate that the comment is special; within
-them, you must supply the name ``coding`` and the name of your chosen encoding,
-separated by ``':'``.
+'coding'.  The ``-*-`` symbols indicate to Emacs that the comment is special;
+they have no significance to Python but are a convention.  Python looks for
+``coding: name`` or ``coding=name`` in the comment.
 
 If you don't include such a comment, the default encoding used will be ASCII.
 Versions of Python before 2.4 were Euro-centric and assumed Latin-1 as a default
index 82a1c21eaddb7405fa039da89a02d32110a69136..3041b7bc00f9931396f4827de215edb1e12f18b0 100644 (file)
@@ -107,8 +107,9 @@ The :mod:`bdb` module also defines two classes:
 
       The *arg* parameter depends on the previous event.
 
-      For more information on trace functions, see :ref:`debugger-hooks`.  For
-      more information on code and frame objects, refer to :ref:`types`.
+      See the documentation for :func:`sys.settrace` for more information on the
+      trace function.  For more information on code and frame objects, refer to
+      :ref:`types`.
 
    .. method:: dispatch_line(frame)
 
index 258b54fdc60951634b18cacdebbf52d40d3c5997..40ec9e8f10bcea8626b386e61fe0fcb6336ae4c0 100644 (file)
@@ -60,7 +60,7 @@ ABC                        Inherits               Abstract Methods        Mixin
                            :class:`Iterable`,     and ``__len__``         ``index``, and ``count``
                            :class:`Container`     
                                                   
-:class:`MutableSequnce`    :class:`Sequence`      ``__getitem__``         Inherited Sequence methods and
+:class:`MutableSequence`   :class:`Sequence`      ``__getitem__``         Inherited Sequence methods and
                                                   ``__delitem__``,        ``append``, ``reverse``, ``extend``, ``pop``,
                                                   ``insert``,             ``remove``, and ``__iadd__``
                                                   and ``__len__``
@@ -487,16 +487,16 @@ Named tuples assign meaning to each position in a tuple and allow for more reada
 self-documenting code.  They can be used wherever regular tuples are used, and
 they add the ability to access fields by name instead of position index.
 
-.. function:: namedtuple(typename, fieldnames, [verbose])
+.. function:: namedtuple(typename, field_names, [verbose])
 
    Returns a new tuple subclass named *typename*.  The new subclass is used to
    create tuple-like objects that have fields accessible by attribute lookup as
    well as being indexable and iterable.  Instances of the subclass also have a
-   helpful docstring (with typename and fieldnames) and a helpful :meth:`__repr__`
+   helpful docstring (with typename and field_names) and a helpful :meth:`__repr__`
    method which lists the tuple contents in a ``name=value`` format.
 
-   The *fieldnames* are a single string with each fieldname separated by whitespace
-   and/or commas, for example ``'x y'`` or ``'x, y'``.  Alternatively, *fieldnames*
+   The *field_names* are a single string with each fieldname separated by whitespace
+   and/or commas, for example ``'x y'`` or ``'x, y'``.  Alternatively, *field_names*
    can be a sequence of strings such as ``['x', 'y']``.
 
    Any valid Python identifier may be used for a fieldname except for names
index 8e920f8056d5a839f2d179084f3d5968da3f760c..0e3733295ff0c1846cd40cbd05f5dac0e78698d1 100644 (file)
@@ -1370,7 +1370,7 @@ function exported by these libraries, and reacquired afterwards.
 
 All these classes can be instantiated by calling them with at least one
 argument, the pathname of the shared library.  If you have an existing handle to
-an already loaded shard library, it can be passed as the ``handle`` named
+an already loaded shared library, it can be passed as the ``handle`` named
 parameter, otherwise the underlying platforms ``dlopen`` or :meth:`LoadLibrary`
 function is used to load the library into the process, and to get a handle to
 it.
index 18df0e0514f5a61928f81ad57060d3692ca4d4f6..25d5f16dbae8ce0b20bfac4501b371bf650a350d 100644 (file)
@@ -214,8 +214,10 @@ I/O Base Classes
 
    .. method:: close()
 
-      Flush and close this stream.  This method has no effect if the file is
-      already closed.
+      Flush and close this stream. This method has no effect if the file is
+      already closed. Once the file is closed, any operation on the file 
+      (e.g. reading or writing) will raise an :exc:`IOError`. The internal
+      file descriptor isn't closed if *closefd* was False.
 
    .. attribute:: closed
 
index 7a131837cf13a4660e372cc0eccb5b2bb05286fa..e1992cc68a93637aa2ba93c24067f394c5a58312 100644 (file)
@@ -919,7 +919,7 @@ inherited by child processes.
 
    Note that *lock* is a keyword only argument.
 
-   Note that an array of :data:`ctypes.c_char` has *value* and *rawvalue*
+   Note that an array of :data:`ctypes.c_char` has *value* and *raw*
    attributes which allow one to use it to store and retrieve strings.
 
 
@@ -968,7 +968,7 @@ processes.
    :func:`Value` instead to make sure that access is automatically synchronized
    using a lock.
 
-   Note that an array of :data:`ctypes.c_char` has ``value`` and ``rawvalue``
+   Note that an array of :data:`ctypes.c_char` has ``value`` and ``raw``
    attributes which allow one to use it to store and retrieve strings -- see
    documentation for :mod:`ctypes`.
 
index 14784fad663eb9073e9255b308644a5a8bfa39a4..1cb450b6abe88e4512b5688358cb0979a218de50 100644 (file)
@@ -933,10 +933,10 @@ Files and Directories
 
 .. function:: listdir(path)
 
-   Return a list containing the names of the entries in the directory. The list is
-   in arbitrary order.  It does not include the special entries ``'.'`` and
-   ``'..'`` even if they are present in the directory. Availability:
-   Unix, Windows.
+   Return a list containing the names of the entries in the directory given by
+   *path*.  The list is in arbitrary order.  It does not include the special
+   entries ``'.'`` and ``'..'`` even if they are present in the
+   directory.  Availability: Unix, Windows.
 
    .. versionchanged:: 2.3
       On Windows NT/2k/XP and Unix, if *path* is a Unicode object, the result will be
index c1a0bcd1c14f4a3bfa79d6de375f8120187f2c34..384c7d9f38bcf70e0309dd19791bc9d7862681fc 100644 (file)
@@ -351,68 +351,3 @@ run [*args* ...]
 
 q(uit)
    Quit from the debugger. The program being executed is aborted.
-
-
-.. _debugger-hooks:
-
-How It Works
-============
-
-Some changes were made to the interpreter:
-
-* ``sys.settrace(func)`` sets the global trace function
-
-* there can also a local trace function (see later)
-
-Trace functions have three arguments: *frame*, *event*, and *arg*. *frame* is
-the current stack frame.  *event* is a string: ``'call'``, ``'line'``,
-``'return'``, ``'exception'``, ``'c_call'``, ``'c_return'``, or
-``'c_exception'``. *arg* depends on the event type.
-
-The global trace function is invoked (with *event* set to ``'call'``) whenever a
-new local scope is entered; it should return a reference to the local trace
-function to be used that scope, or ``None`` if the scope shouldn't be traced.
-
-The local trace function should return a reference to itself (or to another
-function for further tracing in that scope), or ``None`` to turn off tracing in
-that scope.
-
-Instance methods are accepted (and very useful!) as trace functions.
-
-The events have the following meaning:
-
-``'call'``
-   A function is called (or some other code block entered).  The global trace
-   function is called; *arg* is ``None``; the return value specifies the local
-   trace function.
-
-``'line'``
-   The interpreter is about to execute a new line of code (sometimes multiple line
-   events on one line exist).  The local trace function is called; *arg* is
-   ``None``; the return value specifies the new local trace function.
-
-``'return'``
-   A function (or other code block) is about to return.  The local trace function
-   is called; *arg* is the value that will be returned.  The trace function's
-   return value is ignored.
-
-``'exception'``
-   An exception has occurred.  The local trace function is called; *arg* is a
-   triple ``(exception, value, traceback)``; the return value specifies the new
-   local trace function.
-
-``'c_call'``
-   A C function is about to be called.  This may be an extension function or a
-   builtin.  *arg* is the C function object.
-
-``'c_return'``
-   A C function has returned. *arg* is ``None``.
-
-``'c_exception'``
-   A C function has thrown an exception.  *arg* is ``None``.
-
-Note that as an exception is propagated down the chain of callers, an
-``'exception'`` event is generated at each level.
-
-For more information on code and frame objects, refer to :ref:`types`.
-
index 111755068c1b763dbbc087e74e2d5a964cf187ae..fa7b7f098b7ea93e4a73decbeb090b34c8306519 100644 (file)
@@ -712,11 +712,60 @@ always available.
       single: debugger
 
    Set the system's trace function, which allows you to implement a Python
-   source code debugger in Python.  See section :ref:`debugger-hooks` in the
-   chapter on the Python debugger.  The function is thread-specific; for a
+   source code debugger in Python.  The function is thread-specific; for a
    debugger to support multiple threads, it must be registered using
    :func:`settrace` for each thread being debugged.
 
+   Trace functions should have three arguments: *frame*, *event*, and
+   *arg*. *frame* is the current stack frame.  *event* is a string: ``'call'``,
+   ``'line'``, ``'return'``, ``'exception'``, ``'c_call'``, ``'c_return'``, or
+   ``'c_exception'``. *arg* depends on the event type.
+
+   The trace function is invoked (with *event* set to ``'call'``) whenever a new
+   local scope is entered; it should return a reference to a local trace
+   function to be used that scope, or ``None`` if the scope shouldn't be traced.
+
+   The local trace function should return a reference to itself (or to another
+   function for further tracing in that scope), or ``None`` to turn off tracing
+   in that scope.
+
+   The events have the following meaning:
+
+   ``'call'`` 
+      A function is called (or some other code block entered).  The
+      global trace function is called; *arg* is ``None``; the return value
+      specifies the local trace function.
+
+   ``'line'``
+      The interpreter is about to execute a new line of code (sometimes multiple
+      line events on one line exist).  The local trace function is called; *arg*
+      is ``None``; the return value specifies the new local trace function.
+
+   ``'return'``
+      A function (or other code block) is about to return.  The local trace
+      function is called; *arg* is the value that will be returned.  The trace
+      function's return value is ignored.
+
+   ``'exception'``
+      An exception has occurred.  The local trace function is called; *arg* is a
+      tuple ``(exception, value, traceback)``; the return value specifies the
+      new local trace function.
+
+   ``'c_call'``
+      A C function is about to be called.  This may be an extension function or
+      a builtin.  *arg* is the C function object.
+
+   ``'c_return'``
+      A C function has returned. *arg* is ``None``.
+
+   ``'c_exception'``
+      A C function has thrown an exception.  *arg* is ``None``.
+
+   Note that as an exception is propagated down the chain of callers, an
+   ``'exception'`` event is generated at each level.
+
+   For more information on code and frame objects, refer to :ref:`types`.
+
    .. note::
 
       The :func:`settrace` function is intended only for implementing debuggers,
index b1ab8fd97cc60cbd43ac8aac7c83668daa2e2ff8..7304c9c385ca7e2769807a0935c43ec3fac3d1e1 100644 (file)
@@ -1365,21 +1365,21 @@ Basic customization
       object: dictionary
       builtin: hash
 
-   Called for the key object for dictionary operations, and by the built-in
-   function :func:`hash`.  Should return an integer usable as a hash value
-   for dictionary operations.  The only required property is that objects which
-   compare equal have the same hash value; it is advised to somehow mix together
-   (e.g., using exclusive or) the hash values for the components of the object that
-   also play a part in comparison of objects.
+   Called by built-in function :func:`hash` and for operations on members of
+   hashed collections including :class:`set`, :class:`frozenset`, and
+   :class:`dict`.  :meth:`__hash__` should return an integer.  The only required
+   property is that objects which compare equal have the same hash value; it is
+   advised to somehow mix together (e.g. using exclusive or) the hash values for
+   the components of the object that also play a part in comparison of objects.
 
    If a class does not define a :meth:`__cmp__` or :meth:`__eq__` method it
    should not define a :meth:`__hash__` operation either; if it defines
    :meth:`__cmp__` or :meth:`__eq__` but not :meth:`__hash__`, its instances
-   will not be usable as dictionary keys.  If a class defines mutable objects
+   will not be usable in hashed collections.  If a class defines mutable objects
    and implements a :meth:`__cmp__` or :meth:`__eq__` method, it should not
-   implement :meth:`__hash__`, since the dictionary implementation requires that
-   a key's hash value is immutable (if the object's hash value changes, it will
-   be in the wrong hash bucket).
+   implement :meth:`__hash__`, since hashable collection implementations require
+   that a object's hash value is immutable (if the object's hash value changes,
+   it will be in the wrong hash bucket).
 
    User-defined classes have :meth:`__cmp__` and :meth:`__hash__` methods
    by default; with them, all objects compare unequal (except with themselves)
@@ -1389,13 +1389,13 @@ Basic customization
    change the meaning of :meth:`__cmp__` or :meth:`__eq__` such that the hash
    value returned is no longer appropriate (e.g. by switching to a value-based
    concept of equality instead of the default identity based equality) can
-   explicitly flag themselves as being unhashable by setting
-   ``__hash__ = None`` in the class definition. Doing so means that not only
-   will instances of the class raise an appropriate :exc:`TypeError` when
-   a program attempts to retrieve their hash value, but they will also be
-   correctly identified as unhashable when checking
-   ``isinstance(obj, collections.Hashable)`` (unlike classes which define
-   their own :meth:`__hash__` to explicitly raise :exc:`TypeError`).
+   explicitly flag themselves as being unhashable by setting ``__hash__ = None``
+   in the class definition. Doing so means that not only will instances of the
+   class raise an appropriate :exc:`TypeError` when a program attempts to
+   retrieve their hash value, but they will also be correctly identified as
+   unhashable when checking ``isinstance(obj, collections.Hashable)`` (unlike
+   classes which define their own :meth:`__hash__` to explicitly raise
+   :exc:`TypeError`).
 
    .. versionchanged:: 2.5
       :meth:`__hash__` may now also return a long integer object; the 32-bit
index 8806d6e7f84d89a1739e835d2429c6e847af380a..8a5a22c1ca89fc4db894b5223d643d87fe0e0c0c 100644 (file)
@@ -854,12 +854,12 @@ class DocTestFinder:
         """
         if module is None:
             return True
+        elif inspect.getmodule(object) is not None:
+            return module is inspect.getmodule(object)
         elif inspect.isfunction(object):
             return module.__dict__ is object.func_globals
         elif inspect.isclass(object):
             return module.__name__ == object.__module__
-        elif inspect.getmodule(object) is not None:
-            return module is inspect.getmodule(object)
         elif hasattr(object, '__module__'):
             return module.__name__ == object.__module__
         elif isinstance(object, property):
index 8462dd5e6a7357e003955de6c4389397aca57929..110804e607f7f1d64e6cec6e164baec7e1ed992c 100644 (file)
--- a/Lib/io.py
+++ b/Lib/io.py
@@ -238,8 +238,6 @@ def open(file, mode="r", buffering=None, encoding=None, errors=None,
         raise ValueError("invalid buffering size")
     if buffering == 0:
         if binary:
-            raw._name = file
-            raw._mode = mode
             return raw
         raise ValueError("can't have unbuffered text I/O")
     if updating:
@@ -251,11 +249,8 @@ def open(file, mode="r", buffering=None, encoding=None, errors=None,
     else:
         raise ValueError("unknown mode: %r" % mode)
     if binary:
-        buffer.name = file
-        buffer.mode = mode
         return buffer
     text = TextIOWrapper(buffer, encoding, errors, newline, line_buffering)
-    text.name = file
     text.mode = mode
     return text
 
@@ -622,6 +617,10 @@ class FileIO(_fileio._FileIO, RawIOBase):
     # that _fileio._FileIO inherits from io.RawIOBase (which would be hard
     # to do since _fileio.c is written in C).
 
+    def __init__(self, name, mode="r", closefd=True):
+        _fileio._FileIO.__init__(self, name, mode, closefd)
+        self._name = name
+
     def close(self):
         _fileio._FileIO.close(self)
         RawIOBase.close(self)
@@ -630,10 +629,6 @@ class FileIO(_fileio._FileIO, RawIOBase):
     def name(self):
         return self._name
 
-    @property
-    def mode(self):
-        return self._mode
-
 
 class BufferedIOBase(IOBase):
 
@@ -767,6 +762,14 @@ class _BufferedIOMixin(BufferedIOBase):
     def closed(self):
         return self.raw.closed
 
+    @property
+    def name(self):
+        return self.raw.name
+
+    @property
+    def mode(self):
+        return self.raw.mode
+
     ### Lower-level APIs ###
 
     def fileno(self):
@@ -1473,6 +1476,10 @@ class TextIOWrapper(TextIOBase):
     def closed(self):
         return self.buffer.closed
 
+    @property
+    def name(self):
+        return self.buffer.name
+
     def fileno(self):
         return self.buffer.fileno()
 
index cb9f02ab8d5a8380b17f2f5034c33e8061137015..9da27d48edfff5d35bb8acc9c00ebf36ee4c8fc1 100644 (file)
@@ -149,7 +149,7 @@ class Pool(object):
 
     def imap(self, func, iterable, chunksize=1):
         '''
-        Equivalent of `itertool.imap()` -- can be MUCH slower than `Pool.map()`
+        Equivalent of `itertools.imap()` -- can be MUCH slower than `Pool.map()`
         '''
         assert self._state == RUN
         if chunksize == 1:
index 6e5ffa9fa2075d0e469f0225b5b1a2fee6038df1..45df1f34b5ff6c616c0f6a372fd2a875649295e7 100644 (file)
@@ -725,7 +725,7 @@ class ByteArrayTest(BaseBytesTest):
         # Issue 4348.  Make sure that operations that don't mutate the array
         # copy the bytes.
         b = bytearray(b'abc')
-        #self.assertFalse(b is b.replace(b'abc', b'cde', 0))
+        self.assertFalse(b is b.replace(b'abc', b'cde', 0))
 
         t = bytearray([i for i in range(256)])
         x = bytearray(b'')
index 9ef2a818b3d4aa11fea24548287f66c4ddf70c30..c9bd38ddffbf44fcf85e5a5bbefaabbcfa7681d6 100644 (file)
@@ -272,6 +272,30 @@ class IOTest(unittest.TestCase):
         self.assertRaises(ValueError, io.open, test_support.TESTFN, 'w',
                           closefd=False)
 
+    def testReadClosed(self):
+        with io.open(test_support.TESTFN, "w") as f:
+            f.write("egg\n")
+        with io.open(test_support.TESTFN, "r") as f:
+            file = io.open(f.fileno(), "r", closefd=False)
+            self.assertEqual(file.read(), "egg\n")
+            file.seek(0)
+            file.close()
+            self.assertRaises(ValueError, file.read)
+
+    def test_no_closefd_with_filename(self):
+        # can't use closefd in combination with a file name
+        self.assertRaises(ValueError,
+                          io.open, test_support.TESTFN, "r", closefd=False)
+
+    def test_closefd_attr(self):
+        with io.open(test_support.TESTFN, "wb") as f:
+            f.write(b"egg\n")
+        with io.open(test_support.TESTFN, "r") as f:
+            self.assertEqual(f.buffer.raw.closefd, True)
+            file = io.open(f.fileno(), "r", closefd=False)
+            self.assertEqual(file.buffer.raw.closefd, False)
+
+
 class MemorySeekTestMixin:
 
     def testInit(self):
@@ -1225,6 +1249,9 @@ class TextIOWrapperTest(unittest.TestCase):
 
 class MiscIOTest(unittest.TestCase):
 
+    def tearDown(self):
+        test_support.unlink(test_support.TESTFN)
+
     def testImport__all__(self):
         for name in io.__all__:
             obj = getattr(io, name, None)
@@ -1237,6 +1264,34 @@ class MiscIOTest(unittest.TestCase):
                 self.assert_(issubclass(obj, io.IOBase))
 
 
+    def test_attributes(self):
+        f = io.open(test_support.TESTFN, "wb", buffering=0)
+        self.assertEquals(f.mode, "w")
+        f.close()
+
+        f = io.open(test_support.TESTFN, "U")
+        self.assertEquals(f.name,            test_support.TESTFN)
+        self.assertEquals(f.buffer.name,     test_support.TESTFN)
+        self.assertEquals(f.buffer.raw.name, test_support.TESTFN)
+        self.assertEquals(f.mode,            "U")
+        self.assertEquals(f.buffer.mode,     "r")
+        self.assertEquals(f.buffer.raw.mode, "r")
+        f.close()
+
+        f = io.open(test_support.TESTFN, "w+")
+        self.assertEquals(f.mode,            "w+")
+        self.assertEquals(f.buffer.mode,     "r+") # Does it really matter?
+        self.assertEquals(f.buffer.raw.mode, "r+")
+
+        g = io.open(f.fileno(), "wb", closefd=False)
+        self.assertEquals(g.mode,     "w")
+        self.assertEquals(g.raw.mode, "w")
+        self.assertEquals(g.name,     f.fileno())
+        self.assertEquals(g.raw.name, f.fileno())
+        f.close()
+        g.close()
+
+
 def test_main():
     test_support.run_unittest(IOTest, BytesIOTest, StringIOTest,
                               BufferedReaderTest, BufferedWriterTest,
index bbdb93eddd2ee66335cd01c7b447fa7e657cfcde..c9294b13605a8d8ae06f40faa4daf211236f1a62 100644 (file)
@@ -9,6 +9,7 @@ import threading
 import mimetools
 import httplib
 import socket
+import StringIO
 import os
 from test import test_support
 
@@ -639,9 +640,93 @@ class CGIHandlerTestCase(unittest.TestCase):
         os.remove("xmldata.txt")
         os.remove(test_support.TESTFN)
 
+class FakeSocket:
+
+    def __init__(self):
+        self.data = StringIO.StringIO()
+
+    def send(self, buf):
+        self.data.write(buf)
+        return len(buf)
+
+    def sendall(self, buf):
+        self.data.write(buf)
+
+    def getvalue(self):
+        return self.data.getvalue()
+
+    def makefile(self, x, y):
+        raise RuntimeError
+
+class FakeTransport(xmlrpclib.Transport):
+    """A Transport instance that records instead of sending a request.
+
+    This class replaces the actual socket used by httplib with a
+    FakeSocket object that records the request.  It doesn't provide a
+    response.
+    """
+
+    def make_connection(self, host):
+        conn = xmlrpclib.Transport.make_connection(self, host)
+        conn._conn.sock = self.fake_socket = FakeSocket()
+        return conn
+
+class TransportSubclassTestCase(unittest.TestCase):
+
+    def issue_request(self, transport_class):
+        """Return an HTTP request made via transport_class."""
+        transport = transport_class()
+        proxy = xmlrpclib.ServerProxy("http://example.com/",
+                                      transport=transport)
+        try:
+            proxy.pow(6, 8)
+        except RuntimeError:
+            return transport.fake_socket.getvalue()
+        return None
+
+    def test_custom_user_agent(self):
+        class TestTransport(FakeTransport):
+
+            def send_user_agent(self, conn):
+                xmlrpclib.Transport.send_user_agent(self, conn)
+                conn.putheader("X-Test", "test_custom_user_agent")
+
+        req = self.issue_request(TestTransport)
+        self.assert_("X-Test: test_custom_user_agent\r\n" in req)
+
+    def test_send_host(self):
+        class TestTransport(FakeTransport):
+
+            def send_host(self, conn, host):
+                xmlrpclib.Transport.send_host(self, conn, host)
+                conn.putheader("X-Test", "test_send_host")
+
+        req = self.issue_request(TestTransport)
+        self.assert_("X-Test: test_send_host\r\n" in req)
+
+    def test_send_request(self):
+        class TestTransport(FakeTransport):
+
+            def send_request(self, conn, url, body):
+                xmlrpclib.Transport.send_request(self, conn, url, body)
+                conn.putheader("X-Test", "test_send_request")
+
+        req = self.issue_request(TestTransport)
+        self.assert_("X-Test: test_send_request\r\n" in req)
+
+    def test_send_content(self):
+        class TestTransport(FakeTransport):
+
+            def send_content(self, conn, body):
+                conn.putheader("X-Test", "test_send_content")
+                xmlrpclib.Transport.send_content(self, conn, body)
+
+        req = self.issue_request(TestTransport)
+        self.assert_("X-Test: test_send_content\r\n" in req)
+
 def test_main():
     xmlrpc_tests = [XMLRPCTestCase, HelperTestCase, DateTimeTestCase,
-         BinaryTestCase, FaultTestCase]
+         BinaryTestCase, FaultTestCase, TransportSubclassTestCase]
 
     # The test cases against a SimpleXMLRPCServer raise a socket error
     # 10035 (WSAEWOULDBLOCK) in the server thread handle_request call when
index a2aacc1f0f00389ca5c301e52b122a9a215bb558..af50cf76c13919846c13b2e5a79e316ac8bf0f97 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,11 @@ What's New in Python 2.6.2
 Core and Builtins
 -----------------
 
+- Issue #4233: Changed semantic of ``_fileio.FileIO``'s ``close()`` 
+  method on file objects with closefd=False. The file descriptor is still
+  kept open but the file object behaves like a closed file. The ``FileIO``
+  object also got a new readonly attribute ``closefd``.
+
 Library
 -------
 
index 49bc29c73176f7c2a61d11db12378719c8b46834..b9310f380caf4635726d44d24a3bf1d819bdd10e 100644 (file)
@@ -61,10 +61,7 @@ static PyObject *
 fileio_close(PyFileIOObject *self)
 {
        if (!self->closefd) {
-               if (PyErr_WarnEx(PyExc_RuntimeWarning,
-                                "Trying to close unclosable fd!", 3) < 0) {
-                       return NULL;
-               }
+               self->fd = -1;
                Py_RETURN_NONE;
        }
        errno = internal_close(self);
@@ -820,6 +817,12 @@ get_closed(PyFileIOObject *self, void *closure)
        return PyBool_FromLong((long)(self->fd < 0));
 }
 
+static PyObject *
+get_closefd(PyFileIOObject *self, void *closure)
+{
+       return PyBool_FromLong((long)(self->closefd));
+}
+
 static PyObject *
 get_mode(PyFileIOObject *self, void *closure)
 {
@@ -828,6 +831,8 @@ get_mode(PyFileIOObject *self, void *closure)
 
 static PyGetSetDef fileio_getsetlist[] = {
        {"closed", (getter)get_closed, NULL, "True if the file is closed"},
+       {"closefd", (getter)get_closefd, NULL, 
+               "True if the file descriptor will be closed"},
        {"mode", (getter)get_mode, NULL, "String giving the file mode"},
        {0},
 };