]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-147991: Speed up tomllib import time (GH-147992)
authorVictor Stinner <vstinner@python.org>
Thu, 30 Apr 2026 16:25:32 +0000 (18:25 +0200)
committerGitHub <noreply@github.com>
Thu, 30 Apr 2026 16:25:32 +0000 (18:25 +0200)
- Use lazy import for regular expressions.
- Use frozendict for string escapes

Co-authored-by: Taneli Hukkinen <hukkinen@eurecom.fr>
Co-authored-by: Petr Viktorin <encukou@gmail.com>
Lib/test/test_tomllib/test_misc.py
Lib/tomllib/_parser.py
Misc/NEWS.d/next/Library/2026-04-02-05-06-34.gh-issue-147991.2ANtR5.rst [new file with mode: 0644]

index 118fde24d88521f101602fd884de306459f913a4..abd0842d10b254f7197a89c798a1b84470125c07 100644 (file)
@@ -9,8 +9,10 @@ import importlib
 from pathlib import Path
 import sys
 import tempfile
+import textwrap
 import unittest
 from test import support
+from test.support.script_helper import assert_python_ok
 
 from . import tomllib
 
@@ -124,3 +126,20 @@ class TestMiscellaneous(unittest.TestCase):
         never imported by tests.
         """
         importlib.import_module(f"{tomllib.__name__}._types")
+
+    def test_lazy_import(self):
+        # Test the TOML file can be parsed without importing regular
+        # expressions (tomllib._re)
+        code = textwrap.dedent("""
+            import sys, tomllib, textwrap
+            document = textwrap.dedent('''
+                [metadata]
+                key = "text"
+                array = ["array", "of", "text"]
+                booleans = [true, false]
+            ''')
+            tomllib.loads(document)
+            print("lazy import?", 'tomllib._re' not in sys.modules)
+        """)
+        proc = assert_python_ok("-c", code)
+        self.assertIn(b"lazy import? True", proc.out)
index b59d0f7d54bdc3b60b1e82134845c20f29ff2d7c..8aa01301dcea321f058787952ef5035214cef03a 100644 (file)
@@ -4,7 +4,11 @@
 
 from __future__ import annotations
 
-from types import MappingProxyType
+# Defer loading regular expressions until we actually need them in
+# parse_value().
+__lazy_modules__ = ["tomllib._re"]
+
+import sys
 
 from ._re import (
     RE_DATETIME,
@@ -15,6 +19,9 @@ from ._re import (
     match_to_number,
 )
 
+if sys.version_info < (3, 15):
+    from types import MappingProxyType as frozendict
+
 TYPE_CHECKING = False
 if TYPE_CHECKING:
     from collections.abc import Iterable
@@ -42,7 +49,7 @@ BARE_KEY_CHARS: Final = frozenset(
 KEY_INITIAL_CHARS: Final = BARE_KEY_CHARS | frozenset("\"'")
 HEXDIGIT_CHARS: Final = frozenset("abcdef" "ABCDEF" "0123456789")
 
-BASIC_STR_ESCAPE_REPLACEMENTS: Final = MappingProxyType(
+BASIC_STR_ESCAPE_REPLACEMENTS: Final = frozendict(
     {
         "\\b": "\u0008",  # backspace
         "\\t": "\u0009",  # tab
diff --git a/Misc/NEWS.d/next/Library/2026-04-02-05-06-34.gh-issue-147991.2ANtR5.rst b/Misc/NEWS.d/next/Library/2026-04-02-05-06-34.gh-issue-147991.2ANtR5.rst
new file mode 100644 (file)
index 0000000..581c529
--- /dev/null
@@ -0,0 +1,2 @@
+Improve :mod:`tomllib` import time (up to 10x faster). Patch by Victor
+Stinner.