feat(config): recursively convert parsed dicts to typed dataclasses in loader (#5269)
* 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
* 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
* 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
* verify sampler and span processor wiring in factory test
Reach into the SDK private fields the same way other tests in this file
already do (pylint protected-access disabled at the class level on the
similar test_meter_provider.py) so we confirm the YAML actually flowed
through into the right Sampler/SpanProcessor/Exporter structure rather
than just landing as some TracerProvider instance.
Addresses Dylan's nit on #5269.
Assisted-by: Claude Opus 4.7 (1M context)
---------
Co-authored-by: Lukas Hering <40302054+herin049@users.noreply.github.com> M
Mike Goldsmith committed
15954ef004ed8a0f9974f6ab5a5083cccb6b1c02
Parent: 39ff55d
Committed by GitHub <noreply@github.com>
on 6/10/2026, 7:02:08 PM