]> granicus.if.org Git - python/commitdiff
Patch 1267 by Christian Heimes.
authorGuido van Rossum <guido@python.org>
Fri, 19 Oct 2007 23:16:50 +0000 (23:16 +0000)
committerGuido van Rossum <guido@python.org>
Fri, 19 Oct 2007 23:16:50 +0000 (23:16 +0000)
Move the initialization of sys.std{in,out,err} and __builtin__.open
to C code.
This solves the problem that "python -S" wouldn't work.

Doc/c-api/concrete.rst
Doc/data/refcounts.dat
Include/fileobject.h
Lib/io.py
Lib/site.py
Lib/test/test_imp.py
Objects/fileobject.c
Parser/tokenizer.c
Parser/tokenizer.h
Python/import.c
Python/pythonrun.c

index 6cd4be49ce7b1e82b0bb999c15db0e4664665d41..e48056c8e15ab241c9aeeaa803dca1fbafcaba4f 100644 (file)
@@ -2425,6 +2425,12 @@ change in future releases of Python.
    pointer, *fp*.  The function *close* will be called when the file should be
    closed.  Return *NULL* on failure.
 
+.. cfunction:: PyFile_FromFileEx(FILE *fp, char *name, char *mode, int (*close)(FILE *), int buffering, char *encoding, char *newline)
+
+   Create a new :ctype:`PyFileObject` from the already-open standard C file
+   pointer, *fp*. The functions works similar to *PyFile_FromFile* but takes
+   optional arguments for *buffering*, *encoding* and *newline*. Use -1 resp.
+   *NULL* for default values.
 
 .. cfunction:: FILE* PyFile_AsFile(PyObject *p)
 
index 4555301f11267820ab4a8a4ad24187a96a7cbcae..5c3fc990d605378c967b8bf24d5f84985165da84 100644 (file)
@@ -338,6 +338,15 @@ PyFile_FromFile:char*:name::
 PyFile_FromFile:char*:mode::
 PyFile_FromFile:int(*:close)::
 
+PyFile_FromFileEx:PyObject*::+1:
+PyFile_FromFileEx:FILE*:fp::
+PyFile_FromFileEx:char*:name::
+PyFile_FromFileEx:char*:mode::
+PyFile_FromFileEx:int(*:close)::
+PyFile_FromFileEx:int:buffering::
+PyFile_FromFileEx:char*:encoding::
+PyFile_FromFileEx:char*:newline::
+
 PyFile_FromString:PyObject*::+1:
 PyFile_FromString:char*:name::
 PyFile_FromString:char*:mode::
index 2d8c397989a25178620f5b935245f3bc85f5b0a3..b65d9847d45cb9e7dc9b83925b448c0cf16a19f7 100644 (file)
@@ -9,6 +9,9 @@ extern "C" {
 #define PY_STDIOTEXTMODE "b"
 
 PyAPI_FUNC(PyObject *) PyFile_FromFile(FILE *, char *, char *, int (*)(FILE*));
+PyAPI_FUNC(PyObject *) PyFile_FromFileEx(FILE *, char *, char *,
+                                        int (*)(FILE *), int, char *,
+                                        char *);
 PyAPI_FUNC(PyObject *) PyFile_GetLine(PyObject *, int);
 PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int);
 PyAPI_FUNC(int) PyFile_WriteString(const char *, PyObject *);
index e7533b5cfcd919b51005c61d1efebdfe3ee9eb01..07846bfb83fdf2d1717ff742227c89648492252d 100644 (file)
--- a/Lib/io.py
+++ b/Lib/io.py
@@ -178,6 +178,18 @@ def open(file, mode="r", buffering=None, encoding=None, newline=None):
     return text
 
 
+class OpenWrapper:
+    """Wrapper for __builtin__.open
+
+    Trick so that open won't become a bound method when stored
+    as a class variable (as dumbdbm does).
+
+    See initstdio() in Python/pythonrun.c.
+    """
+    def __new__(cls, *args, **kwargs):
+        return open(*args, **kwargs)
+
+
 class UnsupportedOperation(ValueError, IOError):
     pass
 
