feat(config): add additionalProperties support to generated config models#5131
feat(config): add additionalProperties support to generated config models#5131MikeGoldsmith wants to merge 8 commits intoopen-telemetry:mainfrom
Conversation
Schema types with additionalProperties (Sampler, SpanExporter, TextMapPropagator, ExperimentalResourceDetector, etc.) now capture unknown keyword arguments in an additional_properties dict field. This enables plugin/custom component names to flow through typed dataclasses without modifying the codegen tool. Implementation: - _additional_properties_support decorator in _common.py wraps the dataclass __init__ to route unknown kwargs into additional_properties - Custom dataclass.jinja2 template for datamodel-codegen conditionally applies the decorator and field when additionalPropertiesType is set - pyproject.toml updated with custom-template-dir and additional-imports - models.py regenerated via tox -e generate-config-from-jsonschema Assisted-by: Claude Opus 4.6
…kwargs - Replace object.__setattr__ with plain self.additional_properties = extra (no frozen dataclasses, simpler and more Pythonic) - Add pylint disable=unexpected-keyword-arg on test lines that intentionally pass unknown kwargs to verify the decorator captures them - Add comment explaining setattr usage for __signature__ (pyright workaround) Assisted-by: Claude Opus 4.6
| @@ -1 +1 @@ | |||
| # SDK File Configuration | |||
There was a problem hiding this comment.
Something that I've been thinking about is if we want file configuration to be its own package entirely. I'm not sure if you have measured the code size yet, but I would imagine that as more features are added, it won't be insignificant. It would be good to at least provide users the option to not install file-based configuration, perhaps in very simple/minimal environments.
There was a problem hiding this comment.
I understand the concern, but I don't think we're adding too much bloat here. Also, if we move to a separate package, the user experience of "it just works" will be broken.
The models are generated at dev-time and source controlled. The deps to build the models (JSON schema and jinja template) won't be included in the dist package either.
I hope to unify the env var & file config paths to leverage these generated models if I can so they'll be useful for both scenarios.
Does that help?
…perties ClassVar tells type checkers the attribute exists without creating a dataclass field. This means additional_properties doesn't appear in __init__ signature, dataclasses.fields(), asdict(), or repr() — only schema-defined fields show up. The decorator sets it as a plain instance attribute at runtime. Assisted-by: Claude Opus 4.6
…s-support' into mike/config-additional-properties-support
Description
Adds support for JSON Schema
additionalPropertiesto the generated config dataclasses. This is the foundation for plugin/custom component loading in declarative file configuration — unknown component names (e.g.my_custom_sampler,my_custom_exporter) can now flow through typed dataclasses without being silently dropped.Problem
The OTel configuration JSON schema defines
additionalPropertieson 12 types (Sampler,SpanExporter,TextMapPropagator,ExperimentalResourceDetector,LogRecordExporter,PushMetricExporter, etc.) to allow plugin component names as keys. However,datamodel-codegenignoresadditionalPropertieswhen generating plain Python dataclasses — there's no stdlib mechanism for it. Unknown kwargs are rejected by the dataclass__init__.Solution
A custom
datamodel-codegentemplate (opentelemetry-sdk/codegen/dataclass.jinja2) conditionally adds two things to affected classes:@_additional_properties_supportdecorator — wraps the dataclass__init__to route unknown kwargs into anadditional_propertiesinstance attribute instead of raisingTypeErroradditional_properties: ClassVar[dict[str, Any]]annotation — satisfies type checkers without creating a dataclass field, soadditional_propertiesdoesn't appear in__init__signature,dataclasses.fields(),asdict(), orrepr()The decorator preserves the original
inspect.signature()(for IDE autocompletion) and appends**kwargsto signal extras are accepted.How it works
The template checks
additionalPropertiesType, a context variable thatdatamodel-codegensets for schema types whereadditionalPropertiesis a type object (e.g.{"type": ["object", "null"]}). This is how the OTel schema defines it for plugin-capable types.Usage
Codegen
No changes to the codegen workflow —
tox -e generate-config-from-jsonschemapicks up the custom template via thecustom-template-dirconfig inpyproject.toml.Tests
TestAdditionalPropertiesSupport— 5 unit tests for the decorator (known fields, unknown fields, mixed, empty, signature preservation)TestGeneratedModelsHaveAdditionalProperties— 6 regression tests verifying the key generated models accept unknown kwargs (guards againstdatamodel-codegenchanging how it passes the template variable)