Christian Heimes added the comment:

Guido van Rossum wrote:
> Shouldn't closefd be passed as 1 in import.c?
> 
> I don't see the point of distinguishing between -1 and +1.  The block
> "if (closefd < 0) { closefd = 1; }" looks rather silly.

I used -1 as default to keep it consistent with buffer=-1. I figured out
that I can go with "closefd != 0 means close it".

> In io.py, you should document that closefd must not be False when a
> filename is given.

Done

> I think in _fileio.c, you can insist that the closefd argument is an int
> (a bool will work anyway, as bool is a subclass of int).

Thanks, it makes the code a bit easier.

> I don't think we should warn when trying to close an unclosable fd; it
> should really just be a no-op.  Also, if you are going to call
> PyErr_WarnEx(), you should test its return value (it can raise an
> exception!).

I think we should keep the warning. The warning made me aware of a minor
bug in quopri.

> Please don't add trailing whitespace.

I've reconfigured my editor to remove trailing spaces.

I've attached a combined patch for closefd and preliminary stderr.

Christian

Added file: 
http://bugs.python.org/file8662/py3k_combined_preliminary_closefd.patch

__________________________________
Tracker <[EMAIL PROTECTED]>
<http://bugs.python.org/issue1329>
__________________________________
Index: Python/pythonrun.c
===================================================================
--- Python/pythonrun.c	(revision 58700)
+++ Python/pythonrun.c	(working copy)
@@ -151,7 +151,7 @@
 {
 	PyInterpreterState *interp;
 	PyThreadState *tstate;
-	PyObject *bimod, *sysmod;
+	PyObject *bimod, *sysmod, *pstderr;
 	char *p;
 #if defined(HAVE_LANGINFO_H) && defined(CODESET)
 	char *codeset;
@@ -228,6 +228,13 @@
 	PyDict_SetItemString(interp->sysdict, "modules",
 			     interp->modules);
 
+	/* Set up a dumb stderr printer until we have enough infrastructure
+           for the io module in place. */
+	pstderr = PyFile_NewStdPrinter(fileno(stderr));
+	if (pstderr == NULL)
+		Py_FatalError("Py_Initialize: can't set preliminary stderr");
+	PySys_SetObject("stderr", pstderr);
+
 	_PyImport_Init();
 
 	/* initialize builtin exceptions */
@@ -720,7 +727,7 @@
 
 	/* Set sys.stdin */
 	if (!(std = PyFile_FromFd(fileno(stdin), "<stdin>", "r", -1,
-				      NULL, "\n"))) {
+				  NULL, "\n", 0))) {
 		goto error;
 	}
 	PySys_SetObject("__stdin__", std);
@@ -729,16 +736,16 @@
 
 	/* Set sys.stdout */
 	if (!(std = PyFile_FromFd(fileno(stdout), "<stdout>", "w", -1,
-				      NULL, "\n"))) {
+				  NULL, "\n", 0))) {
             goto error;
         }
 	PySys_SetObject("__stdout__", std);
 	PySys_SetObject("stdout", std);
 	Py_DECREF(std);
 
-	/* Set sys.stderr */
+	/* Set sys.stderr, replaces the preliminary stderr */
 	if (!(std = PyFile_FromFd(fileno(stderr), "<stderr>", "w", -1,
-				      NULL, "\n"))) {
+				  NULL, "\n", 0))) {
             goto error;
         }
         PySys_SetObject("__stderr__", std);
Index: Python/import.c
===================================================================
--- Python/import.c	(revision 58700)
+++ Python/import.c	(working copy)
@@ -2588,7 +2588,7 @@
 				   (char*)PyUnicode_GetDefaultEncoding();
 		}
 		fob = PyFile_FromFd(fd, pathname, fdp->mode, -1,
-					(char*)encoding, NULL);
+				    (char*)encoding, NULL, 1);
 		if (fob == NULL) {
 			close(fd);
 			PyMem_FREE(found_encoding);
Index: Include/fileobject.h
===================================================================
--- Include/fileobject.h	(revision 58700)
+++ Include/fileobject.h	(working copy)
@@ -8,7 +8,8 @@
 
 #define PY_STDIOTEXTMODE "b"
 
-PyAPI_FUNC(PyObject *) PyFile_FromFd(int, char *, char *, int, char *, char *);
+PyAPI_FUNC(PyObject *) PyFile_FromFd(int, char *, char *, int, char *, char *,
+				     int);
 PyAPI_FUNC(PyObject *) PyFile_GetLine(PyObject *, int);
 PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int);
 PyAPI_FUNC(int) PyFile_WriteString(const char *, PyObject *);
