Patch 1267 by Christian Heimes.

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.
This commit is contained in:
Guido van Rossum 2007-10-19 23:16:50 +00:00
parent 75a902db78
commit ce3a72aec6
11 changed files with 175 additions and 31 deletions

View File

@ -2425,6 +2425,12 @@ change in future releases of Python.
pointer, *fp*. The function *close* will be called when the file should be pointer, *fp*. The function *close* will be called when the file should be
closed. Return *NULL* on failure. 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) .. cfunction:: FILE* PyFile_AsFile(PyObject *p)

View File

@ -338,6 +338,15 @@ PyFile_FromFile:char*:name::
PyFile_FromFile:char*:mode:: PyFile_FromFile:char*:mode::
PyFile_FromFile:int(*:close):: 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:PyObject*::+1:
PyFile_FromString:char*:name:: PyFile_FromString:char*:name::
PyFile_FromString:char*:mode:: PyFile_FromString:char*:mode::

View File

@ -9,6 +9,9 @@ extern "C" {
#define PY_STDIOTEXTMODE "b" #define PY_STDIOTEXTMODE "b"
PyAPI_FUNC(PyObject *) PyFile_FromFile(FILE *, char *, char *, int (*)(FILE*)); 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(PyObject *) PyFile_GetLine(PyObject *, int);
PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int); PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int);
PyAPI_FUNC(int) PyFile_WriteString(const char *, PyObject *); PyAPI_FUNC(int) PyFile_WriteString(const char *, PyObject *);

View File

@ -178,6 +178,18 @@ def open(file, mode="r", buffering=None, encoding=None, newline=None):
return text 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): class UnsupportedOperation(ValueError, IOError):
pass pass

View File

@ -402,23 +402,6 @@ def execsitecustomize():
(err.__class__.__name__, err)) (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(): def main():
abs__file__() abs__file__()
paths_in_sys = removeduppaths() paths_in_sys = removeduppaths()
@ -433,7 +416,6 @@ def main():
sethelper() sethelper()
aliasmbcs() aliasmbcs()
setencoding() setencoding()
installnewio()
execsitecustomize() execsitecustomize()
# Remove sys.setdefaultencoding() so that users cannot change the # Remove sys.setdefaultencoding() so that users cannot change the
# encoding after initialization. The test for presence is needed when # encoding after initialization. The test for presence is needed when

View File

@ -38,9 +38,16 @@ class LockTests(unittest.TestCase):
self.fail("release_lock() without lock should raise " self.fail("release_lock() without lock should raise "
"RuntimeError") "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(): def test_main():
test_support.run_unittest( test_support.run_unittest(
LockTests, LockTests,
ImportTests,
) )
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -28,22 +28,32 @@ extern "C" {
PyObject * PyObject *
PyFile_FromFile(FILE *fp, char *name, char *mode, int (*close)(FILE *)) 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"); io = PyImport_ImportModule("io");
if (io == NULL) if (io == NULL)
return NULL; return NULL;
stream = PyObject_CallMethod(io, "open", "is", fileno(fp), mode); stream = PyObject_CallMethod(io, "open", "isiss", fileno(fp), mode,
Py_DECREF(io); buffering, encoding, newline);
Py_DECREF(io);
if (stream == NULL) if (stream == NULL)
return NULL; return NULL;
nameobj = PyUnicode_FromString(name); if (name != NULL) {
if (nameobj == NULL) nameobj = PyUnicode_FromString(name);
PyErr_Clear(); if (nameobj == NULL)
else {
if (PyObject_SetAttrString(stream, "name", nameobj) < 0)
PyErr_Clear(); PyErr_Clear();
Py_DECREF(nameobj); else {
if (PyObject_SetAttrString(stream, "name", nameobj) < 0)
PyErr_Clear();
Py_DECREF(nameobj);
}
} }
return stream; return stream;
} }

View File

@ -1601,7 +1601,28 @@ PyTokenizer_RestoreEncoding(struct tok_state* tok, int len, int *offset)
} }
#endif #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 #ifdef Py_DEBUG

