Commit 8044598c authored by Arnaud Fontaine's avatar Arnaud Fontaine

ZODB Components: Optimize find_load_module() from b45914fa ExternalMethod optimization.

This method is used to import ZODB Components when fallback on filesystem is needed
and used when loading Document and Extension Components.

1,000,000 executions:
  * Before:
    timeit("erp5.component.extension.find_load_module(module_name)",
           setup="import erp5.component.extension; module_name='Hoge'")
    59.073
    59.324
  * b45914fa ExternalMethod optimization:
    timeit("__import__('erp5.component.extension.' + module_name, fromlist='*', level=0)",
           setup="module_name='Hoge'")
    1.754
    1.845
  * This commit:
    timeit("import_module('erp5.component.extension.' + module_name)",
           setup="from importlib import import_module; module_name='Hoge'")
    1.346
    1.311
    => Faster because import_module() calls __import__() without fromlist (not
       needed as it returns module from sys.modules after this) and level
       parameters.
    => Introduced in python3 and backported to python2.7. Recommended over
       __import__ in Python documentation for non-internal usage and when
       getting the module itself and not its top-level one.
parent 7aa5fb76
...@@ -39,6 +39,7 @@ from . import aq_method_lock ...@@ -39,6 +39,7 @@ from . import aq_method_lock
from types import ModuleType from types import ModuleType
from zLOG import LOG, BLATHER, WARNING from zLOG import LOG, BLATHER, WARNING
from Acquisition import aq_base from Acquisition import aq_base
from importlib import import_module
class ComponentVersionPackage(ModuleType): class ComponentVersionPackage(ModuleType):
""" """
...@@ -369,15 +370,15 @@ class ComponentDynamicPackage(ModuleType): ...@@ -369,15 +370,15 @@ class ComponentDynamicPackage(ModuleType):
plain import would hide the real error, instead log it... plain import would hide the real error, instead log it...
""" """
fullname = self._namespace + '.' + name fullname = self._namespace + '.' + name
loader = self.find_module(fullname) try:
if loader is not None: # Wrapper around __import__ much faster than calling find_module() then
try: # load_module(), and returning module 'name' in contrary to __import__
return loader.load_module(fullname) # returning 'erp5' (requiring fromlist parameter which is slower)
except ImportError, e: return import_module(fullname)
import traceback except ImportError as e:
if str(e) != "No module named " + name:
LOG("ERP5Type.dynamic", WARNING, LOG("ERP5Type.dynamic", WARNING,
"Could not load Component module '%s'\n%s" % (fullname, "Could not load Component module %r" % fullname, error=True)
traceback.format_exc()))
return None return None
......
...@@ -52,22 +52,10 @@ class _(PatchClass(ExternalMethod)): ...@@ -52,22 +52,10 @@ class _(PatchClass(ExternalMethod)):
return self._getFunction(reload)[0] return self._getFunction(reload)[0]
def _getFunction(self, reload=False): def _getFunction(self, reload=False):
try: import erp5.component.extension
component_module = __import__( component_module = erp5.component.extension.find_load_module(self._module)
'erp5.component.extension.' + self._module, if component_module is None:
fromlist="*", level=0) # Fall back on filesystem
except ImportError, e:
if str(e) != "No module named " + self._module:
# Fall back loudly if a component exists but is broken.
# XXX: We used __import__ instead of
# erp5.component.extension.find_load_module
# because the latter is much slower.
# XXX: Should we also fall back on FS if the module imports
# successfully but does not contain the wanted function?
LOG("ERP5Type.dynamic", WARNING,
"Could not load Component module %r"
% ('erp5.component.extension.' + self._module),
error=1)
if not reload: if not reload:
from Globals import DevelopmentMode from Globals import DevelopmentMode
if DevelopmentMode: if DevelopmentMode:
......
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