Skip to content

Commit b0e700d

Browse files
committed
Fix circular import between threading and _threading_local
Since Python 3.7 thread support is always available, _thread._local always exists. The fallback 'try: from _thread import _local except ImportError: from _threading_local import local' is obsolete and reintroduces a circular import when _thread._local is deleted (e.g. del _thread._local; import threading). - In Lib/threading.py, remove the try/except fallback and directly use 'from _thread import _local as local'. - In Lib/_threading_local.py, remove the top-level 'from threading import current_thread, RLock' and use lazy imports inside get_dict(), create_dict(), and local.__new__(). This breaks the cycle and makes 'import _thread; del _thread._local; import threading' succeed, as reported in the issue. Fixes #156341 Co-authored-by: Muse Spark <muse-spark@users.noreply.github.com> Co-authored-by: Aryan Singh K <70511529+aryansk@users.noreply.github.com> AI disclosure: Muse Spark assisted in analysis and fix drafting; changes reviewed and tested manually (py_compile ok). Signed-off-by: aryansk <70511529+aryansk@users.noreply.github.com>
1 parent a728080 commit b0e700d

2 files changed

Lines changed: 8 additions & 10 deletions

File tree

Lib/_threading_local.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@ def __init__(self):
3636
def get_dict(self):
3737
"""Return the dict for the current thread. Raises KeyError if none
3838
defined."""
39+
from threading import current_thread
3940
thread = current_thread()
4041
return self.dicts[id(thread)][1]
4142

4243
def create_dict(self):
4344
"""Create a new dict for the current thread, and return it."""
45+
from threading import current_thread
4446
localdict = {}
4547
key = self.key
4648
thread = current_thread()
@@ -85,6 +87,7 @@ class local:
8587
def __new__(cls, /, *args, **kw):
8688
if (args or kw) and (cls.__init__ is object.__init__):
8789
raise TypeError("Initialization arguments are not supported")
90+
from threading import RLock
8891
self = object.__new__(cls)
8992
impl = _localimpl()
9093
impl.localargs = (args, kw)
@@ -115,6 +118,3 @@ def __delattr__(self, name):
115118
% self.__class__.__name__)
116119
with _patch(self):
117120
return object.__delattr__(self, name)
118-
119-
120-
from threading import current_thread, RLock

Lib/threading.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,11 @@
6161
TIMEOUT_MAX = _thread.TIMEOUT_MAX
6262
del _thread
6363

64-
# get thread-local implementation, either from the thread
65-
# module, or from the python fallback
66-
67-
try:
68-
from _thread import _local as local
69-
except ImportError:
70-
from _threading_local import local
64+
# get thread-local implementation from the thread module
65+
# (fallback to _threading_local is obsolete since Python 3.7 - thread support
66+
# is always available, and _thread._local always exists; keeping the fallback
67+
# would reintroduce the circular import with _threading_local)
68+
from _thread import _local as local
7169

7270
# Support for profile and trace hooks
7371

0 commit comments

Comments
 (0)