datamodel-code-generator icon indicating copy to clipboard operation
datamodel-code-generator copied to clipboard

Multiple pattern properties are not handled correctly

Open georgms opened this issue 3 years ago • 5 comments

Describe the bug

JSON schema pattern properties can provide multiple patterns where any object property key must match one of the patterns. This is probably not handled correctly by models generated from such a schema.

To Reproduce

Example schema:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Foo",
  "type": "object",
  "properties": {
    "bar": {
      "type": "object",
      "patternProperties": {
        "^A_\\d$": {
          "type": "string"
        },
        "^B_\\d$": {
          "type": "string"
        }
      }
    }
  }
}

Used commandline:

$ datamodel-codegen --input tests/data/jsonschema/pattern_properties.json

Expected behavior The given command should generate a model that handles this example data:

{
  "bar": {
    "A_1": "a",
    "B_2": "b"
  }
}

However, it will fail with the following error message:

pydantic.error_wrappers.ValidationError: 2 validation errors for Foo
bar -> __key__
  string does not match regex "^A_\d$" (type=value_error.str.regex; pattern=^A_\d$)
bar -> __key__
  string does not match regex "^B_\d$" (type=value_error.str.regex; pattern=^B_\d$)

Version:

  • OS: Ubuntu 20.04
  • Python version: 3.8.10
  • datamodel-code-generator version: 0.11.15

Additional context Add any other context about the problem here.

georgms avatar Dec 22 '21 14:12 georgms

I added a reproduction case in #663 .

georgms avatar Dec 22 '21 14:12 georgms

I have asked in https://github.com/samuelcolvin/pydantic/discussions/3561 how to handle this in Pydantic.

georgms avatar Dec 22 '21 14:12 georgms

So the generator comes up with something like

class Foo(BaseModel):
    bar: Optional[
        Union[
             Dict[constr(regex=r'^A_\d$'), str],
             Dict[constr(regex=r'^B_\d$'), str],
        ]
    ] = None

However, the correct way is

class Foo(BaseModel):
    bar: Optional[
        Dict[
            Union[constr(regex=r'^A_\d$'), constr(regex=r'^B_\d$')],
            str,
        ]
    ] = None

So Union inside Dict, not the other way around. I'll try to come up with a fix for that.

georgms avatar Jan 11 '22 08:01 georgms

Nevermind. This only works for the case where all keys the same type str.

georgms avatar Jan 11 '22 14:01 georgms

@georgms Thank you for creating PR and the issue.

Nevermind. This only works for the case where all keys the same type str.

We should discuss the best way in the pydantic project.

koxudaxi avatar Jan 11 '22 17:01 koxudaxi

no response :(

koxudaxi avatar Dec 28 '22 14:12 koxudaxi