Add function to import XML files for tests

Close #14627
This commit is contained in:
Nicolas Évrard committed 2026-09-01 18:49:45 +02:00
1 parent f53376fa30
commit 385bce6315
4 files changed
+65 -8

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
* Add function to import XML files
* Add support for router in Pool
* Add explicit request context in URLAccessor
* Retry unfinished queued tasks
+20
View File
@@ -0,0 +1,20 @@
.. _ref-convert:
.. module:: trytond.convert
=======
Convert
=======
The ``convert`` module provides a way to import records from XML files.
import_xml
----------
.. function:: import_xml(xml, module)
Imports the records from ``xml`` into the database as if they were defined in
``module``.
Those records are not store in the Model Data table.
``xml`` can be a :py:class:`string <str>`, a :py:class:`bytes <bytes>` or a
file object.
+1
View File
@@ -28,4 +28,5 @@ Reference of the ``trytond`` API:
filestore
cache
bus
convert
tests
+43 -8
View File
@@ -1,6 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime
import io
import logging
import os.path
import re
@@ -13,6 +14,8 @@ from trytond import __version__
from trytond.pyson import CONTEXT, PYSONEncoder
from trytond.transaction import Transaction, inactive_records
__all__ = ['import_xml']
logger = logging.getLogger(__name__)
CDATA_START = re.compile(r'^\s*\<\!\[cdata\[', re.IGNORECASE)
@@ -377,13 +380,16 @@ class FS2DBAccessor:
class TrytondXmlHandler(sax.handler.ContentHandler):
def __init__(self, pool, module, module_state, modules, languages):
def __init__(
self, pool, module, module_state, modules, languages,
store_model_data=True):
"Register known taghandlers, and managed tags."
sax.handler.ContentHandler.__init__(self)
super().__init__()
self.pool = pool
self.module = module
self.ModelData = pool.get('ir.model.data')
self.store_model_data = store_model_data
self.fs2db = FS2DBAccessor(self.ModelData)
self.to_delete = self.populate_to_delete()
self.noupdate = None
@@ -474,7 +480,8 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
self.write_records(model, *actions)
self.grouped_write.clear()
if name == 'data' and self.grouped_model_data:
self.ModelData.save(self.grouped_model_data)
if self.store_model_data:
self.ModelData.save(self.grouped_model_data)
self.grouped_model_data.clear()
# Closing tag found, if we are in a delegation the handler
@@ -531,11 +538,15 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
process. The records that are not encountered are deleted from the
database in post_import."""
# Fetch the data in id descending order to avoid depedendcy
# problem when the corresponding recordds will be deleted:
module_data = self.ModelData.search([
('module', '=', self.module),
], order=[('id', 'DESC')])
if self.store_model_data:
# Fetch the data in id descending order to avoid depedendcy
# problem when the corresponding recordds will be deleted:
module_data = self.ModelData.search([
('module', '=', self.module),
], order=[('id', 'DESC')])
else:
module_data = []
return set(rec.fs_id for rec in module_data)
def import_record(self, model, values, fs_id, domain=None):
@@ -691,3 +702,27 @@ def post_import(pool, module, to_delete):
transaction.commit()
return True
def import_xml(xml):
from trytond.pool import Pool
pool = Pool()
Modules = pool.get('ir.module')
modules = {m.name for m in Modules.search([
('state', '=', 'activated'),
])}
Lang = pool.get('ir.lang')
langs = {l.code for l in Lang.search([
('translatable', '=', True),
])}
parser = TrytondXmlHandler(
pool, None, 'to activate', modules, langs, store_model_data=False)
if isinstance(xml, str):
stream = io.BytesIO(xml.encode('utf8'))
elif isinstance(xml, bytes):
stream = io.BytesIO(xml)
else:
stream = xml
parser.parse_xmlstream(stream)