@@ -235,15 +235,15 @@ list[tuple[int, int, int]]]):
235235 self .unit = unit
236236
237237
238- cdef class ThreadState :
238+ cdef class _ThreadState :
239239 """
240240 Helper object for holding the thread-local state; documentations are
241241 for reference only, and all APIs are to be considered private and
242242 subject to change.
243243 """
244244 cdef TraceCallback * callback
245245 cdef public object active_instances # type: set[LineProfiler]
246- cdef public int _wrap_trace
246+ cdef int _wrap_trace
247247
248248 def __init__ (self , instances = (), wrap_trace = False ):
249249 self .active_instances = set (instances)
@@ -382,7 +382,7 @@ cdef class LineProfiler:
382382 cdef public object threaddata
383383
384384 # This is shared between instances and threads
385- _all_thread_states = {} # type: dict[int, ThreadState ]
385+ _all_thread_states = {} # type: dict[int, _ThreadState ]
386386
387387 def __init__ (self , *functions , wrap_trace = None ):
388388 self .functions = []
@@ -469,12 +469,17 @@ cdef class LineProfiler:
469469 self .threaddata.enable_count = value
470470
471471 # These two are shared between instances, but thread-local
472+ # (Ideally speaking they could've been class attributes...)
472473
473474 property wrap_trace :
474475 def __get__ (self ):
475476 return self ._thread_state.wrap_trace
476477 def __set__ (self , wrap_trace ):
477- self ._thread_state.wrap_trace = wrap_trace
478+ # Make sure we have a thread state
479+ state = self ._thread_state
480+ # Sync values between all thread states
481+ for state in self ._all_thread_states.values():
482+ state.wrap_trace = wrap_trace
478483
479484 property _thread_state :
480485 def __get__ (self ):
@@ -483,16 +488,23 @@ cdef class LineProfiler:
483488 return self ._all_thread_states[thread_id]
484489 except KeyError :
485490 pass
486-
487- # First instance, load default `wrap_trace` value from the
488- # environment
489- # (TODO: migrate to `line_profiler.cli_utils.boolean()`
490- # after merging #335)
491- from os import environ
492-
493- env = environ.get(' LINE_PROFILE_WRAP_TRACE' , ' ' ).lower()
494- wrap_trace = env not in {' ' , ' 0' , ' off' , ' false' , ' no' }
495- self ._all_thread_states[thread_id] = state = ThreadState(
491+ # First profiler instance on the thread, get the correct
492+ # `wrap_trace` value and set up a `_ThreadState`
493+ try :
494+ state, * _ = self ._all_thread_states.values()
495+ except ValueError :
496+ # First thread in the interpretor: load default
497+ # `wrap_trace` value from the environment
498+ # (TODO: migrate to `line_profiler.cli_utils.boolean()`
499+ # after merging #335)
500+ from os import environ
501+
502+ env = environ.get(' LINE_PROFILE_WRAP_TRACE' , ' ' ).lower()
503+ wrap_trace = env not in {' ' , ' 0' , ' off' , ' false' , ' no' }
504+ else :
505+ # Fetch the `.wrap_trace` value from an existing state
506+ wrap_trace = state.wrap_trace
507+ self ._all_thread_states[thread_id] = state = _ThreadState(
496508 wrap_trace = wrap_trace)
497509 return state
498510
@@ -633,7 +645,7 @@ cdef extern int python_trace_callback(object state_,
633645 https://github.com/python/cpython/blob/de2a4036/Include/cpython/\
634646pystate.h#L16
635647 """
636- cdef ThreadState state
648+ cdef _ThreadState state
637649 cdef object prof_
638650 cdef LineProfiler prof
639651 cdef LastTime old
@@ -645,7 +657,7 @@ pystate.h#L16
645657 cdef unordered_map[int64, LineTime] line_entries
646658 cdef uint64 linenum
647659
648- state = < ThreadState > state_
660+ state = < _ThreadState > state_
649661
650662 if what == PyTrace_LINE or what == PyTrace_RETURN:
651663 # Normally we'd need to DECREF the return from get_frame_code,
0 commit comments