From 3b06e5378ae21572a024b6484176b9678100ee53 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 7 Jan 2008 20:12:44 +0000 Subject: [PATCH] Another patch for #1762972: __file__ points to the py file instead pyo/pyc file --- Lib/test/test_import.py | 23 +++++++++++++++++++++- Misc/NEWS | 3 +++ Python/import.c | 42 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py index 6c9e0b00a1e..760713e69cf 100644 --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -1,4 +1,4 @@ -from test.test_support import TESTFN, run_unittest, catch_warning +from test.test_support import TESTFN, run_unittest, catch_warning import unittest import os @@ -200,6 +200,27 @@ class ImportTest(unittest.TestCase): if TESTFN in sys.modules: del sys.modules[TESTFN] + def test_file_to_source(self): + # check if __file__ points to the source file where available + source = TESTFN + ".py" + with open(source, "w") as f: + f.write("test = None\n") + + sys.path.insert(0, os.curdir) + try: + mod = __import__(TESTFN) + self.failUnless(mod.__file__.endswith('.py')) + os.remove(source) + del sys.modules[TESTFN] + mod = __import__(TESTFN) + self.failUnless(mod.__file__.endswith('.pyc')) + finally: + sys.path.pop(0) + remove_files(TESTFN) + if TESTFN in sys.modules: + del sys.modules[TESTFN] + + class PathsTests(unittest.TestCase): SAMPLES = ('test', 'test\u00e4\u00f6\u00fc\u00df', 'test\u00e9\u00e8', 'test\u00b0\u00b3\u00b2') diff --git a/Misc/NEWS b/Misc/NEWS index 0bd12482ad2..8a770609bac 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ What's New in Python 3.0a3? Core and Builtins ----------------- +- Issue #1762972: __file__ points to the source file instead of the pyc/pyo + file if the py file exists. + - Issue #1393: object_richcompare() returns NotImplemented instead of False if the objects aren't equal, to give the other side a chance. diff --git a/Python/import.c b/Python/import.c index 07bcbbf398b..f3421435632 100644 --- a/Python/import.c +++ b/Python/import.c @@ -78,9 +78,10 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *); 3080 (PEP 3137 make __file__ and __name__ unicode) 3090 (kill str8 interning) 3100 (merge from 2.6a0, see 62151) + 3102 (__file__ points to source file) . */ -#define MAGIC (3100 | ((long)'\r'<<16) | ((long)'\n'<<24)) +#define MAGIC (3102 | ((long)'\r'<<16) | ((long)'\n'<<24)) /* Magic word as global; note that _PyImport_Init() can change the value of this global to accommodate for alterations of how the @@ -624,6 +625,8 @@ _RemoveModule(const char *name) "sys.modules failed"); } +static PyObject * get_sourcefile(const char *file); + /* Execute a code object in a module and return the module object * WITH INCREMENTED REFERENCE COUNT. If an error occurs, name is * removed from sys.modules, to avoid leaving damaged module objects @@ -657,7 +660,7 @@ PyImport_ExecCodeModuleEx(char *name, PyObject *co, char *pathname) /* Remember the filename as the __file__ attribute */ v = NULL; if (pathname != NULL) { - v = PyUnicode_DecodeFSDefault(pathname); + v = get_sourcefile(pathname); if (v == NULL) PyErr_Clear(); } @@ -960,12 +963,43 @@ load_source_module(char *name, char *pathname, FILE *fp) return m; } +/* Get source file -> unicode or None + * Returns the path to the py file if available, else the given path + */ +static PyObject * +get_sourcefile(const char *file) +{ + char py[MAXPATHLEN + 1]; + Py_ssize_t len; + PyObject *u; + struct stat statbuf; + + if (!file || !*file) { + Py_RETURN_NONE; + } + + len = strlen(file); + if (len > MAXPATHLEN || PyOS_stricmp(&file[len-4], ".pyc") != 0) { + return PyUnicode_DecodeFSDefault(file); + } + + strncpy(py, file, len-1); + py[len] = '\0'; + if (stat(py, &statbuf) == 0 && + S_ISREG(statbuf.st_mode)) { + u = PyUnicode_DecodeFSDefault(py); + } + else { + u = PyUnicode_DecodeFSDefault(file); + } + return u; +} /* Forward */ static PyObject *load_module(char *, FILE *, char *, int, PyObject *); static struct filedescr *find_module(char *, char *, PyObject *, char *, size_t, FILE **, PyObject **); -static struct _frozen *find_frozen(char *name); +static struct _frozen * find_frozen(char *); /* Load a package and return its module object WITH INCREMENTED REFERENCE COUNT */ @@ -988,7 +1022,7 @@ load_package(char *name, char *pathname) PySys_WriteStderr("import %s # directory %s\n", name, pathname); d = PyModule_GetDict(m); - file = PyUnicode_DecodeFSDefault(pathname); + file = get_sourcefile(pathname); if (file == NULL) goto error; path = Py_BuildValue("[O]", file);