diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -780,6 +780,9 @@ class _FileFinder: mod_filename = tail_module + suffix full_path = _path_join(self.path, mod_filename) if _path_isfile(full_path) and _case_ok(self.path, mod_filename): + if "module" in suffix: + msg = "deprecated module file name format: {!r}" + _warnings.warn(msg.format(mod_filename), DeprecationWarning) return loader(fullname, full_path) return None diff --git a/Lib/importlib/test/extension/test_finder.py b/Lib/importlib/test/extension/test_finder.py --- a/Lib/importlib/test/extension/test_finder.py +++ b/Lib/importlib/test/extension/test_finder.py @@ -2,8 +2,13 @@ from importlib import _bootstrap from .. import abc from . import util +import imp +import os import unittest +from test.support import TESTFN, unlink + + class FinderTests(abc.FinderTests): """Test the finder for extension modules.""" @@ -37,6 +42,26 @@ class FinderTests(abc.FinderTests): # XXX Raise an exception if someone tries to use the 'path' argument? + def test_deprecated_suffixes(self): + # Issue #14040: deprecated C extension suffixes + suffixes = [suffix for suffix, _, kind in imp.get_suffixes() + if kind == imp.C_EXTENSION and 'module' in suffix] + if not suffixes: + self.skipTest("no deprecated suffixes to test for") + importer = _bootstrap._FileFinder(os.curdir, + _bootstrap._ExtensionFinderDetails()) + for suffix in suffixes: + module_filename = TESTFN + suffix + with open(module_filename, 'wb') as f: + pass + try: + with self.assertWarns(DeprecationWarning) as cm: + imp.find_module(TESTFN, [os.curdir]) + self.assertIn(module_filename, str(cm.warning)) + finally: + unlink(module_filename) + + def test_main(): from test.support import run_unittest diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -331,6 +331,23 @@ class ImportTests(unittest.TestCase): del sys.path[0] remove_files(TESTFN) + def test_deprecated_suffixes(self): + # Issue #14040: deprecated C extension suffixes + suffixes = [suffix for suffix, _, kind in imp.get_suffixes() + if kind == imp.C_EXTENSION and 'module' in suffix] + if not suffixes: + self.skipTest("no deprecated suffixes to test for") + for suffix in suffixes: + module_filename = TESTFN + suffix + with open(module_filename, 'wb') as f: + pass + try: + with self.assertWarns(DeprecationWarning) as cm: + imp.find_module(TESTFN, [os.curdir]) + self.assertIn(module_filename, str(cm.warning)) + finally: + unlink(module_filename) + class PycRewritingTests(unittest.TestCase): # Test that the `co_filename` attribute on code objects always points diff --git a/Python/dynload_aix.c b/Python/dynload_aix.c --- a/Python/dynload_aix.c +++ b/Python/dynload_aix.c @@ -27,8 +27,8 @@ typedef struct Module { } Module, *ModulePtr; const struct filedescr _PyImport_DynLoadFiletab[] = { - {".so", "rb", C_EXTENSION}, - {"module.so", "rb", C_EXTENSION}, + {".so", "rb", C_EXTENSION, 0}, + {"module.so", "rb", C_EXTENSION, 1}, {0, 0} }; diff --git a/Python/dynload_dl.c b/Python/dynload_dl.c --- a/Python/dynload_dl.c +++ b/Python/dynload_dl.c @@ -10,8 +10,8 @@ extern char *Py_GetProgramName(void); const struct filedescr _PyImport_DynLoadFiletab[] = { - {".o", "rb", C_EXTENSION}, - {"module.o", "rb", C_EXTENSION}, + {".o", "rb", C_EXTENSION, 0}, + {"module.o", "rb", C_EXTENSION, 1}, {0, 0} }; diff --git a/Python/dynload_hpux.c b/Python/dynload_hpux.c --- a/Python/dynload_hpux.c +++ b/Python/dynload_hpux.c @@ -14,8 +14,8 @@ #endif const struct filedescr _PyImport_DynLoadFiletab[] = { - {SHLIB_EXT, "rb", C_EXTENSION}, - {"module"SHLIB_EXT, "rb", C_EXTENSION}, + {SHLIB_EXT, "rb", C_EXTENSION, 0}, + {"module"SHLIB_EXT, "rb", C_EXTENSION, 1}, {0, 0} }; diff --git a/Python/dynload_next.c b/Python/dynload_next.c --- a/Python/dynload_next.c +++ b/Python/dynload_next.c @@ -9,8 +9,8 @@ #include const struct filedescr _PyImport_DynLoadFiletab[] = { - {".so", "rb", C_EXTENSION}, - {"module.so", "rb", C_EXTENSION}, + {".so", "rb", C_EXTENSION, 0}, + {"module.so", "rb", C_EXTENSION, 1}, {0, 0} }; diff --git a/Python/dynload_os2.c b/Python/dynload_os2.c --- a/Python/dynload_os2.c +++ b/Python/dynload_os2.c @@ -10,8 +10,8 @@ const struct filedescr _PyImport_DynLoadFiletab[] = { - {".pyd", "rb", C_EXTENSION}, - {".dll", "rb", C_EXTENSION}, + {".pyd", "rb", C_EXTENSION, 0}, + {".dll", "rb", C_EXTENSION, 0}, {0, 0} }; diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c --- a/Python/dynload_shlib.c +++ b/Python/dynload_shlib.c @@ -38,25 +38,25 @@ const struct filedescr _PyImport_DynLoadFiletab[] = { #ifdef __CYGWIN__ - {".dll", "rb", C_EXTENSION}, - {"module.dll", "rb", C_EXTENSION}, + {".dll", "rb", C_EXTENSION, 0}, + {"module.dll", "rb", C_EXTENSION, 1}, #else /* !__CYGWIN__ */ #if defined(PYOS_OS2) && defined(PYCC_GCC) - {".pyd", "rb", C_EXTENSION}, - {".dll", "rb", C_EXTENSION}, + {".pyd", "rb", C_EXTENSION, 0}, + {".dll", "rb", C_EXTENSION, 1}, #else /* !(defined(PYOS_OS2) && defined(PYCC_GCC)) */ #ifdef __VMS - {".exe", "rb", C_EXTENSION}, - {".EXE", "rb", C_EXTENSION}, - {"module.exe", "rb", C_EXTENSION}, - {"MODULE.EXE", "rb", C_EXTENSION}, + {".exe", "rb", C_EXTENSION, 0}, + {".EXE", "rb", C_EXTENSION, 0}, + {"module.exe", "rb", C_EXTENSION, 0}, + {"MODULE.EXE", "rb", C_EXTENSION, 0}, #else /* !__VMS */ - {"." SOABI ".so", "rb", C_EXTENSION}, - {"module." SOABI ".so", "rb", C_EXTENSION}, - {".abi" PYTHON_ABI_STRING ".so", "rb", C_EXTENSION}, - {"module.abi" PYTHON_ABI_STRING ".so", "rb", C_EXTENSION}, - {".so", "rb", C_EXTENSION}, - {"module.so", "rb", C_EXTENSION}, + {"." SOABI ".so", "rb", C_EXTENSION, 0}, + {"module." SOABI ".so", "rb", C_EXTENSION, 1}, + {".abi" PYTHON_ABI_STRING ".so", "rb", C_EXTENSION, 0}, + {"module.abi" PYTHON_ABI_STRING ".so", "rb", C_EXTENSION, 1}, + {".so", "rb", C_EXTENSION, 0}, + {"module.so", "rb", C_EXTENSION, 1}, #endif /* __VMS */ #endif /* defined(PYOS_OS2) && defined(PYCC_GCC) */ #endif /* __CYGWIN__ */ diff --git a/Python/dynload_win.c b/Python/dynload_win.c --- a/Python/dynload_win.c +++ b/Python/dynload_win.c @@ -17,9 +17,9 @@ void _Py_DeactivateActCtx(ULONG_PTR cook const struct filedescr _PyImport_DynLoadFiletab[] = { #ifdef _DEBUG - {"_d.pyd", "rb", C_EXTENSION}, + {"_d.pyd", "rb", C_EXTENSION, 0}, #else - {".pyd", "rb", C_EXTENSION}, + {".pyd", "rb", C_EXTENSION, 0}, #endif {0, 0} }; diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -1994,6 +1994,14 @@ find_module_path_list(PyObject *fullname } if (match) { Py_DECREF(prefix); + if (fdp->deprecated && + PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "deprecated module file name format: %R", + filename)) { + Py_DECREF(filename); + fclose(fp); + return NULL; + } *p_path = filename; *p_fp = fp; return fdp; diff --git a/Python/importdl.h b/Python/importdl.h --- a/Python/importdl.h +++ b/Python/importdl.h @@ -24,6 +24,7 @@ struct filedescr { char *suffix; char *mode; enum filetype type; + int deprecated; }; extern struct filedescr * _PyImport_Filetab; extern const struct filedescr _PyImport_DynLoadFiletab[];