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

[ADD] support update mode where we never try to create records #80

Merged
merged 1 commit into from
Oct 6, 2017
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
50 changes: 47 additions & 3 deletions openupgradelib/openupgrade.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
import inspect
import uuid
import logging
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
from contextlib import contextmanager
try:
from contextlib import ExitStack
Expand All @@ -46,6 +50,7 @@ def __exit__(self, exc_type, exc_value, traceback):
self._cms.pop().__exit__(exc_type, exc_value, traceback)

from psycopg2.extensions import AsIs
from lxml import etree
from . import openupgrade_tools

core = None
Expand Down Expand Up @@ -249,9 +254,14 @@ def load_data(cr, module_name, filename, idref=None, mode='init'):
:param filename: the path to the filename, relative to the module \
directory.
:param idref: optional hash with ?id mapping cache?
:param mode: one of 'init', 'update', 'demo'. Always use 'init' \
for adding new items from files that are marked with 'noupdate'. Defaults \
to 'init'.
:param mode: one of 'init', 'update', 'demo', 'init_no_create'. \
Always use 'init' for adding new items from files that are marked with \
'noupdate'. Defaults to 'init'.
'init_no_create' is a hack to load data for records which have \
forcecreate=False set. As those records won't be recreated during the \
update, standard Odoo would recreate the record if it was deleted, \
but this will fail in cases where there are required fields to be \
filled which are not contained in the data file.
"""

if idref is None:
Expand All @@ -267,11 +277,45 @@ def load_data(cr, module_name, filename, idref=None, mode='init'):
cr, module_name, pathname, fp.read(), idref, mode, noupdate)
elif ext == '.yml':
yaml_import(cr, module_name, fp, None, idref=idref, mode=mode)
elif mode == 'init_no_create':
for fp2 in _get_existing_records(cr, fp, module_name):
tools.convert_xml_import(
cr, module_name, fp2, idref, mode='init',
)
else:
tools.convert_xml_import(cr, module_name, fp, idref, mode=mode)
finally:
fp.close()

def _get_existing_records(cr, fp, module_name):
"""yield file like objects per 'leaf' node in the xml file that exists.
This is for not trying to create a record with partial data in case the
record was removed in the database."""
def yield_element(node, path=None):
if node.tag not in ['openerp', 'odoo', 'data']:
if node.tag == 'record':
xmlid = node.attrib['id']
if '.' not in xmlid:
module = module_name
else:
module, xmlid = xmlid.split('.', 1)
cr.execute(
'select id from ir_model_data where module=%s and name=%s',
(module, xmlid)
)
if not cr.rowcount:
return
yield StringIO(etree.tostring(path))
else:
for child in node:
for value in yield_element(
child,
etree.SubElement(path, node.tag, node.attrib)
if path else etree.Element(node.tag, node.attrib)
):
yield value
return yield_element(etree.parse(fp).getroot())

# for backwards compatibility
load_xml = load_data
table_exists = openupgrade_tools.table_exists
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ coveralls
# Version locked due to https://gitlab.com/pycqa/flake8/issues/268
flake8==3.2.0
pep8-naming
lxml