details: https://code.tryton.org/tryton/commit/d5204e72c1ba
branch: default
user: Cédric Krier <[email protected]>
date: Thu Dec 11 17:57:01 2025 +0100
description:
Lazy import html2text and weasyprint
diffstat:
modules/marketing_automation/marketing_automation.py | 12 +-----
modules/marketing_email/marketing.py | 11 +-----
trytond/doc/ref/report.rst | 7 ++++
trytond/trytond/ir/email_.py | 22 ++++--------
trytond/trytond/report/__init__.py | 4 +-
trytond/trytond/report/report.py | 35 +++++++------------
trytond/trytond/tests/test_report.py | 6 +-
7 files changed, 37 insertions(+), 60 deletions(-)
diffs (230 lines):
diff -r 79ee566ee0dc -r d5204e72c1ba
modules/marketing_automation/marketing_automation.py
--- a/modules/marketing_automation/marketing_automation.py Thu Dec 11
16:31:51 2025 +0100
+++ b/modules/marketing_automation/marketing_automation.py Thu Dec 11
17:57:01 2025 +0100
@@ -11,12 +11,6 @@
parse_qsl, quote, urlencode, urljoin, urlsplit, urlunsplit)
from dateutil.relativedelta import relativedelta
-
-try:
- import html2text
-except ImportError:
- html2text = None
-
from genshi.core import END, START, Attrs, QName
from genshi.template import MarkupTemplate
from genshi.template import TemplateError as GenshiTemplateError
@@ -31,7 +25,7 @@
fields)
from trytond.pool import Pool
from trytond.pyson import Eval, If, PYSONDecoder, TimeDelta
-from trytond.report import Report
+from trytond.report import Report, html_to_text
from trytond.sendmail import SMTPDataManager, send_message_transactional
from trytond.tools import grouped_slice, pairwise_longest, reduce_ids
from trytond.tools.chart import sparkline
@@ -750,9 +744,7 @@
set_from_header(msg, from_, sender or from_)
msg['To'] = to
msg['Subject'] = subject
- if html2text:
- converter = html2text.HTML2Text()
- content_text = converter.handle(content)
+ if content_text := html_to_text(content):
msg.add_alternative(content_text, subtype='plain')
if msg.is_multipart():
msg.add_alternative(content, subtype='html')
diff -r 79ee566ee0dc -r d5204e72c1ba modules/marketing_email/marketing.py
--- a/modules/marketing_email/marketing.py Thu Dec 11 16:31:51 2025 +0100
+++ b/modules/marketing_email/marketing.py Thu Dec 11 17:57:01 2025 +0100
@@ -14,11 +14,6 @@
from sql import Literal
from sql.aggregate import Count
-try:
- import html2text
-except ImportError:
- html2text = None
-
import trytond.config as config
from trytond.i18n import gettext
from trytond.ir.session import token_hex
@@ -26,7 +21,7 @@
DeactivableMixin, Index, ModelSQL, ModelView, Unique, Workflow, fields)
from trytond.pool import Pool
from trytond.pyson import Eval
-from trytond.report import Report, get_email
+from trytond.report import Report, get_email, html_to_text
from trytond.sendmail import SMTPDataManager, send_message_transactional
from trytond.tools import grouped_slice, reduce_ids
from trytond.tools.email_ import (
@@ -506,9 +501,7 @@
msg['List-Unsubscribe'] = (
f'<{email.get_email_unsubscribe_url()}>')
msg['List-Unsubscribe-Post'] = 'List-Unsubscribe=One-Click'
- if html2text:
- converter = html2text.HTML2Text()
- content_text = converter.handle(content)
+ if content_text := html_to_text(content):
msg.add_alternative(content_text, subtype='plain')
if msg.is_multipart():
msg.add_alternative(content, subtype='html')
diff -r 79ee566ee0dc -r d5204e72c1ba trytond/doc/ref/report.rst
--- a/trytond/doc/ref/report.rst Thu Dec 11 16:31:51 2025 +0100
+++ b/trytond/doc/ref/report.rst Thu Dec 11 17:57:01 2025 +0100
@@ -147,3 +147,10 @@
.. warning::
It may return the content unconverted if some dependencies are missing.
+
+.. function:: html_to_text(content):
+
+ Converts ``HTML`` content to plain text.
+
+ .. warning::
+ It may return ``None`` if some dependencies are missing.
diff -r 79ee566ee0dc -r d5204e72c1ba trytond/trytond/ir/email_.py
--- a/trytond/trytond/ir/email_.py Thu Dec 11 16:31:51 2025 +0100
+++ b/trytond/trytond/ir/email_.py Thu Dec 11 17:57:01 2025 +0100
@@ -6,10 +6,6 @@
from email.message import EmailMessage
from email.utils import getaddresses
-try:
- import html2text
-except ImportError:
- html2text = None
from genshi.template import TextTemplate
import trytond.config as config
@@ -18,7 +14,7 @@
from trytond.model.exceptions import AccessError, ValidationError
from trytond.pool import Pool
from trytond.pyson import Bool, Eval, PYSONDecoder
-from trytond.report import Report
+from trytond.report import Report, html_to_text
from trytond.rpc import RPC
from trytond.sendmail import send_message_transactional
from trytond.tools import escape_wildcard, slugify
@@ -107,16 +103,14 @@
'body': body,
'signature': user.signature or '',
}
- if html2text:
- body_text = HTML_EMAIL % {
- 'subject': subject,
- 'body': body,
- 'signature': '',
- }
- converter = html2text.HTML2Text()
- body_text = converter.handle(body_text)
+ body_text = HTML_EMAIL % {
+ 'subject': subject,
+ 'body': body,
+ 'signature': '',
+ }
+ if body_text := html_to_text(body_text):
if user.signature:
- body_text += '\n-- \n' + converter.handle(user.signature)
+ body_text += '\n-- \n' + html_to_text(user.signature)
msg.add_alternative(body_text, subtype='plain')
if msg.is_multipart():
msg.add_alternative(body_html, subtype='html')
diff -r 79ee566ee0dc -r d5204e72c1ba trytond/trytond/report/__init__.py
--- a/trytond/trytond/report/__init__.py Thu Dec 11 16:31:51 2025 +0100
+++ b/trytond/trytond/report/__init__.py Thu Dec 11 17:57:01 2025 +0100
@@ -1,5 +1,5 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
-from .report import Report, get_email, mjml_to_html
+from .report import Report, get_email, html_to_text, mjml_to_html
-__all__ = [Report, get_email, mjml_to_html]
+__all__ = [Report, get_email, html_to_text, mjml_to_html]
diff -r 79ee566ee0dc -r d5204e72c1ba trytond/trytond/report/report.py
--- a/trytond/trytond/report/report.py Thu Dec 11 16:31:51 2025 +0100
+++ b/trytond/trytond/report/report.py Thu Dec 11 17:57:01 2025 +0100
@@ -21,17 +21,6 @@
from itertools import groupby
import dateutil.tz
-
-try:
- import html2text
-except ImportError:
- html2text = None
-
-try:
- import weasyprint
-except ImportError:
- weasyprint = None
-
from genshi.filters import Translator
from genshi.template.text import TextTemplate
@@ -422,10 +411,10 @@
input_format = report.template_extension
output_format = report.extension or report.template_extension
- if (weasyprint
- and input_format in {'html', 'xhtml'}
+ if (input_format in {'html', 'xhtml'}
and output_format == 'pdf'):
- return output_format, weasyprint.HTML(string=data).write_pdf()
+ if weasyprint := _lazy_import('weasyprint'):
+ return output_format, weasyprint.HTML(string=data).write_pdf()
if (input_format == 'xml'
and output_format == 'html'
@@ -612,7 +601,6 @@
else:
report_name = report
Report_ = pool.get(report_name, type='report')
- converter = None
title = None
msg = EmailMessage()
header_factory = msg.policy.header_factory
@@ -631,13 +619,11 @@
break
else:
maintype, subtype = 'application', ext
- if maintype == 'text' and subtype == 'html' and html2text:
- if not converter:
- converter = html2text.HTML2Text()
- content_text = converter.handle(content)
- msg.add_alternative(content_text, subtype='plain', headers=[
- header_factory('Content-Language', language.code),
- ])
+ if maintype == 'text' and subtype == 'html':
+ if content_text := html_to_text(content):
+ msg.add_alternative(content_text, subtype='plain', headers=[
+ header_factory('Content-Language', language.code),
+ ])
types = {
'subtype': subtype,
}
@@ -663,3 +649,8 @@
if mrml := _lazy_import('mrml'):
content = mrml.to_html(content).content
return content
+
+
+def html_to_text(content):
+ if html2text := _lazy_import('html2text'):
+ return html2text.HTML2Text().handle(content)
diff -r 79ee566ee0dc -r d5204e72c1ba trytond/trytond/tests/test_report.py
--- a/trytond/trytond/tests/test_report.py Thu Dec 11 16:31:51 2025 +0100
+++ b/trytond/trytond/tests/test_report.py Thu Dec 11 17:57:01 2025 +0100
@@ -136,9 +136,9 @@
'<!doctype html><title>Test</title>')
@with_transaction()
- @patch('trytond.report.report.html2text')
- def test_get_email_html_without_html2text(self, html2text):
- html2text.__bool__.side_effect = lambda: False
+ @patch('trytond.report.report.html_to_text')
+ def test_get_email_html_without_html2text(self, html_to_text):
+ html_to_text.side_effect = lambda content: None
class FakeReport(Report):
@classmethod