Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3b06e53

Browse files
committed
Another patch for #1762972: __file__ points to the py file instead pyo/pyc file
1 parent a38f73b commit 3b06e53

3 files changed

Lines changed: 63 additions & 5 deletions

File tree

Lib/test/test_import.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from test.test_support import TESTFN, run_unittest, catch_warning
1+
from test.test_support import TESTFN, run_unittest, catch_warning
22

33
import unittest
44
import os
@@ -200,6 +200,27 @@ def test_failing_reload(self):
200200
if TESTFN in sys.modules:
201201
del sys.modules[TESTFN]
202202

203+
def test_file_to_source(self):
204+
# check if __file__ points to the source file where available
205+
source = TESTFN + ".py"
206+
with open(source, "w") as f:
207+
f.write("test = None\n")
208+
209+
sys.path.insert(0, os.curdir)
210+
try:
211+
mod = __import__(TESTFN)
212+
self.failUnless(mod.__file__.endswith('.py'))
213+
os.remove(source)
214+
del sys.modules[TESTFN]
215+
mod = __import__(TESTFN)
216+
self.failUnless(mod.__file__.endswith('.pyc'))
217+
finally:
218+
sys.path.pop(0)
219+
remove_files(TESTFN)
220+
if TESTFN in sys.modules:
221+
del sys.modules[TESTFN]
222+
223+
203224
class PathsTests(unittest.TestCase):
204225
SAMPLES = ('test', 'test\u00e4\u00f6\u00fc\u00df', 'test\u00e9\u00e8',
205226
'test\u00b0\u00b3\u00b2')

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ What's New in Python 3.0a3?
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #1762972: __file__ points to the source file instead of the pyc/pyo
16+
file if the py file exists.
17+
1518
- Issue #1393: object_richcompare() returns NotImplemented instead of
1619
False if the objects aren't equal, to give the other side a chance.
1720

Python/import.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,10 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
7878
3080 (PEP 3137 make __file__ and __name__ unicode)
7979
3090 (kill str8 interning)
8080
3100 (merge from 2.6a0, see 62151)
81+
3102 (__file__ points to source file)
8182
.
8283
*/
83-
#define MAGIC (3100 | ((long)'\r'<<16) | ((long)'\n'<<24))
84+
#define MAGIC (3102 | ((long)'\r'<<16) | ((long)'\n'<<24))
8485

8586
/* Magic word as global; note that _PyImport_Init() can change the
8687
value of this global to accommodate for alterations of how the
@@ -624,6 +625,8 @@ _RemoveModule(const char *name)
624625
"sys.modules failed");
625626
}
626627

628+
static PyObject * get_sourcefile(const char *file);
629+
627630
/* Execute a code object in a module and return the module object
628631
* WITH INCREMENTED REFERENCE COUNT. If an error occurs, name is
629632
* removed from sys.modules, to avoid leaving damaged module objects
@@ -657,7 +660,7 @@ PyImport_ExecCodeModuleEx(char *name, PyObject *co, char *pathname)
657660
/* Remember the filename as the __file__ attribute */
658661
v = NULL;
659662
if (pathname != NULL) {
660-
v = PyUnicode_DecodeFSDefault(pathname);
663+
v = get_sourcefile(pathname);
661664
if (v == NULL)
662665
PyErr_Clear();
663666
}
@@ -960,12 +963,43 @@ load_source_module(char *name, char *pathname, FILE *fp)
960963
return m;
961964
}
962965

966+
/* Get source file -> unicode or None
967+
* Returns the path to the py file if available, else the given path
968+
*/
969+
static PyObject *
970+
get_sourcefile(const char *file)
971+
{
972+
char py[MAXPATHLEN + 1];
973+
Py_ssize_t len;
974+
PyObject *u;
975+
struct stat statbuf;
976+
977+
if (!file || !*file) {
978+
Py_RETURN_NONE;
979+
}
980+
981+
len = strlen(file);
982+
if (len > MAXPATHLEN || PyOS_stricmp(&file[len-4], ".pyc") != 0) {
983+
return PyUnicode_DecodeFSDefault(file);
984+
}
985+
986+
strncpy(py, file, len-1);
987+
py[len] = '\0';
988+
if (stat(py, &statbuf) == 0 &&
989+
S_ISREG(statbuf.st_mode)) {
990+
u = PyUnicode_DecodeFSDefault(py);
991+
}
992+
else {
993+
u = PyUnicode_DecodeFSDefault(file);
994+
}
995+
return u;
996+
}
963997

964998
/* Forward */
965999
static PyObject *load_module(char *, FILE *, char *, int, PyObject *);
9661000
static struct filedescr *find_module(char *, char *, PyObject *,
9671001
char *, size_t, FILE **, PyObject **);
968-
static struct _frozen *find_frozen(char *name);
1002+
static struct _frozen * find_frozen(char *);
9691003

9701004
/* Load a package and return its module object WITH INCREMENTED
9711005
REFERENCE COUNT */
@@ -988,7 +1022,7 @@ load_package(char *name, char *pathname)
9881022
PySys_WriteStderr("import %s # directory %s\n",
9891023
name, pathname);
9901024
d = PyModule_GetDict(m);
991-
file = PyUnicode_DecodeFSDefault(pathname);
1025+
file = get_sourcefile(pathname);
9921026
if (file == NULL)
9931027
goto error;
9941028
path = Py_BuildValue("[O]", file);

0 commit comments

Comments
 (0)