@@ -20,6 +21,13 @@
 */
 PyAPI_DATA(const char *) Py_FileSystemDefaultEncoding;
 
+/* Internal API
+
+   The std printer acts as a preliminary sys.stderr until the new io
+   infrastructure is in place. */
+PyAPI_FUNC(PyObject *) PyFile_NewStdPrinter(int);
+PyAPI_DATA(PyTypeObject) PyStdPrinter_Type;
+
 #ifdef __cplusplus
 }
 #endif
Index: Objects/object.c
===================================================================
--- Objects/object.c	(revision 58700)
+++ Objects/object.c	(working copy)
@@ -1595,6 +1595,9 @@
 
 	if (PyType_Ready(&PyCode_Type) < 0)
 		Py_FatalError("Can't initialize 'code'");
+
+	if (PyType_Ready(&PyStdPrinter_Type) < 0)
+		Py_FatalError("Can't initialize StdPrinter");
 }
 
 
Index: Objects/fileobject.c
===================================================================
--- Objects/fileobject.c	(revision 58700)
+++ Objects/fileobject.c	(working copy)
@@ -27,15 +27,15 @@
 
 PyObject *
 PyFile_FromFd(int fd, char *name, char *mode, int buffering, char *encoding,
-	      char *newline)
+	      char *newline, int closefd)
 {
 	PyObject *io, *stream, *nameobj = NULL;
 
 	io = PyImport_ImportModule("io");
 	if (io == NULL)
 		return NULL;
-	stream = PyObject_CallMethod(io, "open", "isiss", fd, mode,
-				     buffering, encoding, newline);
+	stream = PyObject_CallMethod(io, "open", "isissi", fd, mode,
+				     buffering, encoding, newline, closefd);
 	Py_DECREF(io);
 	if (stream == NULL)
 		return NULL;
@@ -325,6 +325,124 @@
 	return buf;
 }
 
+/* **************************** std printer **************************** */
+
+typedef struct {
+	PyObject_HEAD
+	int fd : 1;
+} PyStdPrinter_Object;
+
+static PyObject *
+stdprinter_new(PyTypeObject *type, PyObject *args, PyObject *kews)
+{
+	PyStdPrinter_Object *self;
+
+	assert(type != NULL && type->tp_alloc != NULL);
+
+	self = (PyStdPrinter_Object *) type->tp_alloc(type, 0);
+	if (self != NULL) {
+		self->fd = -1;
+	}
+
+	return (PyObject *) self;
+}
+
+PyObject *
+PyFile_NewStdPrinter(int fd)
+{
+	PyStdPrinter_Object *self;
+
+	if (fd != 1 && fd != 2) {
+		PyErr_BadInternalCall();
+		return NULL;
+	}
+
+	self = PyObject_New(PyStdPrinter_Object,
+			    &PyStdPrinter_Type);
+	self->fd = fd;
+	return (PyObject*)self;
+}
+
+PyObject *
+stdprinter_write(PyStdPrinter_Object *self, PyObject *args)
+{
+	char *c;
+	Py_ssize_t n;
+
+	if (self->fd < 0) {
+		PyErr_SetString(PyExc_ValueError,
+				"I/O operation on closed file");
+		return NULL;
+	}
+
+	if (!PyArg_ParseTuple(args, "s#", &c, &n)) {
+		return NULL;
+	}
+
+	Py_BEGIN_ALLOW_THREADS
+	errno = 0;
+	n = write(self->fd, c, n);
+	Py_END_ALLOW_THREADS
+
+	if (n < 0) {
+		if (errno == EAGAIN)
+			Py_RETURN_NONE;
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	return PyInt_FromSsize_t(n);
+}
+
+static PyMethodDef stdprinter_methods[] = {
+	{"write", (PyCFunction)stdprinter_write, METH_VARARGS, ""},
+ 	{NULL,		NULL}		/* sentinel */
+};
+
+PyTypeObject PyStdPrinter_Type = {
+	PyVarObject_HEAD_INIT(&PyType_Type, 0)
+	"stderrprinter",			/* tp_name */
+	sizeof(PyStdPrinter_Object),		/* tp_basicsize */
+	0,					/* tp_itemsize */
+	/* methods */
+	0,					/* tp_dealloc */
+	0,					/* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	0,					/* tp_repr */
+	0,					/* tp_as_number */
+	0,					/* tp_as_sequence */
+	0,					/* tp_as_mapping */
+	0,					/* tp_hash */
+	0,					/* tp_call */
+	0,					/* tp_str */
+	PyObject_GenericGetAttr,		/* tp_getattro */
+	0,					/* tp_setattro */
+	0,					/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
+	0,					/* tp_doc */
+	0,					/* tp_traverse */
+	0,					/* tp_clear */
+	0,					/* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	0,					/* tp_iter */
+	0,					/* tp_iternext */
+	stdprinter_methods,			/* tp_methods */
+	0,					/* tp_members */
+	0,					/* tp_getset */
+	0,					/* tp_base */
+	0,					/* tp_dict */
+	0,					/* tp_descr_get */
+	0,					/* tp_descr_set */
+	0,					/* tp_dictoffset */
+	0,					/* tp_init */
+	PyType_GenericAlloc,			/* tp_alloc */
+	stdprinter_new,				/* tp_new */
+	PyObject_Del,				/* tp_free */
+};
+
+
 #ifdef __cplusplus
 }
 #endif
