diff --git a/addons/base_import_module/models/ir_module.py b/addons/base_import_module/models/ir_module.py index ce1499941a9..eda9562fd65 100644 --- a/addons/base_import_module/models/ir_module.py +++ b/addons/base_import_module/models/ir_module.py @@ -8,6 +8,7 @@ import sys import zipfile from os.path import join as opj +import odoo from odoo import api, fields, models, _ from odoo.exceptions import UserError from odoo.modules import load_information_from_description_file @@ -125,7 +126,7 @@ class IrModule(models.Model): with tempdir() as module_dir: import odoo.modules.module as module try: - module.ad_paths.append(module_dir) + odoo.addons.__path__.append(module_dir) z.extractall(module_dir) dirs = [d for d in os.listdir(module_dir) if os.path.isdir(opj(module_dir, d))] for mod_name in dirs: @@ -139,7 +140,7 @@ class IrModule(models.Model): _logger.exception('Error while importing module') errors[mod_name] = exception_to_unicode(e) finally: - module.ad_paths.remove(module_dir) + odoo.addons.__path__.remove(module_dir) r = ["Successfully imported module '%s'" % mod for mod in success] for mod, error in errors.items(): r.append("Error while importing module '%s'.\n\n %s \n Make sure those modules are installed and try again." % (mod, error)) diff --git a/addons/transifex/models/ir_translation.py b/addons/transifex/models/ir_translation.py index 6c9e84755d7..ed1150f8d14 100644 --- a/addons/transifex/models/ir_translation.py +++ b/addons/transifex/models/ir_translation.py @@ -10,8 +10,8 @@ from os.path import join as opj import os import werkzeug +import odoo from odoo import models, fields -from odoo.modules.module import ad_paths class IrTranslation(models.Model): @@ -27,7 +27,7 @@ class IrTranslation(models.Model): tx_config_file = ConfigParser() tx_sections = [] - for addon_path in ad_paths: + for addon_path in odoo.addons.__path__: tx_path = opj(addon_path, '.tx', 'config') if os.path.isfile(tx_path): tx_config_file.read(tx_path) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 3aa2c0e64d9..8fabef0bf38 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1155,7 +1155,8 @@ class View(http.Controller): class Binary(http.Controller): def placeholder(self, image='placeholder.png'): - return tools.file_open(get_resource_path('web', 'static/src/img', image), 'rb').read() + with tools.file_open(get_resource_path('web', 'static/src/img', image), 'rb') as fd: + return fd.read() @http.route(['/web/content', '/web/content/', diff --git a/odoo/addons/base/models/ir_attachment.py b/odoo/addons/base/models/ir_attachment.py index 7aae9cc5910..27b52033ab5 100644 --- a/odoo/addons/base/models/ir_attachment.py +++ b/odoo/addons/base/models/ir_attachment.py @@ -100,7 +100,8 @@ class IrAttachment(models.Model): if bin_size: r = human_size(os.path.getsize(full_path)) else: - r = base64.b64encode(open(full_path,'rb').read()) + with open(full_path,'rb') as fd: + r = base64.b64encode(fd.read()) except (IOError, OSError): _logger.info("_read_file reading %s", full_path, exc_info=True) return r diff --git a/odoo/cli/server.py b/odoo/cli/server.py index fcb7f2de700..f6214aaa6e7 100644 --- a/odoo/cli/server.py +++ b/odoo/cli/server.py @@ -59,7 +59,7 @@ def report_configuration(): _logger.info("Odoo version %s", __version__) if os.path.isfile(config.rcfile): _logger.info("Using configuration file at " + config.rcfile) - _logger.info('addons paths: %s', odoo.modules.module.ad_paths) + _logger.info('addons paths: %s', odoo.addons.__path__) if config.get('upgrades_paths'): _logger.info('upgrades path: %s', config['upgrades_paths']) host = config['db_host'] or os.environ.get('PGHOST', 'default') diff --git a/odoo/http.py b/odoo/http.py index cc26cd80a1f..9e0da1768fc 100644 --- a/odoo/http.py +++ b/odoo/http.py @@ -1299,14 +1299,15 @@ class Root(object): controllers and configure them. """ # TODO should we move this to ir.http so that only configured modules are served ? statics = {} - for addons_path in odoo.modules.module.ad_paths: + for addons_path in odoo.addons.__path__: for module in sorted(os.listdir(str(addons_path))): if module not in addons_manifest: mod_path = opj(addons_path, module) manifest_path = module_manifest(mod_path) path_static = opj(addons_path, module, 'static') if manifest_path and os.path.isdir(path_static): - manifest_data = open(manifest_path, 'rb').read() + with open(manifest_path, 'rb') as fd: + manifest_data = fd.read() manifest = ast.literal_eval(pycompat.to_text(manifest_data)) if not manifest.get('installable', True): continue diff --git a/odoo/modules/module.py b/odoo/modules/module.py index 13c1600985e..53f1ee6d77e 100644 --- a/odoo/modules/module.py +++ b/odoo/modules/module.py @@ -31,60 +31,45 @@ README = ['README.rst', 'README.md', 'README.txt'] _logger = logging.getLogger(__name__) # addons path as a list -ad_paths = [] +# ad_paths is a deprecated alias, please use odoo.addons.__path__ +@tools.lazy +def ad_paths(): + _logger.warning('"odoo.modules.module.ad_paths" is a deprecated ' + 'proxy to "odoo.addons.__path__". Please consider ' + 'using the latter as the former is going to be ' + 'removed in the next version.', + exc_info=DeprecationWarning(), stack_info=True) + return odoo.addons.__path__ hooked = False # Modules already loaded loaded = [] class AddonsHook(object): - """ Makes modules accessible through openerp.addons.* and odoo.addons.* """ + """ Makes modules accessible through openerp.addons.* """ def find_module(self, name, path=None): - if name.startswith(('odoo.addons.', 'openerp.addons.'))\ - and name.count('.') == 2: + if name.startswith('openerp.addons.') and name.count('.') == 2: + _logger.warning('"openerp.addons" is a deprecated alias to ' + '"odoo.addons". Please consider using the ' + 'latter as the former is going to be removed ' + 'in the next version.', + exc_info=DeprecationWarning(), stack_info=True) return self def load_module(self, name): assert name not in sys.modules - # get canonical names odoo_name = re.sub(r'^openerp.addons.(\w+)$', r'odoo.addons.\g<1>', name) - openerp_name = re.sub(r'^odoo.addons.(\w+)$', r'openerp.addons.\g<1>', odoo_name) - assert odoo_name not in sys.modules - assert openerp_name not in sys.modules + odoo_module = sys.modules.get(odoo_name) + if not odoo_module: + odoo_module = importlib.import_module(odoo_name) - # get module name in addons paths - _1, _2, addon_name = name.split('.') - # load module - f, path, (_suffix, _mode, type_) = imp.find_module(addon_name, ad_paths) - if f: f.close() + sys.modules[name] = odoo_module - # TODO: fetch existing module from sys.modules if reloads permitted - # create empty odoo.addons.* module, set name - new_mod = types.ModuleType(odoo_name) - new_mod.__loader__ = self + return odoo_module - # module top-level can only be a package - assert type_ == imp.PKG_DIRECTORY, "Odoo addon top-level must be a package" - modfile = opj(path, '__init__.py') - new_mod.__file__ = modfile - new_mod.__path__ = [path] - new_mod.__package__ = odoo_name - - # both base and alias should be in sys.modules to handle recursive and - # corecursive situations - sys.modules[odoo_name] = sys.modules[openerp_name] = new_mod - - # execute source in context of module *after* putting everything in - # sys.modules, so recursive import works - exec(open(modfile, 'rb').read(), new_mod.__dict__) - - # people import openerp.addons and expect openerp.addons. to work - setattr(odoo.addons, addon_name, new_mod) - - return sys.modules[name] # need to register loader with setuptools as Jinja relies on it when using # PackageLoader pkg_resources.register_loader_type(AddonsHook, pkg_resources.DefaultProvider) @@ -96,6 +81,11 @@ class OdooHook(object): # openerp.addons. should already be matched by AddonsHook, # only framework and subdirectories of modules should match if re.match(r'^openerp\b', name): + _logger.warning('openerp is a deprecated alias to odoo. ' + 'Please consider using the latter as the ' + 'former is going to be removed in the next ' + 'version.', + exc_info=DeprecationWarning(), stack_info=True) return self def load_module(self, name): @@ -125,28 +115,21 @@ def initialize_sys_path(): ``import odoo.addons.crm``) works even if the addons are not in the PYTHONPATH. """ - global ad_paths global hooked dd = os.path.normcase(tools.config.addons_data_dir) - if os.access(dd, os.R_OK) and dd not in ad_paths: - ad_paths.append(dd) + if os.access(dd, os.R_OK) and dd not in odoo.addons.__path__: + odoo.addons.__path__.append(dd) for ad in tools.config['addons_path'].split(','): ad = os.path.normcase(os.path.abspath(tools.ustr(ad.strip()))) - if ad not in ad_paths: - ad_paths.append(ad) + if ad not in odoo.addons.__path__: + odoo.addons.__path__.append(ad) # add base module path base_path = os.path.normcase(os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'addons'))) - if base_path not in ad_paths and os.path.isdir(base_path): - ad_paths.append(base_path) - - # add odoo.addons.__path__ - for ad in __import__('odoo.addons').addons.__path__: - ad = os.path.abspath(ad) - if ad not in ad_paths and os.path.isdir(ad): - ad_paths.append(ad) + if base_path not in odoo.addons.__path__ and os.path.isdir(base_path): + odoo.addons.__path__.append(base_path) if not hooked: sys.meta_path.insert(0, OdooHook()) @@ -162,7 +145,7 @@ def get_module_path(module, downloaded=False, display_warning=True): """ initialize_sys_path() - for adp in ad_paths: + for adp in odoo.addons.__path__: files = [opj(adp, module, manifest) for manifest in MANIFEST_NAMES] +\ [opj(adp, module + '.zip')] if any(os.path.exists(f) for f in files): @@ -241,7 +224,7 @@ def get_resource_from_path(path): :return: tuple(module_name, relative_path, os_relative_path) if possible, else None """ resource = False - for adpath in ad_paths: + for adpath in odoo.addons.__path__: # force trailing separator adpath = os.path.join(adpath, "") if os.path.commonprefix([adpath, path]) == adpath: @@ -338,8 +321,8 @@ def load_information_from_description_file(module, mod_path=None): readme_path = [opj(mod_path, x) for x in README if os.path.isfile(opj(mod_path, x))] if readme_path: - readme_text = tools.file_open(readme_path[0]).read() - info['description'] = readme_text + with tools.file_open(readme_path[0]) as fd: + info['description'] = fd.read() # auto_install is set to `False` if disabled, and a set of # auto_install dependencies otherwise. That way, we can set @@ -418,7 +401,7 @@ def get_modules(): plist = [] initialize_sys_path() - for ad in ad_paths: + for ad in odoo.addons.__path__: plist.extend(listdir(ad)) return list(set(plist)) diff --git a/odoo/service/server.py b/odoo/service/server.py index 490d204d166..15d3009e36b 100644 --- a/odoo/service/server.py +++ b/odoo/service/server.py @@ -210,7 +210,7 @@ class FSWatcherBase(object): class FSWatcherWatchdog(FSWatcherBase): def __init__(self): self.observer = Observer() - for path in odoo.modules.module.ad_paths: + for path in odoo.addons.__path__: _logger.info('Watching addons folder %s', path) self.observer.schedule(self, path, recursive=True) @@ -236,7 +236,7 @@ class FSWatcherInotify(FSWatcherBase): inotify.adapters._LOGGER.setLevel(logging.ERROR) # recreate a list as InotifyTrees' __init__ deletes the list's items paths_to_watch = [] - for path in odoo.modules.module.ad_paths: + for path in odoo.addons.__path__: paths_to_watch.append(path) _logger.info('Watching addons folder %s', path) self.watcher = InotifyTrees(paths_to_watch, mask=INOTIFY_LISTEN_EVENTS, block_duration_s=.5) diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py index 356e08db371..5715c9b83c6 100644 --- a/odoo/tools/misc.py +++ b/odoo/tools/misc.py @@ -157,7 +157,7 @@ def file_open(name, mode="r", subdir='addons', pathinfo=False): @return fileobject if pathinfo is False else (fileobject, filepath) """ import odoo.modules as addons - adps = addons.module.ad_paths + adps = odoo.addons.__path__ rtp = os.path.normcase(os.path.abspath(config['root_path'])) basename = name @@ -205,7 +205,7 @@ def _fileopen(path, mode, basedir, pathinfo, basename=None): name = os.path.normpath(os.path.normcase(os.path.join(basedir, path))) import odoo.modules as addons - paths = addons.module.ad_paths + [config['root_path']] + paths = odoo.addons.__path__ + [config['root_path']] for addons_path in paths: addons_path = os.path.normpath(os.path.normcase(addons_path)) + os.sep if name.startswith(addons_path): diff --git a/odoo/tools/translate.py b/odoo/tools/translate.py index 39edaee9423..761da202dc1 100644 --- a/odoo/tools/translate.py +++ b/odoo/tools/translate.py @@ -954,7 +954,7 @@ def trans_generate(lang, modules, cr): for m in env['ir.module.module'].search_read([('state', '=', 'installed')], fields=['name']) ] - path_list = [(path, True) for path in odoo.modules.module.ad_paths] + path_list = [(path, True) for path in odoo.addons.__path__] # Also scan these non-addon paths for bin_path in ['osv', 'report', 'modules', 'service', 'tools']: path_list.append((os.path.join(config['root_path'], bin_path), True))