Skip to content

Commit

Permalink
[IMP] import hook: moved to a proper location (openerp.modules.module…
Browse files Browse the repository at this point in the history
… instead of openerp-server).

bzr revid: [email protected]
  • Loading branch information
Vo Minh Thu committed Jan 9, 2012
1 parent 455e47e commit d348a0d
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 85 deletions.
84 changes: 0 additions & 84 deletions openerp-server
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
87 changes: 86 additions & 1 deletion openerp/modules/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,91 @@

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.
Expand All @@ -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.
Expand Down

0 comments on commit d348a0d

Please sign in to comment.