[IMP] module.py: deprecate openerp
[PEP-594] is deprecating the `imp` module, that module is used in `module.py` in order to dynamically import addons using any of the `odoo.addons` or `openerp.addons` import anchor. We are deprecating `openerp` module/addons imports in v13 in order to remove the support in v14 and greatly simplify how modules/addons are loaded. If you are still using the old `import openerp` or `import openerp.addons`, `import odoo` and `import odoo.addons` are drop-in replacements. The `odoo.modules.module.ad_paths` addon paths list has been deprecated too. The list is now accessible on `odoo.addons.__path__` where they are now directly loaded [2]. See also: [PEP-594]: https://python.org/dev/peps/pep-0594/ [2]: https://packaging.python.org/guides/packaging-namespace-packages/ closes odoo/odoo#36597 Task: 2003936 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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/<string:xmlid>',
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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')
|
||||
|
||||
+3
-2
@@ -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
|
||||
|
||||
+37
-54
@@ -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.<module> 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.<identifier> 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))
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
+2
-2
@@ -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):
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user