-
-
Notifications
You must be signed in to change notification settings - Fork 34.4k
gh-109653: Improve import preformance of tkinter library with lazy imports
#148409
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
sharktide
wants to merge
9
commits into
python:main
Choose a base branch
from
sharktide:patch-2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+27
−14
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
f0e2f9b
Lazy import modules in tkinter __init__
sharktide 4bcb491
Add _get_magic_re and _get_space_re functions.
sharktide 995d6a1
Update usage in _stringify
sharktide 44567a4
Add docstring to new functions
sharktide 0dfab78
Format
sharktide ce94f9e
Add NEWS entry
sharktide 01000ea
Move lazy import re down in the file
sharktide 1da6e7b
Reorder imports for clarity
sharktide f0bd1eb
Stop lazy imported modules from appearing in __all__
sharktide File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -29,16 +29,15 @@ | |||
| button.pack(side=BOTTOM) | ||||
| tk.mainloop() | ||||
| """ | ||||
|
|
||||
| import _tkinter # If this fails your Python may not be configured for Tk | ||||
| from tkinter.constants import * | ||||
| import collections | ||||
| import enum | ||||
| import sys | ||||
| import types | ||||
|
|
||||
| import _tkinter # If this fails your Python may not be configured for Tk | ||||
| lazy import sys | ||||
| lazy import types | ||||
| lazy import re | ||||
| TclError = _tkinter.TclError | ||||
| from tkinter.constants import * | ||||
| import re | ||||
|
|
||||
| wantobjects = 1 | ||||
| _debug = False # set to True to print executed Tcl/Tk commands | ||||
|
|
@@ -50,22 +49,33 @@ | |||
| WRITABLE = _tkinter.WRITABLE | ||||
| EXCEPTION = _tkinter.EXCEPTION | ||||
|
|
||||
| _magic_re = None | ||||
| _space_re = None | ||||
|
|
||||
| _magic_re = re.compile(r'([\\{}])') | ||||
| _space_re = re.compile(r'([\s])', re.ASCII) | ||||
| def _get_magic_re(): | ||||
| """Internal function.""" | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this docstring (and below) doesn't add any info. (you can say that this function hides the
Suggested change
|
||||
| global _magic_re | ||||
| if _magic_re is None: | ||||
| _magic_re = re.compile(r'([\\{}])') | ||||
| return _magic_re | ||||
|
|
||||
| def _get_space_re(): | ||||
| """Internal function.""" | ||||
| global _space_re | ||||
| if _space_re is None: | ||||
| _space_re = re.compile(r'([\s])', re.ASCII) | ||||
| return _space_re | ||||
|
|
||||
| def _join(value): | ||||
| """Internal function.""" | ||||
| return ' '.join(map(_stringify, value)) | ||||
|
|
||||
|
|
||||
| def _stringify(value): | ||||
| """Internal function.""" | ||||
| if isinstance(value, (list, tuple)): | ||||
| if len(value) == 1: | ||||
| value = _stringify(value[0]) | ||||
| if _magic_re.search(value): | ||||
| if _get_magic_re().search(value): | ||||
| value = '{%s}' % value | ||||
| else: | ||||
| value = '{%s}' % _join(value) | ||||
|
|
@@ -76,14 +86,14 @@ def _stringify(value): | |||
| value = str(value) | ||||
| if not value: | ||||
| value = '{}' | ||||
| elif _magic_re.search(value): | ||||
| elif _get_magic_re().search(value): | ||||
| # add '\' before special characters and spaces | ||||
| value = _magic_re.sub(r'\\\1', value) | ||||
| value = _get_magic_re().sub(r'\\\1', value) | ||||
| value = value.replace('\n', r'\n') | ||||
| value = _space_re.sub(r'\\\1', value) | ||||
| value = _get_space_re().sub(r'\\\1', value) | ||||
| if value[0] == '"': | ||||
| value = '\\' + value | ||||
| elif value[0] == '"' or _space_re.search(value): | ||||
| elif value[0] == '"' or _get_space_re().search(value): | ||||
| value = '{%s}' % value | ||||
| return value | ||||
|
|
||||
|
|
@@ -5094,6 +5104,7 @@ def _test(): | |||
|
|
||||
| __all__ = [name for name, obj in globals().items() | ||||
| if not name.startswith('_') and not isinstance(obj, types.ModuleType) | ||||
| and not isinstance(obj, types.LazyImportType) | ||||
| and name not in {'wantobjects'}] | ||||
|
|
||||
| if __name__ == '__main__': | ||||
|
|
||||
2 changes: 2 additions & 0 deletions
2
Misc/NEWS.d/next/Library/2026-04-11-18-49-40.gh-issue-109653.VXU-w8.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Reduce the import time of :mod:`tkinter` with lazy imports. Patch by Rihaan | ||
| Meher. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the code, I think both
sysandtypeswill end up being imported always, because of:https://github.com/python/cpython/pull/148409/changes#diff-46c8ee2e6d4e02b7a2839d0cabde53331f5ad74fb09fdd6149b70e9d5cfb2cddR5107
https://github.com/sharktide/cpython/blob/f0bd1ebd7c4c6ac7126d7fc8332e59744427d6fc/Lib/tkinter/__init__.py#L2635
At the same time, there are some inline imports that you can convert to
lazysyntax:tracebackandoshttps://github.com/sharktide/cpython/blob/f0bd1ebd7c4c6ac7126d7fc8332e59744427d6fc/Lib/tkinter/__init__.py#L2622
https://github.com/sharktide/cpython/blob/f0bd1ebd7c4c6ac7126d7fc8332e59744427d6fc/Lib/tkinter/__init__.py#L2539
(though you should checj again whether
oswill end up being imported anyways)