View File

@ -67,6 +67,7 @@ extern void PyTokenizer_Free(struct tok_state *);
extern int PyTokenizer_Get(struct tok_state *, char **, char **); extern int PyTokenizer_Get(struct tok_state *, char **, char **);
extern char * PyTokenizer_RestoreEncoding(struct tok_state* tok, extern char * PyTokenizer_RestoreEncoding(struct tok_state* tok,
int len, int *offset); int len, int *offset);
extern char * PyTokenizer_FindEncoding(FILE *fp);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -91,6 +91,9 @@ static PyObject *extensions = NULL;
/* This table is defined in config.c: */ /* This table is defined in config.c: */
extern struct _inittab _PyImport_Inittab[]; extern struct _inittab _PyImport_Inittab[];
/* Method from Parser/tokenizer.c */
extern char * PyTokenizer_FindEncoding(FILE *fp);
struct _inittab *PyImport_Inittab = _PyImport_Inittab; struct _inittab *PyImport_Inittab = _PyImport_Inittab;
/* these tables define the module suffixes that Python recognizes */ /* these tables define the module suffixes that Python recognizes */
@ -2558,6 +2561,7 @@ call_find_module(char *name, PyObject *path)
struct filedescr *fdp; struct filedescr *fdp;
char pathname[MAXPATHLEN+1]; char pathname[MAXPATHLEN+1];
FILE *fp = NULL; FILE *fp = NULL;
char *encoding = NULL;
pathname[0] = '\0'; pathname[0] = '\0';
if (path == Py_None) if (path == Py_None)
@ -2566,7 +2570,14 @@ call_find_module(char *name, PyObject *path)
if (fdp == NULL) if (fdp == NULL)
return NULL; return NULL;
if (fp != 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) { if (fob == NULL) {
fclose(fp); fclose(fp);
return NULL; return NULL;

View File

@ -51,6 +51,7 @@ extern grammar _PyParser_Grammar; /* From graminit.c */
/* Forward */ /* Forward */
static void initmain(void); static void initmain(void);
static void initsite(void); static void initsite(void);
static int initstdio(void);
static PyObject *run_mod(mod_ty, const char *, PyObject *, PyObject *, static PyObject *run_mod(mod_ty, const char *, PyObject *, PyObject *,
PyCompilerFlags *, PyArena *); PyCompilerFlags *, PyArena *);
static PyObject *run_pyc_file(FILE *, const char *, PyObject *, PyObject *, 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() */ initsigs(); /* Signal handling stuff, including initintr() */
initmain(); /* Module __main__ */ initmain(); /* Module __main__ */
if (initstdio() < 0)
Py_FatalError(
"Py_Initialize: can't initialize sys standard streams");
if (!Py_NoSiteFlag) if (!Py_NoSiteFlag)
initsite(); /* Module site */ 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 */ /* Parse input from a file and execute it */
int int
@ -1146,10 +1225,10 @@ PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
int err = 0; int err = 0;
PyObject *f = PySys_GetObject("stderr"); PyObject *f = PySys_GetObject("stderr");
Py_INCREF(value); Py_INCREF(value);
if (f == NULL) if (f == NULL) {
_PyObject_Dump(value); _PyObject_Dump(value);
if (f == NULL)
fprintf(stderr, "lost sys.stderr\n"); fprintf(stderr, "lost sys.stderr\n");
}
else { else {
fflush(stdout); fflush(stdout);
if (tb && tb != Py_None) if (tb && tb != Py_None)
@ -1589,6 +1668,9 @@ void
Py_FatalError(const char *msg) Py_FatalError(const char *msg)
{ {
fprintf(stderr, "Fatal Python error: %s\n", msg); fprintf(stderr, "Fatal Python error: %s\n", msg);
if (PyErr_Occurred()) {
PyErr_Print();
}
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
OutputDebugString("Fatal Python error: "); OutputDebugString("Fatal Python error: ");
OutputDebugString(msg); OutputDebugString(msg);