Don't allow extra keys in top schema model

This commit is contained in:
Sina Atalay
2025-12-26 23:18:17 +03:00
parent 68ea7c35e0
commit 24b89bec90
3 changed files with 31 additions and 4 deletions

View File

@@ -155,7 +155,7 @@
"type": "object"
},
"Cv": {
"additionalProperties": true,
"additionalProperties": false,
"properties": {
"name": {
"anyOf": [
@@ -4986,6 +4986,7 @@
"description": "Vertical space between text-based entries. It can be specified with units (cm, in, pt, mm, ex, em). For example, `0.1cm`. The default value is `0.3em`."
},
"show_time_spans_in": {
"default": [],
"description": "Section titles where time spans (e.g., '2 years 3 months') should be displayed. The default value is `[]`.",
"items": {
"type": "string"
@@ -5017,6 +5018,7 @@
"description": "Vertical space between text-based entries. It can be specified with units (cm, in, pt, mm, ex, em). For example, `0.1cm`. The default value is `0.15cm`."
},
"show_time_spans_in": {
"default": [],
"description": "Section titles where time spans (e.g., '2 years 3 months') should be displayed. The default value is `[]`.",
"items": {
"type": "string"
@@ -5048,6 +5050,7 @@
"description": "Vertical space between text-based entries. It can be specified with units (cm, in, pt, mm, ex, em). For example, `0.1cm`. The default value is `0.3em`."
},
"show_time_spans_in": {
"default": [],
"description": "Section titles where time spans (e.g., '2 years 3 months') should be displayed. The default value is `[]`.",
"items": {
"type": "string"
@@ -5079,6 +5082,7 @@
"description": "Vertical space between text-based entries. It can be specified with units (cm, in, pt, mm, ex, em). For example, `0.1cm`. The default value is `0.3em`."
},
"show_time_spans_in": {
"default": [],
"description": "Section titles where time spans (e.g., '2 years 3 months') should be displayed. The default value is `[]`.",
"items": {
"type": "string"
@@ -5744,7 +5748,7 @@
"type": "string"
}
},
"additionalProperties": true,
"additionalProperties": false,
"properties": {
"cv": {
"$ref": "#/$defs/Cv",

View File

@@ -2,7 +2,7 @@ import pathlib
import pydantic
from .base import BaseModelWithExtraKeys
from .base import BaseModelWithoutExtraKeys
from .cv.cv import Cv
from .design.classic_theme import ClassicTheme
from .design.design import Design
@@ -11,7 +11,7 @@ from .settings.settings import Settings
from .validation_context import get_input_file_path
class RenderCVModel(BaseModelWithExtraKeys):
class RenderCVModel(BaseModelWithoutExtraKeys):
# Technically, `cv` is a required field, but we don't pass it to the JSON Schema
# so that the same schema can be used for standalone design, locale, and settings
# files.

View File

@@ -9,6 +9,26 @@ from rendercv.exception import RenderCVInternalError
type FieldSpec = tuple[type[Any], FieldInfo]
def sanitize_defaults(value: Any) -> Any:
"""Recursively convert CommentedMap/CommentedSeq to dict/list.
Why:
ruamel.yaml returns custom types that behave like dict/list but confuse Pydantic
and JSON schema generation. Stripping metadata ensures clean defaults.
Args:
value: The value to sanitize (can be nested dict/list structure).
Returns:
The sanitized value with standard Python types.
"""
if isinstance(value, list):
return [sanitize_defaults(v) for v in value]
if isinstance(value, dict):
return {k: sanitize_defaults(v) for k, v in value.items()}
return value
def create_variant_pydantic_model[T: pydantic.BaseModel](
variant_name: str,
defaults: dict[str, Any],
@@ -50,6 +70,9 @@ def create_variant_pydantic_model[T: pydantic.BaseModel](
"""
validate_defaults_against_base(defaults, base_class, variant_name)
# Sanitize defaults to remove ruamel.yaml metadata
defaults = sanitize_defaults(defaults)
field_specs: dict[str, Any] = {}
base_fields = base_class.model_fields