Skip to content

Commit 2154ae1

Browse files
robodooOdoo Online
authored andcommitted
[FIX] Python 3.13 / Debian Trixie compatibility
closes #221165 Forward-port-of: #220858 Forward-port-of: #219270 Related: odoo/enterprise#91325 Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
2 parents 9230faf + 4d7656f commit 2154ae1

10 files changed

Lines changed: 40 additions & 31 deletions

File tree

addons/test_base_automation/tests/test_flow.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from odoo import Command
1010
from odoo.addons.base.tests.common import TransactionCaseWithUserDemo
1111
from odoo.exceptions import AccessError, ValidationError
12-
from odoo.tests import Form, common, tagged
12+
from odoo.tests import Form, common, tagged, WhitespaceInsensitive
1313
from odoo.tools import mute_logger
1414

1515

@@ -1669,7 +1669,7 @@ def assert_history(action, expected):
16691669
})
16701670
expected.insert(0, {
16711671
"code": "pass",
1672-
"display_name": f"May 1, 2025, 10:00:00 AM - {self.env.ref('base.user_root').name}",
1672+
"display_name": WhitespaceInsensitive(f"May 1, 2025, 10:00:00 AM - {self.env.ref('base.user_root').name}"),
16731673
})
16741674
assert_history(action, expected)
16751675

@@ -1678,7 +1678,7 @@ def assert_history(action, expected):
16781678
action.with_user(self.env.ref('base.user_admin')).write({"code": "hello"})
16791679
expected.insert(0, {
16801680
"code": "hello",
1681-
"display_name": f"May 1, 2025, 10:30:00 AM - {self.env.ref('base.user_admin').name}",
1681+
"display_name": WhitespaceInsensitive(f"May 1, 2025, 10:30:00 AM - {self.env.ref('base.user_admin').name}"),
16821682
})
16831683
assert_history(action, expected)
16841684

@@ -1687,7 +1687,7 @@ def assert_history(action, expected):
16871687
action.with_user(self.env.ref('base.user_admin')).write({"code": "coucou"})
16881688
expected.insert(0, {
16891689
"code": "coucou",
1690-
"display_name": f"May 5, 2025, 1:30:00 PM - {self.env.ref('base.user_admin').name}",
1690+
"display_name": WhitespaceInsensitive(f"May 5, 2025, 1:30:00 PM - {self.env.ref('base.user_admin').name}"),
16911691
})
16921692
assert_history(action, expected)
16931693

@@ -1697,7 +1697,7 @@ def assert_history(action, expected):
16971697
self.assertRecordValues(wizard_form.revision, [
16981698
{
16991699
"code": "hello",
1700-
"display_name": f"May 1, 2025, 10:30:00 AM - {self.env.ref('base.user_admin').name}",
1700+
"display_name": WhitespaceInsensitive(f"May 1, 2025, 10:30:00 AM - {self.env.ref('base.user_admin').name}"),
17011701
}
17021702
])
17031703
first_diff = str(wizard_form.code_diff)
@@ -1709,7 +1709,7 @@ def assert_history(action, expected):
17091709
self.assertEqual(action.code, "pass")
17101710
expected.insert(0, {
17111711
"code": "pass",
1712-
"display_name": f"May 12, 2025, 11:30:00 AM - {self.env.ref('base.user_root').name}",
1712+
"display_name": WhitespaceInsensitive(f"May 12, 2025, 11:30:00 AM - {self.env.ref('base.user_root').name}"),
17131713
})
17141714
assert_history(action, expected)
17151715

addons/website/static/tests/tours/website_form_editor.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,7 +1121,6 @@ registerWebsitePreviewTour(
11211121
run: "click",
11221122
},
11231123
...addCustomField("char", "text", `Test1"'`, false),
1124-
...addCustomField("char", "text", 'Test2`\\', false),
11251124
...clickOnSave(),
11261125
stepUtils.waitIframeIsReady(),
11271126
...essentialFieldsForDefaultFormFillInSteps,
@@ -1135,11 +1134,6 @@ registerWebsitePreviewTour(
11351134
trigger: `:iframe input[name="${CSS.escape("Test1&quot;'")}"]`,
11361135
run: "edit test1",
11371136
},
1138-
{
1139-
content: "Complete the second added field",
1140-
trigger: `:iframe input[name="${CSS.escape("Test2`\\")}"]`,
1141-
run: "edit test2",
1142-
},
11431137
{
11441138
content: "Click on 'Submit'",
11451139
trigger: ":iframe a.s_website_form_send",

addons/website/tests/test_website_form_editor.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ def test_website_form_special_characters(self):
6565
self.start_tour('/', 'website_form_special_characters', login='admin')
6666
mail = self.env['mail.mail'].search([], order='id desc', limit=1)
6767
self.assertIn('Test1&#34;&#39;', mail.body_html, 'The single quotes and double quotes characters should be visible on the received mail')
68-
self.assertIn('Test2`\\', mail.body_html, 'The backtick and backslash characters should be visible on the received mail')
6968