index 53e859ea85707104631584cd2fc51dcf58d8ed68..f1db89c9f0b2deefa095a11e85ac959927dcf427 100644 (file)
@@ -402,23 +402,6 @@ def execsitecustomize():
             (err.__class__.__name__, err))
 
 
-def installnewio():
-    """Install new I/O library as default."""
-    import io
-    # Hack to avoid a nasty recursion issue when Python is invoked
-    # in verbose mode: pre-import the Latin-1 and UTF-8 codecs
-    from encodings import latin_1, utf_8
-    # Trick so that open won't become a bound method when stored
-    # as a class variable (as dumbdbm does)
-    class open:
-        def __new__(cls, *args, **kwds):
-            return io.open(*args, **kwds)
-    __builtin__.open = open
-    sys.__stdin__ = sys.stdin = io.open(0, "r", newline='\n')
-    sys.__stdout__ = sys.stdout = io.open(1, "w", newline='\n')
-    sys.__stderr__ = sys.stderr = io.open(2, "w", newline='\n')
-
-
 def main():
     abs__file__()
     paths_in_sys = removeduppaths()
@@ -433,7 +416,6 @@ def main():
     sethelper()
     aliasmbcs()
     setencoding()
-    installnewio()
     execsitecustomize()
     # Remove sys.setdefaultencoding() so that users cannot change the
     # encoding after initialization.  The test for presence is needed when
index 62b14e071bd0da41585376c2293c66f92e3792c1..87efc33415edcc7acf28d2f5e59e468c7cca3747 100644 (file)
@@ -38,9 +38,16 @@ class LockTests(unittest.TestCase):
                 self.fail("release_lock() without lock should raise "
                             "RuntimeError")
 
+class ImportTests(unittest.TestCase):
+
+    def test_find_module_encoding(self):
+        fd = imp.find_module("heapq")[0]
+        self.assertEqual(fd.encoding, "iso-8859-1")
+
 def test_main():
     test_support.run_unittest(
                 LockTests,
+                ImportTests,
             )
 
 if __name__ == "__main__":
