# HG changeset patch # User Stefan Behnel # Date 1321691224 -3600 # Node ID b24c35531360864b329b64c548a7e524dc2d7075 # Parent fa2f8dd077e0d3c67f6897e68b89830230bcf3f9 implemented ticket #13429: let the shared library loader provide __file__ to the init function of extension modules by setting it at module creation time diff -r fa2f8dd077e0 -r b24c35531360 Include/modsupport.h --- a/Include/modsupport.h Fri Nov 18 20:14:34 2011 +0100 +++ b/Include/modsupport.h Sat Nov 19 09:27:04 2011 +0100 @@ -120,6 +120,7 @@ #ifndef Py_LIMITED_API PyAPI_DATA(char *) _Py_PackageContext; +PyAPI_DATA(PyObject *) _Py_ModuleImportContext; #endif #ifdef __cplusplus diff -r fa2f8dd077e0 -r b24c35531360 Lib/test/test_capi.py --- a/Lib/test/test_capi.py Fri Nov 18 20:14:34 2011 +0100 +++ b/Lib/test/test_capi.py Sat Nov 19 09:27:04 2011 +0100 @@ -142,6 +142,11 @@ def test(self): self.assertEqual(_testcapi.argparsing("Hello", "World"), 1) +# __file__ support at module init time (issue #13429) +class TestModuleInitFilePath(unittest.TestCase): + def test(self): + self.assertEqual(_testcapi.module_init_file_path, _testcapi.__file__) + class EmbeddingTest(unittest.TestCase): @@ -176,7 +181,8 @@ def test_main(): - support.run_unittest(CAPITest, TestPendingCalls, Test6012, EmbeddingTest) + support.run_unittest(CAPITest, TestPendingCalls, Test6012, + TestModuleInitFilePath, EmbeddingTest) for name in dir(_testcapi): if name.startswith('test_'): diff -r fa2f8dd077e0 -r b24c35531360 Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c Fri Nov 18 20:14:34 2011 +0100 +++ b/Modules/_testcapimodule.c Sat Nov 19 09:27:04 2011 +0100 @@ -2579,11 +2579,20 @@ PyInit__testcapi(void) { PyObject *m; + PyObject *filepath; m = PyModule_Create(&_testcapimodule); if (m == NULL) return NULL; + filepath = PyModule_GetFilenameObject(m); + if (filepath == NULL) { + PyErr_Clear(); /* will be noticed by the test */ + } else { + PyModule_AddObject(m, "module_init_file_path", filepath); + filepath = NULL; + } + Py_TYPE(&_HashInheritanceTester_Type)=&PyType_Type; Py_TYPE(&_MemoryViewTester_Type)=&PyType_Type; diff -r fa2f8dd077e0 -r b24c35531360 Objects/moduleobject.c --- a/Objects/moduleobject.c Fri Nov 18 20:14:34 2011 +0100 +++ b/Objects/moduleobject.c Sat Nov 19 09:27:04 2011 +0100 @@ -124,6 +124,19 @@ } d = PyModule_GetDict((PyObject*)m); + + /* The dynamic library loader stores the file path to the imported + shared library in _Py_ModuleImportContext so that we can + properly set __file__ before running the module init function. + If it's set, assume it's valid - it's the best value we can get. + It will eventually be overwritten by the loader itself. + */ + if (_Py_ModuleImportContext != NULL) { + if (PyDict_SetItemString(d, "__file__", _Py_ModuleImportContext) < 0) { + PyErr_Clear(); /* Not important enough to report */ + } + } + if (module->m_methods != NULL) { n = PyUnicode_FromString(name); if (n == NULL) diff -r fa2f8dd077e0 -r b24c35531360 Python/importdl.c --- a/Python/importdl.c Fri Nov 18 20:14:34 2011 +0100 +++ b/Python/importdl.c Sat Nov 19 09:27:04 2011 +0100 @@ -27,7 +27,7 @@ #ifndef MS_WINDOWS PyObject *pathbytes; #endif - PyObject *nameascii; + PyObject *nameascii, *oldimportcontext; char *namestr, *lastdot, *shortname, *packagecontext, *oldcontext; dl_funcptr p0; PyObject* (*p)(void); @@ -82,8 +82,11 @@ } oldcontext = _Py_PackageContext; _Py_PackageContext = packagecontext; + oldimportcontext = _Py_ModuleImportContext; + _Py_ModuleImportContext = path; m = (*p)(); _Py_PackageContext = oldcontext; + _Py_ModuleImportContext = oldimportcontext; if (m == NULL) goto error; @@ -98,7 +101,7 @@ def = PyModule_GetDef(m); def->m_base.m_init = p; - /* Remember the filename as the __file__ attribute */ + /* Remember the filename as the __file__ attribute (in case it wasn't set yet) */ if (PyModule_AddObject(m, "__file__", path) < 0) PyErr_Clear(); /* Not important enough to report */ else diff -r fa2f8dd077e0 -r b24c35531360 Python/modsupport.c --- a/Python/modsupport.c Fri Nov 18 20:14:34 2011 +0100 +++ b/Python/modsupport.c Sat Nov 19 09:27:04 2011 +0100 @@ -11,6 +11,9 @@ /* Package context -- the full module name for package imports */ char *_Py_PackageContext = NULL; +/* Module import context -- the full module file path (__file__) for dynlib imports */ +PyObject *_Py_ModuleImportContext = NULL; + /* Helper for mkvalue() to scan the length of a format */ static int