details: https://code.tryton.org/tryton/commit/8f9a1a21539c
branch: default
user: Nicolas Évrard <[email protected]>
date: Tue Sep 01 18:49:45 2026 +0200
description:
Add function to import XML files for tests
Close #14627
diffstat:
trytond/CHANGELOG | 1 +
trytond/doc/ref/convert.rst | 20 +++++++++++++++++
trytond/doc/ref/index.rst | 1 +
trytond/trytond/convert.py | 51 +++++++++++++++++++++++++++++++++++++-------
4 files changed, 65 insertions(+), 8 deletions(-)
diffs (139 lines):
diff -r 419eb1c2556c -r 8f9a1a21539c trytond/CHANGELOG
--- a/trytond/CHANGELOG Tue Sep 01 21:57:25 2026 +0200
+++ b/trytond/CHANGELOG Tue Sep 01 18:49:45 2026 +0200
@@ -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
diff -r 419eb1c2556c -r 8f9a1a21539c trytond/doc/ref/convert.rst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/trytond/doc/ref/convert.rst Tue Sep 01 18:49:45 2026 +0200
@@ -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.
diff -r 419eb1c2556c -r 8f9a1a21539c trytond/doc/ref/index.rst
--- a/trytond/doc/ref/index.rst Tue Sep 01 21:57:25 2026 +0200
+++ b/trytond/doc/ref/index.rst Tue Sep 01 18:49:45 2026 +0200
@@ -28,4 +28,5 @@
filestore
cache
bus
+ convert
tests
diff -r 419eb1c2556c -r 8f9a1a21539c trytond/trytond/convert.py
--- a/trytond/trytond/convert.py Tue Sep 01 21:57:25 2026 +0200
+++ b/trytond/trytond/convert.py Tue Sep 01 18:49:45 2026 +0200
@@ -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.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 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 @@
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 @@
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 @@
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)