index 02675f5f3efd0f59aa9efed8475d434f021ab8f2..b6d200d0c21068e6110c23250c3e1cc29191c4eb 100644 (file)
@@ -28,22 +28,32 @@ extern "C" {
 PyObject *
 PyFile_FromFile(FILE *fp, char *name, char *mode, int (*close)(FILE *))
 {
-       PyObject *io, *stream, *nameobj;
+       return PyFile_FromFileEx(fp, name, mode, close, -1, NULL, NULL);
+}
+
+PyObject *
+PyFile_FromFileEx(FILE *fp, char *name, char *mode, int (*close)(FILE *),
+              int buffering, char *encoding, char *newline)
+{
+       PyObject *io, *stream, *nameobj=NULL;
 
        io = PyImport_ImportModule("io");
        if (io == NULL)
                return NULL;
-       stream = PyObject_CallMethod(io, "open", "is", fileno(fp), mode);
-        Py_DECREF(io);
+       stream = PyObject_CallMethod(io, "open", "isiss", fileno(fp), mode,
+                                   buffering, encoding, newline);
+       Py_DECREF(io);
        if (stream == NULL)
                return NULL;
-        nameobj = PyUnicode_FromString(name);
-        if (nameobj == NULL)
-               PyErr_Clear();
-       else {
-               if (PyObject_SetAttrString(stream, "name", nameobj) < 0)
+       if (name != NULL) {
+               nameobj = PyUnicode_FromString(name);
+               if (nameobj == NULL)
                        PyErr_Clear();
-               Py_DECREF(nameobj);
+               else {
+                       if (PyObject_SetAttrString(stream, "name", nameobj) < 0)
+                               PyErr_Clear();
+                       Py_DECREF(nameobj);
+               }
        }
        return stream;
 }
index 8f67e0e62ab06086d9b524d56a141aefa04d542d..0ccd02b58d12c4ac637e5eecfdb0864ddda8816e 100644 (file)
@@ -1601,7 +1601,28 @@ PyTokenizer_RestoreEncoding(struct tok_state* tok, int len, int *offset)
 }
 #endif
 
-                          
+/* Get -*- encoding -*- from a Python file
+
+   PyTokenizer_FindEncoding returns NULL when it can't find the encoding in
+   the first or second line of the file. In this case the encoding is
+   PyUnicode_GetDefaultEncoding().
+*/
+char *
+PyTokenizer_FindEncoding(FILE *fp) {
+       struct tok_state *tok;
+       char *p_start=NULL, *p_end=NULL;
+
+       if ((tok = PyTokenizer_FromFile(fp, NULL, NULL, NULL)) == NULL) {
+               rewind(fp);
+               return NULL;
+       }
+       while(((tok->lineno <= 2) && (tok->done == E_OK))) {
+               PyTokenizer_Get(tok, &p_start, &p_end);
+       }
+
+       rewind(fp);
+       return tok->encoding;
+}
 
 #ifdef Py_DEBUG
 
index 72982bde47e43b4d58707b1d8f9be31ed0e8f370..a66d78e7d97b44a2f1918fefed174bc34e414be3 100644 (file)
@@ -67,6 +67,7 @@ extern void PyTokenizer_Free(struct tok_state *);
 extern int PyTokenizer_Get(struct tok_state *, char **, char **);
 extern char * PyTokenizer_RestoreEncoding(struct tok_state* tok, 
                                          int len, int *offset);
+extern char * PyTokenizer_FindEncoding(FILE *fp);
 
 #ifdef __cplusplus
 }
index 21dcbd45d7ab629fb180b3e7efee90d0f00dbafc..323b55a540e1e1ebf05915f2aedc08365d705b71 100644 (file)
@@ -91,6 +91,9 @@ static PyObject *extensions = NULL;
 /* This table is defined in config.c: */
 extern struct _inittab _PyImport_Inittab[];
 
+/* Method from Parser/tokenizer.c */
+extern char * PyTokenizer_FindEncoding(FILE *fp);
+
 struct _inittab *PyImport_Inittab = _PyImport_Inittab;
 
 /* these tables define the module suffixes that Python recognizes */
@@ -2558,6 +2561,7 @@ call_find_module(char *name, PyObject *path)
        struct filedescr *fdp;
        char pathname[MAXPATHLEN+1];
        FILE *fp = NULL;
+       char *encoding = NULL;
 
        pathname[0] = '\0';
        if (path == Py_None)
