[IMP] import hook: moved to a proper location (openerp.modules.module instead of openerp-server).

bzr revid: vmt@openerp.com-20120109125243-qhtr070dvtc3akb5
This commit is contained in:
Vo Minh Thu 2012-01-09 13:52:43 +01:00
parent 455e47e5e8
commit d348a0de79
2 changed files with 86 additions and 85 deletions

View File

@ -217,90 +217,6 @@ if __name__ == "__main__":
check_root_user()
openerp.tools.config.parse_config(sys.argv[1:])
class ImportHook(object):
"""
Import hook to load OpenERP addons from multiple paths.
OpenERP implements its own import-hook to load its addons. OpenERP
addons are Python modules. Originally, they were each living in their
own top-level namespace, e.g. the sale module, or the hr module. For
backward compatibility, `import <module>` is still supported. Now they
are living in `openerp.addons`. The good way to import such modules is
thus `import openerp.addons.module`.
For backward compatibility, loading an addons puts it in `sys.modules`
under both the legacy (short) name, and the new (longer) name. This
ensures that
import hr
import openerp.addons.hr
loads the hr addons only once.
When an OpenERP addons name clashes with some other installed Python
module (for instance this is the case of the `resource` addons),
obtaining the OpenERP addons is only possible with the long name. The
short name will give the expected Python module.
"""
def find_module(self, module_name, package_path):
module_parts = module_name.split('.')
if len(module_parts) == 3 and module_name.startswith('openerp.addons.'):
return self # We act as a loader too.
# TODO list of loadable modules can be cached instead of always
# calling get_module_path().
if len(module_parts) == 1 and \
openerp.modules.module.get_module_path(module_parts[0],
display_warning=False):
try:
# Check if the bare module name clashes with another module.
f, path, descr = imp.find_module(module_parts[0])
logger = logging.getLogger('init')
logger.warning("""
Ambiguous import: the OpenERP module `%s` is shadowed by another
module (available at %s).
To import it, use `import openerp.addons.<module>.`.""" % (module_name, path))
return
except ImportError, e:
# Using `import <module_name>` instead of
# `import openerp.addons.<module_name>` is ugly but not harmful
# and kept for backward compatibility.
return self # We act as a loader too.
def load_module(self, module_name):
module_parts = module_name.split('.')
if len(module_parts) == 3 and module_name.startswith('openerp.addons.'):
module_part = module_parts[2]
if module_name in sys.modules:
return sys.modules[module_name]
if len(module_parts) == 1:
module_part = module_parts[0]
if module_part in sys.modules:
return sys.modules[module_part]
try:
# Check if the bare module name shadows another module.
f, path, descr = imp.find_module(module_part)
is_shadowing = True
except ImportError, e:
# Using `import <module_name>` instead of
# `import openerp.addons.<module_name>` is ugly but not harmful
# and kept for backward compatibility.
is_shadowing = False
# Note: we don't support circular import.
f, path, descr = imp.find_module(module_part, openerp.modules.module.ad_paths)
mod = imp.load_module(module_name, f, path, descr)
if not is_shadowing:
sys.modules[module_part] = mod
sys.modules['openerp.addons.' + module_part] = mod
return mod
openerp.modules.module.initialize_sys_path()
sys.meta_path.append(ImportHook())
check_postgres_user()
openerp.netsvc.init_logger()
report_configuration()

View File

@ -56,6 +56,91 @@ loaded = []
logger = netsvc.Logger()
class AddonsImportHook(object):
"""
Import hook to load OpenERP addons from multiple paths.
OpenERP implements its own import-hook to load its addons. OpenERP
addons are Python modules. Originally, they were each living in their
own top-level namespace, e.g. the sale module, or the hr module. For
backward compatibility, `import <module>` is still supported. Now they
are living in `openerp.addons`. The good way to import such modules is
thus `import openerp.addons.module`.
For backward compatibility, loading an addons puts it in `sys.modules`
under both the legacy (short) name, and the new (longer) name. This
ensures that
import hr
import openerp.addons.hr
loads the hr addons only once.
When an OpenERP addons name clashes with some other installed Python
module (for instance this is the case of the `resource` addons),
obtaining the OpenERP addons is only possible with the long name. The
short name will give the expected Python module.
Instead of relying on some addons path, an alternative approach would be
to use pkg_resources entry points from already installed Python libraries
(and install our addons as such). Even when implemented, we would still
have to support the addons path approach for backward compatibility.
"""
def find_module(self, module_name, package_path):
module_parts = module_name.split('.')
if len(module_parts) == 3 and module_name.startswith('openerp.addons.'):
return self # We act as a loader too.
# TODO list of loadable modules can be cached instead of always
# calling get_module_path().
if len(module_parts) == 1 and \
get_module_path(module_parts[0],
display_warning=False):
try:
# Check if the bare module name clashes with another module.
f, path, descr = imp.find_module(module_parts[0])
logger = logging.getLogger('init')
logger.warning("""
Ambiguous import: the OpenERP module `%s` is shadowed by another
module (available at %s).
To import it, use `import openerp.addons.<module>.`.""" % (module_name, path))
return
except ImportError, e:
# Using `import <module_name>` instead of
# `import openerp.addons.<module_name>` is ugly but not harmful
# and kept for backward compatibility.
return self # We act as a loader too.
def load_module(self, module_name):
module_parts = module_name.split('.')
if len(module_parts) == 3 and module_name.startswith('openerp.addons.'):
module_part = module_parts[2]
if module_name in sys.modules:
return sys.modules[module_name]
if len(module_parts) == 1:
module_part = module_parts[0]
if module_part in sys.modules:
return sys.modules[module_part]
try:
# Check if the bare module name shadows another module.
f, path, descr = imp.find_module(module_part)
is_shadowing = True
except ImportError, e:
# Using `import <module_name>` instead of
# `import openerp.addons.<module_name>` is ugly but not harmful
# and kept for backward compatibility.
is_shadowing = False
# Note: we don't support circular import.
f, path, descr = imp.find_module(module_part, ad_paths)
mod = imp.load_module(module_name, f, path, descr)
if not is_shadowing:
sys.modules[module_part] = mod
sys.modules['openerp.addons.' + module_part] = mod
return mod
def initialize_sys_path():
""" Add all addons paths in sys.path.
@ -68,7 +153,7 @@ def initialize_sys_path():
ad_paths = map(lambda m: os.path.abspath(tools.ustr(m.strip())), tools.config['addons_path'].split(','))
ad_paths.append(_ad) # for get_module_path
sys.meta_path.append(AddonsImportHook())
def get_module_path(module, downloaded=False, display_warning=True):
"""Return the path of the given module.