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
**#4`FoundryContext` Pydantic model + `from_package()` classmethod**
73
73
74
-
The library owns the derivation logic in `ProjectConfig.from_package(project_name)`, which reads from `importlib.metadata`, `sys.argv`, CI env vars, etc. Projects construct a config and pass it at call sites.
74
+
The library owns the derivation logic in `FoundryContext.from_package(project_name)`, which reads from `importlib.metadata`, `sys.argv`, CI env vars, etc. Projects construct a context and pass it at call sites.
75
75
76
76
```python
77
-
config=ProjectConfig.from_package("bridge")
78
-
locate_subclasses(BaseService, config=config)
77
+
ctx=FoundryContext.from_package("bridge")
78
+
locate_subclasses(BaseService, context=ctx)
79
79
```
80
80
81
81
* Pros: requirements #1 and #2 satisfied; typed; derivation logic lives once in the library
82
-
* Cons: requirement #3 only partially satisfied — projects must hold and thread their own `config` reference to read derived values, which doesn't fully eliminate `_constants.py`
82
+
* Cons: requirement #3 only partially satisfied — projects must hold and thread their own `context` reference to read derived values, which doesn't fully eliminate `_constants.py`
83
83
84
-
**#5`ProjectConfig.from_package()` + `configure()` + `foundry.config` accessor (combination of #3 and #4)**
84
+
**#5`FoundryContext.from_package()` + `configure()` + `foundry.context` accessor (combination of #3 and #4)**
85
85
86
-
Extends #4 with a `configure()` call that stores the config as library-level state, exposed back to callers via `foundry.config`. Library functions fall back to the configured default but accept an explicit `config` override for testing.
86
+
Extends #4 with a `configure()` call that stores the context as library-level state, exposed back to callers via `foundry.context`. Library functions fall back to the configured default but accept an explicit `context` override for testing.
* Pros: all four requirements satisfied; `_constants.py` can be deleted outright; ergonomic for production; testable without resetting global state
107
-
* Cons: global mutable state, though contained — tests pass config explicitly and never need to reset it
107
+
* Cons: global mutable state, though contained — tests pass context explicitly and never need to reset it
108
108
109
109
## Decision
110
110
111
-
I suggest we use **#5**.
111
+
We use **#5**.
112
112
113
-
`ProjectConfig` holds project identity and build metadata. Runtime mode flags (`is_container`, `is_cli`, `is_test`, `is_library`) are only consumed by `sentry_initialize()`, so they live in a nested `SentryContext` rather than on `ProjectConfig` directly:
113
+
### Naming
114
+
115
+
The central type is named `FoundryContext` (not `ProjectConfig` or `ProjectContext`). Rationale:
116
+
117
+
- "Config" was rejected because it implies values loaded from env vars or files; this object is derived at startup from `importlib.metadata`, `sys.argv`, and env vars — it is computed context, not configuration input. The existing `SentrySettings` type already uses the "settings/config" pattern for env-based values.
118
+
- "Project" prefix was considered but doesn't communicate which library owns the type. Since `FoundryContext` is specifically the library's handle on a project, naming it after the library makes the dependency explicit and aids discoverability.
119
+
- The name is consistent with `SentryContext` (also runtime-computed, also nested within the same design).
120
+
121
+
### Structure
122
+
123
+
`FoundryContext` is a frozen Pydantic model, making all instances immutable after construction. Runtime mode flags (`is_container`, `is_cli`, `is_test`, `is_library`) are only consumed by `sentry_initialize()`, so they live in a nested `SentryContext` rather than on `FoundryContext` directly:
`SentryContext` is kept separate from `SentrySettings` (which holds SDK configuration loaded from env vars). `SentryContext` is runtime-computed; `SentrySettings` is env-based.
160
172
173
+
### Extending FoundryContext
174
+
175
+
Projects that need additional context fields beyond the base set can subclass `FoundryContext`. The subclass overrides `from_package()` to compute its extra fields, using `model_dump()` to forward all base fields:
`foundry.context` is typed as `FoundryContext` — sufficient for all library functions. Project code that needs access to the extended fields keeps its own reference to the concrete instance:
# library uses foundry.context (FoundryContext) — no project-specific fields needed
205
+
# project code uses bridge_context directly for its own extended fields
206
+
bridge_context.tenant_id
207
+
```
208
+
209
+
This avoids module-level generics (which are awkward in Python) while keeping both the library and project code fully typed without casts.
210
+
161
211
## Consequences
162
212
163
-
-`_constants.py` is eliminated entirely across all projects; derivation logic lives once in the library and derived values are read back via `foundry.config`.
213
+
-`_constants.py` is eliminated entirely across all projects; derivation logic lives once in the library and derived values are read back via `foundry.context`.
164
214
- New projects (API servers and CLI tools alike) require a single `configure()` call and no boilerplate.
165
-
- Production call sites are clean — no config threading.
166
-
- Tests can pass a `ProjectConfig` directly without touching or resetting global state.
215
+
- Production call sites are clean — no context threading.
216
+
- Tests can pass a `FoundryContext` directly without touching or resetting global state.
167
217
-`SentryContext` nesting makes it clear that the mode flags are Sentry-specific and not general-purpose project metadata.
218
+
- Projects that need additional fields subclass `FoundryContext` and pass their subclass to `configure()`; they hold their own typed reference for project-specific access.
0 commit comments