@@ -2566,7 +2570,14 @@ call_find_module(char *name, PyObject *path)
        if (fdp == NULL)
                return NULL;
        if (fp != NULL) {
-               fob = PyFile_FromFile(fp, pathname, fdp->mode, fclose);
+               if (strchr(fdp->mode, 'b') == NULL) {
+                       /* Python text file, get encoding from tokenizer */
+                       encoding = PyTokenizer_FindEncoding(fp);
+                       encoding = (encoding != NULL) ? encoding :
+                                  (char*)PyUnicode_GetDefaultEncoding();
+               }
+               fob = PyFile_FromFileEx(fp, pathname, fdp->mode, fclose, -1,
+                                       (char*)encoding, NULL);
                if (fob == NULL) {
                        fclose(fp);
                        return NULL;
index 4e239c94acc818a48eaf47889f85f7bdcb999454..f641547afd5b8c337e85a0735fcc04e2fd5ef39e 100644 (file)
@@ -51,6 +51,7 @@ extern grammar _PyParser_Grammar; /* From graminit.c */
 /* Forward */
 static void initmain(void);
 static void initsite(void);
+static int initstdio(void);
 static PyObject *run_mod(mod_ty, const char *, PyObject *, PyObject *,
                          PyCompilerFlags *, PyArena *);
 static PyObject *run_pyc_file(FILE *, const char *, PyObject *, PyObject *,
@@ -241,6 +242,9 @@ Py_InitializeEx(int install_sigs)
                initsigs(); /* Signal handling stuff, including initintr() */
 
        initmain(); /* Module __main__ */
+       if (initstdio() < 0)
+               Py_FatalError(
+                   "Py_Initialize: can't initialize sys standard streams");
        if (!Py_NoSiteFlag)
                initsite(); /* Module site */
 
@@ -676,6 +680,81 @@ initsite(void)
        }
 }
 
+/* Initialize sys.stdin, stdout, stderr and __builtin__.open */
+static int
+initstdio(void)
+{
+       PyObject *iomod = NULL, *wrapper;
+       PyObject *bimod = NULL;
+       PyObject *m;
+       PyObject *std = NULL;
+       int status = 0;
+
+       /* Hack to avoid a nasty recursion issue when Python is invoked
+          in verbose mode: pre-import the Latin-1 and UTF-8 codecs */
+       if ((m = PyImport_ImportModule("encodings.utf_8")) == NULL) {
+               goto error;
+       }
+       Py_DECREF(m);
+
+       if (!(m = PyImport_ImportModule("encodings.latin_1"))) {
+               goto error;
+       }
+       Py_DECREF(m);
+
+       if (!(bimod = PyImport_ImportModule("__builtin__"))) {
+               goto error;
+       }
+
+       if (!(iomod = PyImport_ImportModule("io"))) {
+               goto error;
+       }
+       if (!(wrapper = PyObject_GetAttrString(iomod, "OpenWrapper"))) {
+               goto error;
+       }
+
+       /* Set __builtin__.open */
+       if (PyObject_SetAttrString(bimod, "open", wrapper) == -1) {
+               goto error;
+       }
+
+       /* Set sys.stdin */
+       if (!(std = PyFile_FromFileEx(stdin, "<stdin>", "r", fclose, -1,
+                                     NULL, "\n"))) {
+               goto error;
+       }
+       PySys_SetObject("__stdin__", std);
+       PySys_SetObject("stdin", std);
+       Py_DECREF(std);
+
+       /* Set sys.stdout */
+       if (!(std = PyFile_FromFileEx(stdout, "<stdout>", "w", fclose, -1,
+                                     NULL, "\n"))) {
+            goto error;
+        }
+       PySys_SetObject("__stdout__", std);
+       PySys_SetObject("stdout", std);
+       Py_DECREF(std);
+
+       /* Set sys.stderr */
+       if (!(std = PyFile_FromFileEx(stderr, "<stderr>", "w", fclose, -1,
+                                     NULL, "\n"))) {
+            goto error;
+        }
+        PySys_SetObject("__stderr__", std);
+       PySys_SetObject("stderr", std);
+       Py_DECREF(std);
+
+        if (0) {
+  error:
+                status = -1;
+        }
+
+       Py_XDECREF(bimod);
+       Py_XDECREF(iomod);
+       return status;
+}
+
 /* Parse input from a file and execute it */
 
 int
@@ -1146,10 +1225,10 @@ PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
        int err = 0;
        PyObject *f = PySys_GetObject("stderr");
        Py_INCREF(value);
-       if (f == NULL)
+       if (f == NULL) {
                _PyObject_Dump(value);
-       if (f == NULL)
                fprintf(stderr, "lost sys.stderr\n");
+       }
        else {
                fflush(stdout);
                if (tb && tb != Py_None)
@@ -1589,6 +1668,9 @@ void
 Py_FatalError(const char *msg)
 {
        fprintf(stderr, "Fatal Python error: %s\n", msg);
+       if (PyErr_Occurred()) {
+               PyErr_Print();
+       }
 #ifdef MS_WINDOWS
        OutputDebugString("Fatal Python error: ");
        OutputDebugString(msg);