Commit 4e244250 authored by Serhiy Storchaka's avatar Serhiy Storchaka Committed by GitHub

bpo-32946: Speed up "from ... import ..." from non-packages. (GH-5873)

parent b931bd0a
...@@ -1016,31 +1016,30 @@ def _handle_fromlist(module, fromlist, import_, *, recursive=False): ...@@ -1016,31 +1016,30 @@ def _handle_fromlist(module, fromlist, import_, *, recursive=False):
""" """
# The hell that is fromlist ... # The hell that is fromlist ...
# If a package was imported, try to import stuff from fromlist. # If a package was imported, try to import stuff from fromlist.
if hasattr(module, '__path__'): for x in fromlist:
for x in fromlist: if not isinstance(x, str):
if not isinstance(x, str): if recursive:
if recursive: where = module.__name__ + '.__all__'
where = module.__name__ + '.__all__' else:
else: where = "``from list''"
where = "``from list''" raise TypeError(f"Item in {where} must be str, "
raise TypeError(f"Item in {where} must be str, " f"not {type(x).__name__}")
f"not {type(x).__name__}") elif x == '*':
elif x == '*': if not recursive and hasattr(module, '__all__'):
if not recursive and hasattr(module, '__all__'): _handle_fromlist(module, module.__all__, import_,
_handle_fromlist(module, module.__all__, import_, recursive=True)
recursive=True) elif not hasattr(module, x):
elif not hasattr(module, x): from_name = '{}.{}'.format(module.__name__, x)
from_name = '{}.{}'.format(module.__name__, x) try:
try: _call_with_frames_removed(import_, from_name)
_call_with_frames_removed(import_, from_name) except ModuleNotFoundError as exc:
except ModuleNotFoundError as exc: # Backwards-compatibility dictates we ignore failed
# Backwards-compatibility dictates we ignore failed # imports triggered by fromlist for modules that don't
# imports triggered by fromlist for modules that don't # exist.
# exist. if (exc.name == from_name and
if (exc.name == from_name and sys.modules.get(from_name, _NEEDS_LOADING) is not None):
sys.modules.get(from_name, _NEEDS_LOADING) is not None): continue
continue raise
raise
return module return module
...@@ -1102,8 +1101,10 @@ def __import__(name, globals=None, locals=None, fromlist=(), level=0): ...@@ -1102,8 +1101,10 @@ def __import__(name, globals=None, locals=None, fromlist=(), level=0):
# Slice end needs to be positive to alleviate need to special-case # Slice end needs to be positive to alleviate need to special-case
# when ``'.' not in name``. # when ``'.' not in name``.
return sys.modules[module.__name__[:len(module.__name__)-cut_off]] return sys.modules[module.__name__[:len(module.__name__)-cut_off]]
else: elif hasattr(module, '__path__'):
return _handle_fromlist(module, fromlist, _gcd_import) return _handle_fromlist(module, fromlist, _gcd_import)
else:
return module
def _builtin_from_name(name): def _builtin_from_name(name):
......
Importing names from already imported module with "from ... import ..." is
now 30% faster if the module is not a package.
...@@ -1800,10 +1800,21 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, ...@@ -1800,10 +1800,21 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
} }
} }
else { else {
final_mod = _PyObject_CallMethodIdObjArgs(interp->importlib, _Py_IDENTIFIER(__path__);
&PyId__handle_fromlist, mod, PyObject *path;
fromlist, interp->import_func, if (_PyObject_LookupAttrId(mod, &PyId___path__, &path) < 0) {
NULL); goto error;
}
if (path) {
Py_DECREF(path);
final_mod = _PyObject_CallMethodIdObjArgs(
interp->importlib, &PyId__handle_fromlist,
mod, fromlist, interp->import_func, NULL);
}
else {
final_mod = mod;
Py_INCREF(mod);
}
} }
error: error:
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment