To: vim_dev@googlegroups.com Subject: Patch 8.1.0201 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.0201 Problem: Newer Python uses "importlib" instead of "imp". Solution: Use "importlib" for newer Python versions. (closes #3163) Files: src/if_py_both.h, src/testdir/test87.in *** ../vim-8.1.0200/src/if_py_both.h 2018-07-08 17:18:58.420462346 +0200 --- src/if_py_both.h 2018-07-22 04:05:36.131054785 +0200 *************** *** 88,95 **** --- 88,99 ---- static PyObject *vim_module; static PyObject *vim_special_path_object; + #if PY_VERSION_HEX >= 0x030700f0 + static PyObject *py_find_spec; + #else static PyObject *py_find_module; static PyObject *py_load_module; + #endif static PyObject *VimError; *************** *** 539,544 **** --- 543,549 ---- return 0; } + #if PY_VERSION_HEX < 0x030700f0 typedef struct { PyObject_HEAD *************** *** 567,572 **** --- 572,578 ---- {"load_module", (PyCFunction)LoaderLoadModule, METH_VARARGS, ""}, { NULL, NULL, 0, NULL} }; + #endif /* Check to see whether a Vim error has been reported, or a keyboard * interrupt has been detected. *************** *** 1163,1168 **** --- 1169,1205 ---- return ret; } + #if PY_VERSION_HEX >= 0x030700f0 + static PyObject * + FinderFindSpec(PyObject *self, PyObject *args) + { + char *fullname; + PyObject *paths; + PyObject *target = Py_None; + PyObject *spec; + + if (!PyArg_ParseTuple(args, "s|O", &fullname, &target)) + return NULL; + + if (!(paths = Vim_GetPaths(self))) + return NULL; + + spec = PyObject_CallFunction(py_find_spec, "sNN", fullname, paths, target); + + Py_DECREF(paths); + + if (!spec) + { + if (PyErr_Occurred()) + return NULL; + + Py_INCREF(Py_None); + return Py_None; + } + + return spec; + } + #else static PyObject * call_load_module(char *name, int len, PyObject *find_module_result) { *************** *** 1305,1310 **** --- 1342,1348 ---- return (PyObject *) loader; } + #endif static PyObject * VimPathHook(PyObject *self UNUSED, PyObject *args) *************** *** 1336,1342 **** --- 1374,1384 ---- {"chdir", (PyCFunction)VimChdir, METH_VARARGS|METH_KEYWORDS, "Change directory"}, {"fchdir", (PyCFunction)VimFchdir, METH_VARARGS|METH_KEYWORDS, "Change directory"}, {"foreach_rtp", VimForeachRTP, METH_O, "Call given callable for each path in &rtp"}, + #if PY_VERSION_HEX >= 0x030700f0 + {"find_spec", FinderFindSpec, METH_VARARGS, "Internal use only, returns spec object for any input it receives"}, + #else {"find_module", FinderFindModule, METH_VARARGS, "Internal use only, returns loader object for any input it receives"}, + #endif {"path_hook", VimPathHook, METH_VARARGS, "Hook function to install in sys.path_hooks"}, {"_get_paths", (PyCFunction)Vim_GetPaths, METH_NOARGS, "Get &rtp-based additions to sys.path"}, { NULL, NULL, 0, NULL} *************** *** 6545,6550 **** --- 6587,6593 ---- OptionsType.tp_traverse = (traverseproc)OptionsTraverse; OptionsType.tp_clear = (inquiry)OptionsClear; + #if PY_VERSION_HEX < 0x030700f0 vim_memset(&LoaderType, 0, sizeof(LoaderType)); LoaderType.tp_name = "vim.Loader"; LoaderType.tp_basicsize = sizeof(LoaderObject); *************** *** 6552,6557 **** --- 6595,6601 ---- LoaderType.tp_doc = "vim message object"; LoaderType.tp_methods = LoaderMethods; LoaderType.tp_dealloc = (destructor)LoaderDestructor; + #endif #if PY_MAJOR_VERSION >= 3 vim_memset(&vimmodule, 0, sizeof(vimmodule)); *************** *** 6583,6589 **** --- 6627,6635 ---- PYTYPE_READY(FunctionType); PYTYPE_READY(OptionsType); PYTYPE_READY(OutputType); + #if PY_VERSION_HEX < 0x030700f0 PYTYPE_READY(LoaderType); + #endif return 0; } *************** *** 6707,6713 **** --- 6753,6761 ---- {"List", (PyObject *)&ListType}, {"Function", (PyObject *)&FunctionType}, {"Options", (PyObject *)&OptionsType}, + #if PY_VERSION_HEX < 0x030700f0 {"_Loader", (PyObject *)&LoaderType}, + #endif }; #define ADD_OBJECT(m, name, obj) \ *************** *** 6729,6734 **** --- 6777,6786 ---- PyObject *other_module; PyObject *attr; PyObject *imp; + #if PY_VERSION_HEX >= 0x030700f0 + PyObject *dict; + PyObject *cls; + #endif for (i = 0; i < (int)(sizeof(numeric_constants) / sizeof(struct numeric_constant)); *************** *** 6801,6806 **** --- 6853,6880 ---- ADD_OBJECT(m, "VIM_SPECIAL_PATH", vim_special_path_object); + #if PY_VERSION_HEX >= 0x030700f0 + if (!(imp = PyImport_ImportModule("importlib.machinery"))) + return -1; + + dict = PyModule_GetDict(imp); + + if (!(cls = PyDict_GetItemString(dict, "PathFinder"))) + { + Py_DECREF(imp); + return -1; + } + + if (!(py_find_spec = PyObject_GetAttrString(cls, "find_spec"))) + { + Py_DECREF(imp); + return -1; + } + + Py_DECREF(imp); + + ADD_OBJECT(m, "_find_spec", py_find_spec); + #else if (!(imp = PyImport_ImportModule("imp"))) return -1; *************** *** 6821,6826 **** --- 6895,6901 ---- ADD_OBJECT(m, "_find_module", py_find_module); ADD_OBJECT(m, "_load_module", py_load_module); + #endif return 0; } *** ../vim-8.1.0200/src/testdir/test87.in 2017-03-05 18:33:37.000000000 +0100 --- src/testdir/test87.in 2018-07-22 04:05:36.131054785 +0200 *************** *** 219,224 **** --- 219,225 ---- import re py33_type_error_pattern = re.compile('^__call__\(\) takes (\d+) positional argument but (\d+) were given$') + py37_exception_repr = re.compile(r'([^\(\),])(\)+)$') def ee(expr, g=globals(), l=locals()): cb = vim.current.buffer *************** *** 227,243 **** exec(expr, g, l) except Exception as e: if sys.version_info >= (3, 3) and e.__class__ is AttributeError and str(e).find('has no attribute')>=0 and not str(e).startswith("'vim."): ! cb.append(expr + ':' + repr((e.__class__, AttributeError(str(e)[str(e).rfind(" '") + 2:-1])))) elif sys.version_info >= (3, 3) and e.__class__ is ImportError and str(e).find('No module named \'') >= 0: ! cb.append(expr + ':' + repr((e.__class__, ImportError(str(e).replace("'", ''))))) elif sys.version_info >= (3, 6) and e.__class__ is ModuleNotFoundError: # Python 3.6 gives ModuleNotFoundError, change it to an ImportError ! cb.append(expr + ':' + repr((ImportError, ImportError(str(e).replace("'", ''))))) elif sys.version_info >= (3, 3) and e.__class__ is TypeError: m = py33_type_error_pattern.search(str(e)) if m: msg = '__call__() takes exactly {0} positional argument ({1} given)'.format(m.group(1), m.group(2)) ! cb.append(expr + ':' + repr((e.__class__, TypeError(msg)))) else: msg = repr((e.__class__, e)) # Messages changed with Python 3.6, change new to old. --- 228,244 ---- exec(expr, g, l) except Exception as e: if sys.version_info >= (3, 3) and e.__class__ is AttributeError and str(e).find('has no attribute')>=0 and not str(e).startswith("'vim."): ! msg = repr((e.__class__, AttributeError(str(e)[str(e).rfind(" '") + 2:-1]))) elif sys.version_info >= (3, 3) and e.__class__ is ImportError and str(e).find('No module named \'') >= 0: ! msg = repr((e.__class__, ImportError(str(e).replace("'", '')))) elif sys.version_info >= (3, 6) and e.__class__ is ModuleNotFoundError: # Python 3.6 gives ModuleNotFoundError, change it to an ImportError ! msg = repr((ImportError, ImportError(str(e).replace("'", '')))) elif sys.version_info >= (3, 3) and e.__class__ is TypeError: m = py33_type_error_pattern.search(str(e)) if m: msg = '__call__() takes exactly {0} positional argument ({1} given)'.format(m.group(1), m.group(2)) ! msg = repr((e.__class__, TypeError(msg))) else: msg = repr((e.__class__, e)) # Messages changed with Python 3.6, change new to old. *************** *** 249,257 **** oldmsg2 = '''"Can't convert 'int' object to str implicitly"''' if msg.find(newmsg2) > -1: msg = msg.replace(newmsg2, oldmsg2) - cb.append(expr + ':' + msg) elif sys.version_info >= (3, 5) and e.__class__ is ValueError and str(e) == 'embedded null byte': ! cb.append(expr + ':' + repr((TypeError, TypeError('expected bytes with no null')))) else: msg = repr((e.__class__, e)) # Some Python versions say can't, others cannot. --- 250,257 ---- oldmsg2 = '''"Can't convert 'int' object to str implicitly"''' if msg.find(newmsg2) > -1: msg = msg.replace(newmsg2, oldmsg2) elif sys.version_info >= (3, 5) and e.__class__ is ValueError and str(e) == 'embedded null byte': ! msg = repr((TypeError, TypeError('expected bytes with no null'))) else: msg = repr((e.__class__, e)) # Some Python versions say can't, others cannot. *************** *** 262,272 **** msg = msg.replace('"cannot ', '\'cannot ') if msg.find(' attributes"') > -1: msg = msg.replace(' attributes"', ' attributes\'') ! cb.append(expr + ':' + msg) else: cb.append(expr + ':NOT FAILED') except Exception as e: ! cb.append(expr + '::' + repr((e.__class__, e))) EOF :fun New(...) : return ['NewStart']+a:000+['NewEnd'] --- 262,277 ---- msg = msg.replace('"cannot ', '\'cannot ') if msg.find(' attributes"') > -1: msg = msg.replace(' attributes"', ' attributes\'') ! if sys.version_info >= (3, 7): ! msg = py37_exception_repr.sub(r'\1,\2', msg) ! cb.append(expr + ':' + msg) else: cb.append(expr + ':NOT FAILED') except Exception as e: ! msg = repr((e.__class__, e)) ! if sys.version_info >= (3, 7): ! msg = py37_exception_repr.sub(r'\1,\2', msg) ! cb.append(expr + '::' + msg) EOF :fun New(...) : return ['NewStart']+a:000+['NewEnd'] *** ../vim-8.1.0200/src/version.c 2018-07-20 23:36:21.171368602 +0200 --- src/version.c 2018-07-22 04:24:39.197154869 +0200 *************** *** 791,792 **** --- 791,794 ---- { /* Add new patch number below this line */ + /**/ + 201, /**/ -- FIRST HEAD: All right! All right! We'll kill him first and then have tea and biscuits. "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///