Skip to content

Dict[str, V] round-trips to a field-named model instead of a mapping (additionalProperties ignored) #1969

Description

@ErenAta16

Describe the issue as clearly as possible:

Dict[str, V] doesn't survive a JSON-Schema round trip. schema_type_to_python treats any {"type": "object"} as a nested model and ignores additionalProperties, so a mapping field comes back as a generated model instead of Dict[str, V]. The generated class is named from the schema title, which for a field like by_user is "By User" — a name with a space in it, not a valid Python identifier.

That means the reconstructed type accepts a fixed (empty) set of keys rather than arbitrary string keys, which is the opposite of what the original annotation meant.

Steps/code to reproduce the bug:

from typing import Dict
from pydantic import BaseModel
from outlines.types.json_schema_utils import (
    json_schema_dict_to_pydantic,
    json_schema_dict_to_dataclass,
)

class Scores(BaseModel):
    by_user: Dict[str, int] = {}

schema = Scores.model_json_schema()
# {"properties": {"by_user": {"additionalProperties": {"type": "integer"},
#                             "default": {}, "title": "By User", "type": "object"}}, ...}

json_schema_dict_to_pydantic(schema).model_fields["by_user"].annotation
json_schema_dict_to_dataclass(schema)

Expected result:

Optional[Dict[str, int]]

Error message:

No error — it degrades quietly:

converter result
json_schema_dict_to_pydantic Optional[outlines.types.json_schema_utils.By User]
json_schema_dict_to_dataclass <class 'outlines.types.json_schema_utils.By User'>
json_schema_dict_to_typeddict NotRequired[outlines.types.json_schema_utils.By User]
"By User".isidentifier()   # False

The generated model has no fields, so nothing in the original mapping's value type survives either — int is gone.

List[str] in the same model round-trips correctly to Optional[List[str]], so this is specific to the additionalProperties shape.

Outlines/Python version information:

outlines @ 13fe8dd (main), Python 3.10.12, pydantic 2.12.5

Context for the maintainers:

schema_type_to_python's t == "object" branch goes straight to json_schema_dict_to_{pydantic,typeddict,dataclass} without looking at additionalProperties. Reading it first — mapping {"type": "object", "additionalProperties": S} with no properties to Dict[str, schema_type_to_python(S)] — would cover it.

Filing this separately because #1908, #1949, #1951 and #1963 are all open against schema_type_to_python and none of them touch additionalProperties; I checked each of them against this repro.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions