@@ -575,7 +575,13 @@ def extract_props(tpe: RiverType) -> list[dict[str, RiverType]]:
575575 if name == "$kind" :
576576 safe_name = "kind"
577577 else :
578- safe_name = name
578+ # For TypedDict encoder, use normalized name to access
579+ # the TypedDict field but the output dictionary key should
580+ # use the original name
581+ if base_model == "TypedDict" :
582+ safe_name = normalize_special_chars (name )
583+ else :
584+ safe_name = name
579585 if prop .type == "object" and not prop .patternProperties :
580586 encoder_name = TypeName (
581587 f"encode_{ render_literal_type (type_name )} "
@@ -675,14 +681,20 @@ def extract_props(tpe: RiverType) -> list[dict[str, RiverType]]:
675681 effective_name = name
676682 extras = []
677683 if name != specialized_name :
678- if base_model != "BaseModel" :
679- # TODO: alias support for TypedDict
680- raise ValueError (
681- f"Field { name } is not a valid Python identifier, but it is in the schema" # noqa: E501
682- )
683- # Pydantic doesn't allow leading underscores in field names
684- effective_name = specialized_name .lstrip ("_" )
685- extras .append (f"alias={ repr (name )} " )
684+ if base_model == "BaseModel" :
685+ # Pydantic doesn't allow leading underscores in field names
686+ effective_name = specialized_name
687+ extras .append (f"alias={ repr (name )} " )
688+ elif base_model == "TypedDict" :
689+ # For TypedDict, we use the normalized name directly
690+ # TypedDict doesn't support aliases, so we normalize
691+ # the field name
692+ effective_name = specialized_name
693+ else :
694+ # For RiverError (which extends BaseModel), use alias
695+ # like BaseModel
696+ effective_name = specialized_name
697+ extras .append (f"alias={ repr (name )} " )
686698
687699 effective_field_names [effective_name ].append (name )
688700
0 commit comments