thds.core 1.45.20250818180904__py3-none-any.whl → 1.45.20250821162245__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of thds.core might be problematic. Click here for more details.

@@ -0,0 +1,114 @@
1
+ import os
2
+ import re
3
+ import sys
4
+ import threading
5
+ import types
6
+ import typing as ty
7
+
8
+ from thds.core import log
9
+
10
+ logger = log.getLogger(__name__)
11
+
12
+
13
+ def _format_frame(frame: types.FrameType) -> str:
14
+ """Format a stack frame as a single readable line."""
15
+ return f"{frame.f_code.co_filename}:{frame.f_lineno} in {frame.f_code.co_name}"
16
+
17
+
18
+ def _get_thread_stack_frames(thread: threading.Thread) -> list[str]:
19
+ """Get stack frames for a specific thread."""
20
+ frames = list[str]()
21
+
22
+ if thread.ident is None:
23
+ logger.warning('Thread "%s" has no identifier; cannot get stack frames.', thread.name)
24
+ return frames
25
+
26
+ # Get the frame for this thread
27
+ current_frames = sys._current_frames()
28
+ frame = current_frames.get(thread.ident)
29
+
30
+ if frame is None:
31
+ logger.warning("unable to get stack frames for thread %s (id: %s)")
32
+ return frames
33
+
34
+ # Get the path of this debug module
35
+ debug_module_path = os.path.abspath(__file__)
36
+
37
+ # Walk the stack
38
+ while frame:
39
+ if not (debug_module_path and os.path.abspath(frame.f_code.co_filename) == debug_module_path):
40
+
41
+ frames.append(_format_frame(frame))
42
+ frame = frame.f_back
43
+ return frames
44
+
45
+
46
+ def _get_thread_info(thread: threading.Thread) -> dict[str, ty.Any]:
47
+ """Extract thread information including stack trace."""
48
+ stack_frames = _get_thread_stack_frames(thread)
49
+ return {
50
+ "thread_id": thread.ident,
51
+ "thread_name": thread.name,
52
+ "stack_frames": stack_frames,
53
+ }
54
+
55
+
56
+ def _is_thread_pool_thread(thread: threading.Thread) -> bool:
57
+ """Check if thread appears to belong to a ThreadPoolExecutor."""
58
+ tpe_patterns = [
59
+ r"ThreadPoolExecutor-\d+_\d+", # Default naming
60
+ r".*-\d+_\d+", # Custom prefix with TPE suffix pattern
61
+ ]
62
+
63
+ for pattern in tpe_patterns:
64
+ if re.match(pattern, thread.name):
65
+ return True
66
+
67
+ return False
68
+
69
+
70
+ def _find_potential_parent_threads() -> list[dict[str, ty.Any]]:
71
+ """Find threads that could be parents of the current thread pool thread."""
72
+ potential_parents = []
73
+ current_thread = threading.current_thread()
74
+
75
+ for thread in threading.enumerate():
76
+ # Skip self
77
+ if thread == current_thread:
78
+ continue
79
+
80
+ # Skip daemon threads
81
+ if thread.daemon:
82
+ continue
83
+
84
+ # Skip other thread pool threads
85
+ if _is_thread_pool_thread(thread):
86
+ continue
87
+
88
+ thread_info = _get_thread_info(thread)
89
+ potential_parents.append(thread_info)
90
+
91
+ return potential_parents
92
+
93
+
94
+ def capture_thread_context() -> dict[str, ty.Any]:
95
+ """
96
+ Capture stack trace for current thread and potential parent threads.
97
+
98
+ Returns:
99
+ Dict with 'current_thread' info and 'potential_parents' list.
100
+ """
101
+ current_thread = threading.current_thread()
102
+
103
+ # Always capture current thread info
104
+ current_info = _get_thread_info(current_thread)
105
+
106
+ # Only look for parents if we think we're in a thread pool
107
+ potential_parents = []
108
+ if _is_thread_pool_thread(current_thread):
109
+ potential_parents = _find_potential_parent_threads()
110
+
111
+ return {
112
+ "current_thread": current_info,
113
+ "potential_parents": potential_parents,
114
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thds.core
3
- Version: 1.45.20250818180904
3
+ Version: 1.45.20250821162245
4
4
  Summary: Core utilities.
5
5
  Author-email: Trilliant Health <info@trillianthealth.com>
6
6
  License: MIT
@@ -41,6 +41,7 @@ thds/core/scaling.py,sha256=f7CtdgK0sN6nroTq5hLAkG8xwbWhbCZUULstSKjoxO0,1615
41
41
  thds/core/scope.py,sha256=9RWWCFRqsgjTyH6rzRm_WnO69N_sEBRaykarc2PAnBY,10834
42
42
  thds/core/source_serde.py,sha256=X4c7LiT3VidejqtTel9YB6dWGB3x-ct39KF9E50Nbx4,139
43
43
  thds/core/stack_context.py,sha256=17lPOuYWclUpZ-VXRkPgI4WbiMzq7_ZY6Kj1QK_1oNo,1332
44
+ thds/core/thread_debug.py,sha256=ox0XmZQxkwoeIVyM6-BV4PNic5VbucJF3GhjkmaP5UQ,3240
44
45
  thds/core/thunks.py,sha256=p1OvMBJ4VGMsD8BVA7zwPeAp0L3y_nxVozBF2E78t3M,1053
45
46
  thds/core/timer.py,sha256=aOpNP-wHKaKs6ONK5fOtIOgx00FChVZquG4PeaEYH_k,5376
46
47
  thds/core/tmp.py,sha256=jA8FwDbXo3hx8o4kRjAlkwpcI77X86GY4Sktkps29ho,3166
@@ -73,8 +74,8 @@ thds/core/sqlite/structured.py,sha256=SvZ67KcVcVdmpR52JSd52vMTW2ALUXmlHEeD-VrzWV
73
74
  thds/core/sqlite/types.py,sha256=oUkfoKRYNGDPZRk29s09rc9ha3SCk2SKr_K6WKebBFs,1308
74
75
  thds/core/sqlite/upsert.py,sha256=BmKK6fsGVedt43iY-Lp7dnAu8aJ1e9CYlPVEQR2pMj4,5827
75
76
  thds/core/sqlite/write.py,sha256=z0219vDkQDCnsV0WLvsj94keItr7H4j7Y_evbcoBrWU,3458
76
- thds_core-1.45.20250818180904.dist-info/METADATA,sha256=ZpphogKhoUCtgZWuIDmHCyoejG7qNHOfiRRw4_8yurE,2216
77
- thds_core-1.45.20250818180904.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
78
- thds_core-1.45.20250818180904.dist-info/entry_points.txt,sha256=bOCOVhKZv7azF3FvaWX6uxE6yrjK6FcjqhtxXvLiFY8,161
79
- thds_core-1.45.20250818180904.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
80
- thds_core-1.45.20250818180904.dist-info/RECORD,,
77
+ thds_core-1.45.20250821162245.dist-info/METADATA,sha256=VsnlsTYqIWz8IhH0Ol1fV6SNMna2E-u7chdnqJ9WOeI,2216
78
+ thds_core-1.45.20250821162245.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
79
+ thds_core-1.45.20250821162245.dist-info/entry_points.txt,sha256=bOCOVhKZv7azF3FvaWX6uxE6yrjK6FcjqhtxXvLiFY8,161
80
+ thds_core-1.45.20250821162245.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
81
+ thds_core-1.45.20250821162245.dist-info/RECORD,,