Skip to content

Commit 313b747

Browse files
committed
feat(testing): add detect_module_runtime_mode to detect stitched/zipapp builds
Add new detect_module_runtime_mode() function that reliably detects whether a module is from a stitched build, zipapp, or regular package. Prioritizes marker- based detection (__STITCHED__, __STANDALONE__) but falls back to path heuristics. This fixes patch_everywhere() which was corrupting stitched module test isolation by patching shared __globals__ dicts. Now patch_everywhere() uses the new detector to skip __globals__ patching for stitched and zipapp modules, which use module- level setattr instead. Changes: - Add detect_module_runtime_mode(mod, *, stitch_hints=None) function - Make stitch_hints keyword-only parameter - Pass stitch_hints to detector in both patch_everywhere call sites - Remove duplicate fallback logic from patch_everywhere (now in detector) - Export detect_module_runtime_mode in __init__.py - Add tests for detector and patch_everywhere isolation behavior - Update API documentation with detect_module_runtime_mode
1 parent b0cc90d commit 313b747

File tree

6 files changed

+434
-106
lines changed

6 files changed

+434
-106
lines changed

docs/api.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Complete API documentation for Apathetic Python Utils.
2222
| **Text Processing** | [`plural()`](#plural), [`remove_path_in_error_message()`](#remove_path_in_error_message) |
2323
| **Type Utilities** | [`safe_isinstance()`](#safe_isinstance), [`literal_to_set()`](#literal_to_set), [`cast_hint()`](#cast_hint), [`schema_from_typeddict()`](#schema_from_typeddict) |
2424
| **Version Utilities** | [`create_version_info()`](#create_version_info) |
25-
| **Testing Utilities** | [`create_mock_superclass_test()`](#create_mock_superclass_test), [`patch_everywhere()`](#patch_everywhere) |
25+
| **Testing Utilities** | [`detect_module_runtime_mode()`](#detect_module_runtime_mode), [`create_mock_superclass_test()`](#create_mock_superclass_test), [`patch_everywhere()`](#patch_everywhere) |
2626
| **Constants** | [`CI_ENV_VARS`](#ci_env_vars) |
2727

2828
## File Loading
@@ -1177,6 +1177,54 @@ assert version >= (3, 10)
11771177

11781178
## Testing Utilities
11791179

1180+
### detect_module_runtime_mode
1181+
1182+
```python
1183+
detect_module_runtime_mode(
1184+
mod: ModuleType,
1185+
*,
1186+
stitch_hints: set[str] | None = None
1187+
) -> str
1188+
```
1189+
1190+
Detect the runtime mode of a specific module.
1191+
1192+
Determines whether a module was built as part of a stitched single-file script, zipapp archive, or standard package by checking for markers and file path attributes.
1193+
1194+
This check prioritizes marker-based detection (`__STITCHED__` and `__STANDALONE__` attributes) as the most reliable method, but falls back to path heuristics when markers are not present.
1195+
1196+
**Parameters:**
1197+
1198+
| Parameter | Type | Description |
1199+
|-----------|------|-------------|
1200+
| `mod` | `ModuleType` | Module to check |
1201+
| `stitch_hints` | `set[str] \| None` | Set of path hints to identify stitched modules. Defaults to `{"/dist/", "stitched"}`. Used as fallback when markers are not present. |
1202+
1203+
**Returns:**
1204+
- `str`: One of:
1205+
- `"stitched"` if module has `__STITCHED__` or `__STANDALONE__` marker, or if `__file__` path matches stitch_hints
1206+
- `"zipapp"` if module `__file__` indicates zipapp (contains `.pyz`)
1207+
- `"package"` for regular package modules
1208+
1209+
**Raises:**
1210+
- `TypeError`: If mod is not a ModuleType
1211+
1212+
**Example:**
1213+
```python
1214+
from apathetic_utils import detect_module_runtime_mode
1215+
import apathetic_utils
1216+
1217+
# Detect module runtime mode
1218+
mode = detect_module_runtime_mode(apathetic_utils)
1219+
print(f"apathetic_utils is running in {mode} mode")
1220+
1221+
# With custom stitch hints
1222+
mode = detect_module_runtime_mode(
1223+
apathetic_utils,
1224+
stitch_hints={"/dist/", "bundled", "embedded"}
1225+
)
1226+
```
1227+
11801228
### create_mock_superclass_test
11811229

11821230
```python

0 commit comments

Comments
 (0)