feat(config): add configure_sdk orchestrator for declarative config (#5270)
* recursively convert parsed dicts to typed dataclasses in loader
Adds `_dict_to_dataclass` in `_conversion.py` which walks each field's
type annotation and converts:
- nested dicts → typed dataclass instances
- lists of dicts → lists of typed dataclasses
- string/value → Enum members (e.g. log_level: info)
- unknown keys → routed to the @_additional_properties decorator
The loader's `_dict_to_model` now produces a fully-typed
OpenTelemetryConfiguration tree end-to-end. Factory functions can rely
on typed attribute access (config.tracer_provider.processors[0].batch
.exporter.otlp_http.endpoint) instead of failing on raw dicts.
This closes the gap between load_config_file() and the factory
functions — YAML/JSON config → SDK objects now works end-to-end.
Closes #5127
Assisted-by: Claude Opus 4.6
* rename changelog fragment to PR #5269
* tighten typing on conversion module
- Use TypeVar for _dict_to_dataclass return — callers now get the
correct type instead of Any
- Use collections.abc.Mapping for input (more permissive than dict)
- Add explicit is_dataclass check at entry — raises TypeError with a
descriptive message instead of failing later in dataclasses.fields
Assisted-by: Claude Opus 4.6
* isolate typing.get_type_hints call to placate astroid 3.x on py3.14
Astroid 3.x (used by pylint 3.x) follows typing.get_type_hints into
Python 3.14's annotationlib, which contains t-string literals it can't
parse and crashes with AttributeError on 'visit_templatestr'. Wrapping
the call in a helper that returns dict[str, Any] stops the inference at
the declared return type.
Assisted-by: Claude Opus 4.7
* inline the typing.get_type_hints wrap
Same effect as the prior helper — declaring the local as ``dict[str, Any]``
stops astroid's inference at the annotation rather than tracing into the
typing internals.
Assisted-by: Claude Opus 4.7
* add configure_sdk orchestrator for declarative config
Single entry point that takes a parsed OpenTelemetryConfiguration,
builds the resource, and applies the tracer/meter/logger providers
and propagator globally. Honors the top-level disabled flag — when
true, no globals are touched.
The orchestrator is a thin composition of the existing per-signal
configure_* factories; the deeper unification with the env-var path
(see #5126) is left for follow-up.
Refs #3631
Refs #5126
Assisted-by: Claude Opus 4.7
* rename changelog fragment to PR #5270
Assisted-by: Claude Opus 4.7
* use ExemplarFilter for enum coercion test fixture; allow 'astroid' in codespell
Replace the bespoke _Level enum (which violated pylint's invalid-name on
lowercase members) with the real ExemplarFilter enum from models.py — the
generated models use lowercase values verbatim from the JSON schema, so
using one of them avoids fighting the linter and exercises the same code
path with real data shapes.
Add 'astroid' to codespell's ignore-words-list; the prior commit's
explanatory comment mentions the library by name and codespell flagged it
as a misspelling of 'asteroid'.
Assisted-by: Claude Opus 4.7
* fix lint on test_sdk.py: hoist import, disable no-self-use
Move ``SdkTracerProvider`` import to module top (ruff PLC0415 /
pylint C0415) and add explicit ``# pylint: disable=no-self-use``
on the three mock-only tests that intentionally do not touch
``self``.
Assisted-by: Claude Opus 4.7
* remove extra blank line after imports (ruff I001)
Assisted-by: Claude Opus 4.7
* add end-to-end loader tests covering YAML -> typed config -> factory
The conversion module has unit tests that exercise _dict_to_dataclass
in isolation, but nothing verified the full pipeline: load a real
YAML file, get back fully-typed nested dataclasses, and feed the
result into a downstream factory function.
Adds two checks built on a representative nested fixture (tracer
provider with a parent-based / trace-id-ratio sampler and a batch
processor with console exporter):
- nested fields (sampler, processors[*].batch) come back as the
expected typed dataclasses, not raw dicts
- the typed result is accepted by ``create_tracer_provider`` and
produces an SDK ``TracerProvider``
This is the integration coverage requested in PR review feedback;
the inline example in the PR description is now an actual regression
test.
Assisted-by: Claude Opus 4.7
* address review feedback on configure_sdk
- log a warning rather than info when called with disabled=true; the
caller asked for setup and got a no-op, so the noise is warranted
- drop test_disabled_false_runs_setup; test_calls_each_signal_with_resource
already covers the disabled=False path with stricter assertions
Assisted-by: Claude Opus 4.7 (1M context)
* accept PathLike in load_config_file
callers with pathlib.Path no longer have to coerce to str at the
boundary. Path(file_path) and everything downstream already handle
PathLike, so this is a signature-only change.
Assisted-by: Claude Opus 4.7 (1M context)
* drop Union import from config conversion module
Use types.UnionType and typing.Union for optional unwrapping instead of
importing Union directly, matching modern | syntax in type hints. M
Mike Goldsmith committed
ba5e8db6e215029d636886bb69b9cc68b89c234c
Parent: 5f677f5
Committed by GitHub <noreply@github.com>
on 6/15/2026, 7:18:35 PM