Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFR] OpenUpgrade framework patches #3

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ repos:
rev: 20.8b1
hooks:
- id: black
exclude: ^openupgrade_framework/odoo_patch/
- repo: https://github.com/prettier/pre-commit
rev: v2.1.2
hooks:
Expand All @@ -53,7 +52,6 @@ repos:
- "@prettier/[email protected]"
args:
- --plugin=@prettier/plugin-xml
exclude: ^openupgrade_framework/odoo_patch/
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v7.8.1
hooks:
Expand Down Expand Up @@ -88,15 +86,13 @@ repos:
rev: v2.7.2
hooks:
- id: pyupgrade
exclude: ^openupgrade_framework/odoo_patch/
- repo: https://github.com/PyCQA/isort
rev: 5.5.1
hooks:
- id: isort
name: isort except __init__.py
args:
- --settings=.
exclude: /__init__\.py$|^openupgrade_framework/odoo_patch/
- repo: https://github.com/acsone/setuptools-odoo
rev: 2.6.0
hooks:
Expand All @@ -106,7 +102,6 @@ repos:
hooks:
- id: flake8
name: flake8 except __init__.py
exclude: /__init__\.py$|^openupgrade_framework/odoo_patch/
additional_dependencies: ["flake8-bugbear==20.1.4"]
- id: flake8
name: flake8 only __init__.py
Expand Down
1 change: 0 additions & 1 deletion openupgrade_framework/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
from . import odoo_patch
from . import openupgrade
2 changes: 1 addition & 1 deletion openupgrade_framework/__manifest__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Copyright Odoo Community Association (OCA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Openupgrade Framework",
"summary": """Module to integrate in the server_wide_modules
Expand Down
1 change: 0 additions & 1 deletion openupgrade_framework/odoo_patch/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
from . import odoo
from . import addons
Empty file.
6 changes: 1 addition & 5 deletions openupgrade_framework/odoo_patch/odoo/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
from . import modules
from . import service

# Nothing todo the function, the function check_security didn't changed
from . import http
from . import addons, models, modules
1 change: 1 addition & 0 deletions openupgrade_framework/odoo_patch/odoo/addons/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import base
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import ir_model
from . import ir_ui_view
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Copyright Odoo Community Association (OCA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openupgradelib import openupgrade
from odoo import api, models
from odoo.addons.base.models.ir_model import IrModel, IrModelData, IrModelRelation
from odoo.tools import mute_logger


def _drop_table(self):
""" Never drop tables """
for model in self:
if self.env.get(model.model) is not None:
openupgrade.message(
self.env.cr, "Unknown", False, False,
"Not dropping the table or view of model %s", model.model)


def _drop_column(self):
""" Never drop columns """
for field in self:
if field.name in models.MAGIC_COLUMNS:
continue
openupgrade.message(
self.env.cr, "Unknown", False, False,
"Not dropping the column of field %s of model %s", field.name,
field.model,
)
continue


IrModel._drop_column = _drop_column
IrModel._drop_table = _drop_table


@api.model
def _process_end(self, modules):
""" Don't warn about upgrade conventions from Odoo
('fields should be explicitely removed by an upgrade script')
"""
with mute_logger('odoo.addons.base.models.ir_model'):
return IrModelData._process_end._original_method(self, modules)


_process_end._original_method = IrModelData._process_end
IrModelData._process_end = _process_end


def _module_data_uninstall(self):
""" Don't delete many2many relation tables. Only unlink the
ir.model.relation record itself.
"""
self.unlink()


IrModelRelation._module_data_uninstall = _module_data_uninstall
Comment on lines +9 to +55
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't you be using OdooPatch?

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright Odoo Community Association (OCA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from odoo import api
from odoo.tools import mute_logger
from odoo.addons.base.models.ir_ui_view import View

_logger = logging.getLogger(__name__)


@api.constrains('arch_db')
def _check_xml(self):
""" Mute warnings about views which are common during migration """
with mute_logger('odoo.addons.base.models.ir_ui_view'):
return View._check_xml._original_method(self)


def handle_view_error(self, message, *args, raise_exception=True, from_exception=None, from_traceback=None):
""" Don't raise or log exceptions in view validation unless explicitely requested """
raise_exception = self.env.context.get('raise_view_error')
to_mute = 'odoo.addons.base.models.ir_ui_view' if raise_exception else 'not_muted'
with mute_logger(to_mute):
try:
return View.handle_view_error._original_method(
self, message, *args,
raise_exception=False, from_exception=from_exception,
from_traceback=from_traceback)
except ValueError:
_logger.warn(
"Can't render custom view %s for model %s. "
"Assuming you are migrating between major versions of "
"Odoo, this view is now set to inactive. Please "
"review the view contents manually after the migration.",
self.xml_id, self.model)
self.write({'active': False})


_check_xml._original_method = View._check_xml
View._check_xml = _check_xml
handle_view_error._original_method = View.handle_view_error
View.handle_view_error = handle_view_error
Comment on lines +38 to +41
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, shouldn't you use OdooPatch?

32 changes: 0 additions & 32 deletions openupgrade_framework/odoo_patch/odoo/http.py

This file was deleted.

33 changes: 33 additions & 0 deletions openupgrade_framework/odoo_patch/odoo/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright Odoo Community Association (OCA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from uuid import uuid4
from odoo.models import BaseModel
from odoo.addons.base.models.ir_model import MODULE_UNINSTALL_FLAG

_logger = logging.getLogger(__name__)


def unlink(self):
""" Don't break on unlink of obsolete records
when called from ir.model::_process_end()

This only adapts the base unlink method. If overrides of this method
on individual models give problems, add patches for those as well.
"""
if not self.env.context.get(MODULE_UNINSTALL_FLAG):
return BaseModel.unlink._original_method(self)
savepoint = str(uuid4)
try:
self.env.cr.execute('SAVEPOINT "%s"' % savepoint)
return BaseModel.unlink._original_method(self)
except Exception as e:
self.env.cr.execute('ROLLBACK TO SAVEPOINT "%s"' % savepoint)
_logger.warning(
"Could not delete obsolete record with ids %s of model %s: %s",
self.ids, self._name, e)
Comment on lines +20 to +28
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could just use with self.env.cr.savepoint(): ...

return False


unlink._original_method = BaseModel.unlink
BaseModel.unlink = unlink
Comment on lines +32 to +33
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same point about OdooPatch

13 changes: 1 addition & 12 deletions openupgrade_framework/odoo_patch/odoo/modules/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1 @@
# Minor changes. (call to safe_eval changed)
# otherwise : adapted to V14
from . import graph

# A lot of changes in the core functions.
from . import loading

# Adapted to V14
from . import migration

# Adapted to V14
from . import registry
from . import graph, migration
115 changes: 14 additions & 101 deletions openupgrade_framework/odoo_patch/odoo/modules/graph.py
Original file line number Diff line number Diff line change
@@ -1,108 +1,21 @@
# flake8: noqa
# pylint: skip-file

import logging
# Copyright Odoo Community Association (OCA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import odoo
import odoo.tools as tools
from odoo.tools.safe_eval import safe_eval

from odoo.modules.graph import Graph

_logger = logging.getLogger(__name__)


if True:

def _update_from_db(self, cr):
if not len(self):
return
# update the graph with values from the database (if exist)
## First, we set the default values for each package in graph
additional_data = {key: {'id': 0, 'state': 'uninstalled', 'dbdemo': False, 'installed_version': None} for key in self.keys()}
## Then we get the values from the database
cr.execute('SELECT name, id, state, demo AS dbdemo, latest_version AS installed_version'
' FROM ir_module_module'
' WHERE name IN %s',(tuple(additional_data),)
)

## and we update the default values with values from the database
additional_data.update((x['name'], x) for x in cr.dictfetchall())

# <OpenUpgrade:ADD>
# Prevent reloading of demo data from the new version on major upgrade
if ('base' in self and additional_data['base']['dbdemo'] and
additional_data['base']['installed_version'] <
odoo.release.major_version):
cr.execute("UPDATE ir_module_module SET demo = false")
for data in additional_data.values():
data['dbdemo'] = False
# </OpenUpgrade>

def update_from_db(self, cr):
""" Prevent reloading of demo data from the new version on major upgrade """
Graph.update_from_db._original_method(self, cr)
if (
"base" in self
and self["base"].dbdemo
and self["base"].installed_version < odoo.release.major_version
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 Beware! You have to use a smart version comparison algorithm. Check out odoo.tools.parse_version.

):
cr.execute("UPDATE ir_module_module SET demo = false")
for package in self.values():
for k, v in additional_data[package.name].items():
setattr(package, k, v)


def _add_modules(self, cr, module_list, force=None):
if force is None:
force = []
packages = []
len_graph = len(self)

# <OpenUpgrade:ADD>
# force additional dependencies for the upgrade process if given
# in config file
forced_deps = tools.config.get_misc('openupgrade', 'force_deps', '{}')
forced_deps = tools.config.get_misc('openupgrade',
'force_deps_' + odoo.release.version,
forced_deps)
forced_deps = safe_eval(forced_deps)
# </OpenUpgrade>

for module in module_list:
# This will raise an exception if no/unreadable descriptor file.
# NOTE The call to load_information_from_description_file is already
# done by db.initialize, so it is possible to not do it again here.
info = odoo.modules.module.load_information_from_description_file(module)
if info and info['installable']:
# <OpenUpgrade:ADD>
info['depends'].extend(forced_deps.get(module, []))
# </OpenUpgrade>
packages.append((module, info)) # TODO directly a dict, like in get_modules_with_version
elif module != 'studio_customization':
_logger.warning('module %s: not installable, skipped', module)

dependencies = dict([(p, info['depends']) for p, info in packages])
current, later = set([p for p, info in packages]), set()

while packages and current > later:
package, info = packages[0]
deps = info['depends']

# if all dependencies of 'package' are already in the graph, add 'package' in the graph
if all(dep in self for dep in deps):
if not package in current:
packages.pop(0)
continue
later.clear()
current.remove(package)
node = self.add_node(package, info)
for kind in ('init', 'demo', 'update'):
if package in tools.config[kind] or 'all' in tools.config[kind] or kind in force:
setattr(node, kind, True)
else:
later.add(package)
packages.append((package, info))
packages.pop(0)

self.update_from_db(cr)

for package in later:
unmet_deps = [p for p in dependencies[package] if p not in self]
_logger.info('module %s: Unmet dependencies: %s', package, ', '.join(unmet_deps))

return len(self) - len_graph
package.dbdemo = False


Graph.update_from_db = _update_from_db
Graph.add_modules = _add_modules
update_from_db._original_method = Graph.update_from_db
Graph.update_from_db = update_from_db
Comment on lines +20 to +21
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same about OdooPatch

Loading