Index: Misc/NEWS
===================================================================
--- Misc/NEWS	(revision 58700)
+++ Misc/NEWS	(working copy)
@@ -28,6 +28,9 @@
   with `Py_FileSystemDefaultEncoding` and a new API method 
   `PyUnicode_DecodeFSDefault(char*)` was added.
 
+- io.open() and _fileio.FileIO have grown a new argument closefd. A false value
+  disables the closing of the file descriptor.
+
 Extension Modules
 -----------------
 
Index: Doc/c-api/concrete.rst
===================================================================
--- Doc/c-api/concrete.rst	(revision 58700)
+++ Doc/c-api/concrete.rst	(working copy)
@@ -2401,12 +2401,12 @@
    :ctype:`PyFileObject`.
 
 
-.. cfunction:: PyFile_FromFd(int fd, char *name, char *mode, int buffering, char *encoding, char *newline)
+.. cfunction:: PyFile_FromFd(int fd, char *name, char *mode, int buffering, char *encoding, char *newline, int closefd)
 
    Create a new :ctype:`PyFileObject` from the file descriptor of an already
    opened file *fd*. The arguments *name*, *encoding* and *newline* can be
-   *NULL* as well as buffering can be *-1* to use the defaults. Return *NULL* on
-   failure.
+   *NULL* as well as *buffering* can be *-1* to use the defaults. Return *NULL*
+   on failure.
 
    .. warning::
 
Index: Lib/quopri.py
===================================================================
--- Lib/quopri.py	(revision 58700)
+++ Lib/quopri.py	(working copy)
@@ -231,7 +231,7 @@
             decode(fp, sys.stdout.buffer)
         else:
             encode(fp, sys.stdout.buffer, tabs)
-        if fp is not sys.stdin:
+        if fp is not sys.stdin.buffer:
             fp.close()
     if sts:
         sys.exit(sts)
Index: Lib/io.py
===================================================================
--- Lib/io.py	(revision 58700)
+++ Lib/io.py	(working copy)
@@ -49,7 +49,8 @@
         self.characters_written = characters_written
 
 