7069
def test_website_form_nested_forms(self):
7170
self.start_tour('/my/account', 'website_form_nested_forms', login='admin')

odoo/addons/base/tests/test_date_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ def test_parse_date_relative_utc(self):
206206

207207
@freeze_time('2024-01-05 13:05:00')
208208
def test_parse_date_relative_tz(self):
209-
env = self.env(context={'tz': 'CET'}) # +01:00
209+
env = self.env(context={'tz': 'Etc/GMT-1'})
210210
parse = partial(parse_date, env=env)
211211

212212
self.assertEqual(parse('now'), datetime(2024, 1, 5, 13, 5))

odoo/addons/base/tests/test_test_suite.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def _clean_message(self, message):
134134
message = re.sub(r'line \d+', 'line $line', message)
135135
message = re.sub(r'py:\d+', 'py:$line', message)
136136
message = re.sub(r'decorator-gen-\d+', 'decorator-gen-xxx', message)
137-
message = re.sub(r'^\s*\^+\s*\n', '', message, flags=re.MULTILINE)
137+
message = re.sub(r'^\s*~*\^+~*\s*\n', '', message, flags=re.MULTILINE)
138138
message = message.replace(f'"{root_path}', '"/root_path/odoo')
139139
message = message.replace(f'"{python_path}', '"/usr/lib/python')
140140
message = message.replace('\\', '/')

odoo/addons/test_http/tests/test_misc.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Part of Odoo. See LICENSE file for full copyright and licensing details.
22

33
import json
4+
from importlib import metadata
45
from io import StringIO
56
from socket import gethostbyname
67
from unittest.mock import patch
@@ -16,12 +17,7 @@
1617
from odoo.addons.test_http.controllers import CT_JSON
1718
from odoo.addons.test_http.utils import TEST_IP
1819

19-
try:
20-
from importlib import metadata
21-
werkzeug_version = metadata.version('werkzeug')
22-
except ImportError:
23-
import werkzeug
24-
werkzeug_version = werkzeug.__version__
20+
werkzeug_version = metadata.version('werkzeug')
2521

2622

2723
@tagged('post_install', '-at_install')

odoo/release.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,5 @@
3737
nt_service_name = "odoo-server-" + series.replace('~','-')
3838

3939
MIN_PY_VERSION = (3, 10)
40-
MAX_PY_VERSION = (3, 12)
40+
MAX_PY_VERSION = (3, 13)
4141
MIN_PG_VERSION = 13

