You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix tintype PYTHON_API.md to match the actual library API
Summary:
Audited tintype/PYTHON_API.md against the C++ binding (_snapshot.cpp), the type stub (_snapshot.pyi), the Python wrappers, and SnapshotCapture.cpp, then corrected the inaccuracies:
- Removed the incorrect "stacktrace ID 0" model. Thread/traceback captures key the stacktrace by the native thread identifier (not 0), and the exception-chain path creates no separate thread stacktrace (only sequential IDs starting from 1). Fixed the take_snapshot parameter docs and the Snapshot.stacktraces attribute description.
- Corrected the enable_sampling Raises note: it raises RuntimeError under free-threaded (no-GIL) Python, not "Python < 3.12" (no such version check exists).
- Documented the previously-missing snapshot_all_threads RuntimeError under free-threaded Python.
- Added the undocumented Snapshot.get_next_snapshot() and SnapshotReader.get_working_file_path() methods.
- Completed the get_stats() key list: snapshot_breakdown.frames_filtered, snapshot_breakdown.snapshots_discarded, object_queue_breakdown.objects_cache_hit, object_queue_breakdown.string_bytes_cache_hit, top-level errors, and top-level file_extension.
- Fixed the broken FILE_FORMAT.md link to point to snapshot_lib/FILE_FORMAT.md.
___
Differential Revision: D108816489
fbshipit-source-id: fc9864f6598c8e554ef7c01a6f9bb05f7564a6c1
-`None`: Capture the current call stack (thread snapshot, stacktrace ID 0).
149
-
-`TracebackType`: Capture the frames from a traceback object (stacktrace ID 0).
150
-
-`BaseException`: Capture the exception's traceback and the full `__cause__`/`__context__` chain. The thread stacktrace gets ID 0; exception stacktraces get sequential IDs starting from 1.
148
+
-`None`: Capture the current call stack as a single stacktrace keyed by the native thread identifier (same as `threading.get_ident()`).
149
+
-`TracebackType`: Capture the frames from a traceback object as a single stacktrace keyed by the native thread identifier.
150
+
-`BaseException`: Capture the exception's traceback and the full `__cause__`/`__context__` chain. No separate thread stacktrace is captured; the exception stacktraces get sequential IDs starting from 1.
151
151
-`max_frames` (`int | None`, default `None`): Maximum number of frames to capture per stacktrace. `None` means no limit. When the limit is reached, the stacktrace is marked as truncated.
152
152
-`max_object_depth` (`int | None`, default `None`): Maximum depth of object graph traversal. Depth 0 is the frame's local variables. When the limit is reached, non-primitive objects are serialized as their `repr()` string with no children. `None` means no limit. When triggered, the `object_depth_truncated` flag is set on the `Stacktrace` object (the `truncated` flag is NOT affected — it only reflects frame omission).
153
153
-`timeout` (`float | None`, default `None`): Maximum time in seconds for the entire snapshot operation. `None` means no timeout. If the timeout is reached, processing stops and any in-progress frame is discarded. Completed frames are preserved.
@@ -185,10 +185,12 @@ Get timing and performance statistics. Only populated if `initialize(collect_sta
185
185
-`total_objects`: Total number of objects serialized to the heap
@@ -211,6 +213,8 @@ Capture all Python threads' call stacks in a single snapshot record. Uses `sys._
211
213
212
214
Auto-initializes with `collect_stats=False` if not already initialized.
213
215
216
+
**Raises:**`RuntimeError` if running under free-threaded (no-GIL) Python, where capturing other threads' frames can deadlock. Use `take_snapshot()` to capture the current thread instead.
217
+
214
218
**Reentrancy:** While `snapshot_all_threads()` is running, concurrent calls to `take_snapshot()`, `take_snapshot(exception)`, and `snapshot_all_threads()` return `None` immediately. The reverse also holds — `snapshot_all_threads()` returns `None` if `take_snapshot()` is in progress.
215
219
216
220
**Stacktrace IDs:** Each stacktrace's `id` is the native thread identifier (same as `threading.get_ident()`), not the sequential IDs used by exception chain snapshots. Thread stacktraces have `exception_object = None`.
@@ -251,7 +255,7 @@ Start periodic sampling. Spawns a C++ timer thread that periodically takes snaps
251
255
-`max_object_depth` (`int | None`, default `None`): Maximum depth of object graph traversal. `None` means no limit.
252
256
-`timeout` (`float`, default `1.0`): Timeout per sample in seconds. In `ALL_THREADS` mode, this is passed to `snapshot_all_threads()`.
253
257
254
-
**Raises:**`RuntimeError` if sampling is already active or if Python < 3.12.
258
+
**Raises:**`RuntimeError` if sampling is already active, or if running under free-threaded (no-GIL) Python, where sampling is unsupported because capturing other threads' frames can deadlock.
255
259
256
260
The sampling timer thread is invisible to `snapshot_all_threads()` — it has no Python frames and does not appear in snapshots.
257
261
@@ -350,6 +354,7 @@ Open a snapshot file for reading. The file may be zstd-compressed or uncompresse
350
354
|`get_stats()`|`dict[str, int]`| Get statistics. Returns live stats for borrowed readers, file stats for file-based readers. |
351
355
|`get_all_source_files()`|`list[SourceFile]`| Get all embedded source files. |
352
356
|`get_extracted_files_dir()`|`str`| Path to temp directory with extracted source files. |
357
+
|`get_working_file_path()`|`str \| None`| Path to the file mmapped by this reader: the temporary decompressed file for file-based readers, or the writer's backing file for borrowed-memory readers. `None` if unavailable. |
353
358
|`get_last_error()`|`str`| Last error message. Empty if no error. |
354
359
|`_read_raw_object(offset)`|`dict \| bool \| None`| Read a raw object from the heap by offset. Internal use only. |
355
360
|`get_python_object(python_id, object_map)`|`Any`| Resolve a Python object ID to a Python object. |
@@ -371,7 +376,7 @@ Represents a single snapshot record. Contains one or more stacktraces and an obj
371
376
|-----------|------|-------------|
372
377
|`timestamp`|`int`| Unix timestamp in microseconds when the snapshot was taken. |
373
378
|`truncated`|`bool`|`True` if this snapshot was truncated due to cancellation, `max_frames`, or timeout. |
374
-
|`stacktraces`|`dict[int, Stacktrace]`| Map from stacktrace ID to `Stacktrace`. ID 0 is the thread/traceback snapshot; IDs 1+ are exception chain entries. |
379
+
|`stacktraces`|`dict[int, Stacktrace]`| Map from stacktrace ID to `Stacktrace`. For thread/traceback snapshots the key is the native thread identifier; for exception snapshots the keys are sequential IDs starting from 1. |
375
380
|`object_map`|`dict[int, int]`| Map from Python object ID to heap offset, used to resolve variable references. |
376
381
377
382
#### Methods
@@ -380,6 +385,7 @@ Represents a single snapshot record. Contains one or more stacktraces and an obj
380
385
|--------|-------------|-------------|
381
386
|`frames()`|`list[Frame]`| Convenience accessor: frames from the first stacktrace. |
382
387
|`get_prev_snapshot()`|`Snapshot \| None`| Get the previous snapshot in the linked list, or `None` if this is the first snapshot. Caches the result. |
388
+
|`get_next_snapshot()`|`Snapshot \| None`| Get the next (chronologically newer) snapshot, or `None` if this is the most recent snapshot. Caches the result. For borrowed (live) readers, a `None` result is not cached, since newer snapshots may still be appended. |
383
389
|`get_python_object(python_id)`|`Any`| Resolve a Python object ID using this snapshot's object map and reader. |
384
390
385
391
### `Stacktrace`
@@ -545,4 +551,4 @@ with sampling(interval, path=path):
545
551
546
552
## Related Documentation
547
553
548
-
-[FILE_FORMAT.md](FILE_FORMAT.md) — Binary file format specification with byte-level struct definitions.
554
+
-[FILE_FORMAT.md](snapshot_lib/FILE_FORMAT.md) — Binary file format specification with byte-level struct definitions.
0 commit comments