-def open(file, mode="r", buffering=None, encoding=None, newline=None):
+def open(file, mode="r", buffering=None, encoding=None, newline=None,
+         closefd=True):
     r"""Replacement for the built-in open function.
 
     Args:
@@ -81,9 +82,13 @@
           other legal values, any `'\n'` characters written are
           translated to the given string.
 
+      closefd: optional argument to keep the underlying file descriptor open
+               when the file is closed. (*) It must not be false when a 
+               filename is given.
+
     (*) If a file descriptor is given, it is closed when the returned
-    I/O object is closed.  If you don't want this to happen, use
-    os.dup() to create a duplicate file descriptor.
+    I/O object is closed.  If you don't want this to happen, set closefd=False
+    or use os.dup() to create a duplicate file descriptor.
 
     Mode strings characters:
       'r': open for reading (default)
@@ -138,7 +143,8 @@
                  (reading and "r" or "") +
                  (writing and "w" or "") +
                  (appending and "a" or "") +
-                 (updating and "+" or ""))
+                 (updating and "+" or ""),
+                 closefd)
     if buffering is None:
         buffering = -1
     if buffering < 0 and raw.isatty():
Index: Lib/test/test_io.py
===================================================================
--- Lib/test/test_io.py	(revision 58700)
+++ Lib/test/test_io.py	(working copy)
@@ -259,6 +259,9 @@
         self.assertEqual(f.write(a), n)
         f.close()
 
+    def test_closefd(self):
+        self.assertRaises(ValueError, io.open, test_support.TESTFN, 'w',
+                          closefd=False)
 
 class MemorySeekTestMixin:
 
Index: Modules/_fileio.c
===================================================================
--- Modules/_fileio.c	(revision 58700)
+++ Modules/_fileio.c	(working copy)
@@ -33,6 +33,7 @@
 	unsigned readable : 1;
 	unsigned writable : 1;
 	int seekable : 2; /* -1 means unknown */
+	int closefd : 1;
 	PyObject *weakreflist;
 } PyFileIOObject;
 
@@ -59,6 +60,13 @@
 static PyObject *
 fileio_close(PyFileIOObject *self)
 {
+	if (self->closefd == 0) {
+		if (PyErr_WarnEx(PyExc_RuntimeWarning, 
+				 "Trying to close unclosable fd!", 3) < 0) {
+			return NULL;
+		}
+		Py_RETURN_NONE;
+	}
 	errno = internal_close(self);
 	if (errno < 0) {
 		PyErr_SetFromErrno(PyExc_IOError);
@@ -119,7 +127,7 @@
 fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
 {
 	PyFileIOObject *self = (PyFileIOObject *) oself;
-	static char *kwlist[] = {"file", "mode", NULL};
+	static char *kwlist[] = {"file", "mode", "closefd", NULL};
 	char *name = NULL;
 	char *mode = "r";
 	char *s;
@@ -130,6 +138,7 @@
 	int rwa = 0, plus = 0, append = 0;
 	int flags = 0;
 	int fd = -1;
+	int closefd = 1;
 
 	assert(PyFileIO_Check(oself));
 	if (self->fd >= 0) {
@@ -138,8 +147,8 @@
 			return -1;
 	}
 
-	if (PyArg_ParseTupleAndKeywords(args, kwds, "i|s:fileio",
-					kwlist, &fd, &mode)) {
+	if (PyArg_ParseTupleAndKeywords(args, kwds, "i|si:fileio",
+					kwlist, &fd, &mode, &closefd)) {
 		if (fd < 0) {
 			PyErr_SetString(PyExc_ValueError,
 					"Negative filedescriptor");
@@ -153,8 +162,9 @@
 	    if (GetVersion() < 0x80000000) {
 		/* On NT, so wide API available */
 		PyObject *po;
-		if (PyArg_ParseTupleAndKeywords(args, kwds, "U|s:fileio",
-						kwlist, &po, &mode)) {
+		if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:fileio",
+						kwlist, &po, &mode, &closefd)
+						) {
 			widename = PyUnicode_AS_UNICODE(po);
 		} else {
 			/* Drop the argument parsing error as narrow
@@ -165,10 +175,10 @@
 	    if (widename == NULL) 
 #endif
 	    {
-		if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|s:fileio",
+		if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:fileio",
 						 kwlist,
 						 Py_FileSystemDefaultEncoding,
-						 &name, &mode))
+						 &name, &mode, &closefd))
 			goto error;
 	    }
 	}
@@ -237,8 +247,16 @@
 
 	if (fd >= 0) {
 		self->fd = fd;
+		self->closefd = closefd;
 	}
 	else {
+		self->closefd = 1;
+		if (closefd == 0) {
+			PyErr_SetString(PyExc_ValueError,
+				"Cannot disable close fd with file name!");
+			goto error;
+		}
+
 		Py_BEGIN_ALLOW_THREADS
 		errno = 0;
 #ifdef MS_WINDOWS
@@ -270,7 +288,7 @@
 	if (self->weakreflist != NULL)
 		PyObject_ClearWeakRefs((PyObject *) self);
 
-	if (self->fd >= 0) {
+	if (self->fd >= 0 && self->closefd != 0) {
 		errno = internal_close(self);
 		if (errno < 0) {
 #ifdef HAVE_STRERROR

_______________________________________________
Python-bugs-list mailing list 
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to