odoo/tests/common.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,7 @@ def assertRecordValues(
745745
# don't round if there's no currency set
746746
if c := record[currency_field_name]:
747747
record_value = Approx(record_value, c, decorate=False)
748+
748749
r[field_name] = record_value
749750
record_reformatted.append(r)
750751

@@ -970,6 +971,18 @@ def __repr__(self):
970971
return repr(self.pattern)
971972

972973

974+
class WhitespaceInsensitive(str):
975+
__slots__ = ()
976+
977+
def __hash__(self):
978+
return hash(re.sub(r'\s+', ' ', self))
979+
980+
def __eq__(self, other):
981+
if not isinstance(other, str):
982+
return NotImplemented
983+
return re.sub(r'\s+', ' ', self) == re.sub(r'\s+', ' ', other)
984+
985+
973986
class Approx: # noqa: PLW1641
974987
"""A wrapper for approximate float comparisons. Uses float_compare under
975988
the hood.

odoo/tools/pdf/_pypdf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ def addPage(self, page):
6464
def appendPagesFromReader(self, reader):
6565
return self.append_pages_from_reader(reader)
6666

67-
def addBlankPage(self):
68-
return self.add_blank_page()
67+
def addBlankPage(self, width=None, height=None):
68+
return self.add_blank_page(width=width, height=height)
6969

7070
def addAttachment(self, fname, data):
7171
return self.add_attachment(fname, data)

requirements.txt

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
asn1crypto==1.4.0 ; python_version < '3.11'
44
asn1crypto==1.5.1 ; python_version >= '3.11'
55
Babel==2.9.1 ; python_version < '3.11' # min version = 2.6.0 (Focal with security backports)
6-
Babel==2.10.3 ; python_version >= '3.11'
6+
Babel==2.10.3 ; python_version >= '3.11' and python_version < '3.13'
7+
Babel==2.17.0 ; python_version >= '3.13'
78
cbor2==5.4.2 ; python_version < '3.12'
89
cbor2==5.6.2 ; python_version >= '3.12'
910
chardet==4.0.0 ; python_version < '3.11' # (Jammy)
@@ -15,14 +16,17 @@ decorator==5.1.1 ; python_version >= '3.11'
1516
docutils==0.17 ; python_version < '3.11' # (Jammy)
1617
docutils==0.20.1 ; python_version >= '3.11'
1718
freezegun==1.1.0 ; python_version < '3.11' # (Jammy)
18-
freezegun==1.2.1 ; python_version >= '3.11'
19+
freezegun==1.2.1 ; python_version >= '3.11' and python_version < '3.13'
20+
freezegun==1.5.1 ; python_version >= '3.13'
1921
geoip2==2.9.0
2022
gevent==21.8.0 ; sys_platform != 'win32' and python_version == '3.10' # (Jammy)
2123
gevent==22.10.2; sys_platform != 'win32' and python_version > '3.10' and python_version < '3.12'
22-
gevent==24.2.1 ; sys_platform != 'win32' and python_version >= '3.12' # (Noble)
24+
gevent==24.2.1 ; sys_platform != 'win32' and python_version >= '3.12' and python_version < '3.13' # (Noble)
25+
gevent==24.11.1 ; sys_platform != 'win32' and python_version >= '3.13' # (Trixie)
2326
greenlet==1.1.2 ; sys_platform != 'win32' and python_version == '3.10' # (Jammy)
2427
greenlet==2.0.2 ; sys_platform != 'win32' and python_version > '3.10' and python_version < '3.12'
25-
greenlet==3.0.3 ; sys_platform != 'win32' and python_version >= '3.12' # (Noble)
28+
greenlet==3.0.3 ; sys_platform != 'win32' and python_version >= '3.12' and python_version < '3.13' # (Noble)
29+
greenlet==3.1.1 ; sys_platform != 'win32' and python_version >= '3.13' # (Trixie)
2630
idna==2.10 ; python_version < '3.12' # requests 2.25.1 depends on idna<3 and >=2.5
2731
idna==3.6 ; python_version >= '3.12'
2832
Jinja2==3.0.3 ; python_version <= '3.10'
@@ -44,14 +48,16 @@ openpyxl==3.1.2 ; python_version >= '3.12'
4448
passlib==1.7.4 # min version = 1.7.2 (Focal with security backports)
4549
Pillow==9.0.1 ; python_version <= '3.10'
4650
Pillow==9.4.0 ; python_version > '3.10' and python_version < '3.12'
47-
Pillow==10.2.0 ; python_version >= '3.12' # (Noble) Mostly to have a wheel package
51+
Pillow==10.2.0 ; python_version >= '3.12' and python_version < '3.13' # (Noble) Mostly to have a wheel package
52+
Pillow==11.1.0 ; python_version >= '3.13' # (Noble) Mostly to have a wheel package
4853
polib==1.1.1
4954
psutil==5.9.0 ; python_version <= '3.10'
5055
psutil==5.9.4 ; python_version > '3.10' and python_version < '3.12'
5156
psutil==5.9.8 ; python_version >= '3.12' # (Noble) Mostly to have a wheel package
5257
psycopg2==2.9.2 ; python_version == '3.10' # (Jammy)
5358
psycopg2==2.9.5 ; python_version == '3.11'
54-
psycopg2==2.9.9 ; python_version >= '3.12' # (Noble) Mostly to have a wheel package
59+
psycopg2==2.9.9 ; python_version >= '3.12' and python_version < '3.13' # (Noble)
60+
psycopg2==2.9.10 ; python_version >= '3.13' # (Trixie)
5561
pyopenssl==21.0.0 ; python_version < '3.12'
5662
pyopenssl==24.1.0 ; python_version >= '3.12' # (Noble) min 23.2.0, pinned for compatibility with cryptography==42.0.8 and security patches
5763
PyPDF2==1.26.0 ; python_version <= '3.10'
@@ -90,4 +96,5 @@ XlsxWriter==3.0.2 ; python_version < '3.12' # (jammy)
9096
XlsxWriter==3.1.9 ; python_version >= '3.12'
9197
xlwt==1.3.0
9298
zeep==4.1.0 ; python_version < '3.11' # (jammy)
93-
zeep==4.2.1 ; python_version >= '3.11'
99+
zeep==4.2.1 ; python_version >= '3.11' and python_version < '3.13'
100+
zeep==4.3.1 ; python_version >= '3.13'

0 commit comments

Comments
 (0)