-
-
Notifications
You must be signed in to change notification settings - Fork 2
Context Pattern Migration
github-actions[bot] edited this page Nov 12, 2025
·
1 revision
This guide expands on ADR-0004 and details the process of migrating existing modules from module-level singletons to the thread-local application context introduced in Importobot v0.1.3. These steps should be followed when upgrading legacy helpers, CLI commands, or integrations that still rely on global state.
- Target Version: Importobot v0.1.3 or later.
- Prerequisite Reading: Review the Application Context Implementation Guide for background information and API references.
-
Local Test Execution: Confirm that your tests can be run locally (e.g., using
make testorpytest). -
Identify Modules: Pinpoint modules that:
- Import
get_*helpers backed by module-level globals. - Mutate shared state (e.g., caches, telemetry clients) without accepting context arguments.
- Spawn worker threads without explicitly calling
clear_context().
- Import
-
Inventory Global Access:
- Search for assignments to
_global_*variables or helpers that cache singletons. - Flag functions that mutate shared objects without accepting a context argument.
- Search for assignments to
-
Adopt Context Accessors:
- Replace direct global usage with
get_context()accessors. - Move lazy instantiation into the context object as needed.
- Replace direct global usage with
-
Implement Thread-Aware Entry Points:
- For worker functions, call
get_context()inside the thread and ensureclear_context()runs within afinallyblock.
- For worker functions, call
-
Expose Optional Context Parameters:
- Public functions should accept
context: ApplicationContext | None = Noneand resolvecontext = context or get_context(). - This makes testing and integration overrides explicit.
- Public functions should accept
-
Update Tests:
- Add the shared
clear_context()fixture (seetests/unit/test_context.py). - When mocking services, set them on the injected context instead of patching module globals.
- Add the shared
-
Remove Deprecated Globals:
- Delete
_global_*caches once all call sites have been migrated to use the context. - Update import paths so consumers retrieve dependencies from
importobot.context.
- Delete
-_performance_cache: PerformanceCache | None = None
-
-def get_performance_cache() -> PerformanceCache:
- global _performance_cache
- if _performance_cache is None:
- _performance_cache = PerformanceCache()
- return _performance_cache
+from importobot.context import ApplicationContext, get_context
+
+def get_performance_cache(
+ context: ApplicationContext | None = None,
+) -> PerformanceCache:
+ """Retrieve the performance cache via the active application context."""
+ context = context or get_context()
+ return context.performance_cachefrom importobot.context import clear_context, get_context
def run_worker(payload: dict[str, str]) -> None:
context = get_context()
try:
cache = context.performance_cache
cache.process(payload)
finally:
clear_context()- Unit tests succeed with the autouse
clear_contextfixture. - Integration tests that start new threads/tasks call
clear_context()in afinallyblock. - Mocked services are attached to the context (e.g.,
context.performance_cache = FakeCache()). - CLI entry points call
clear_context()on exit (seeimportobot.cli.main).
| Symptom | Likely Cause | Fix |
|---|---|---|
AttributeError: 'ApplicationContext' object has no attribute ... |
Service property not defined on ApplicationContext. |
Add a lazily-evaluated property to ApplicationContext. |
| Cache state shared across tests | Missing clear_context() in fixtures. |
Add an autouse fixture to clear the context before/after each test. |
| Thread reuses stale services | Worker thread never clears its context. | Wrap the thread body in a try/finally block with clear_context(). |
- Review
wiki/architecture/Application-Context-Implementation.mdfor deeper API details. - Update team onboarding documentation to reference the context access pattern.
- Remove any lingering test utilities that patch module-level singletons.