1

I am trying to create a pydantic model that can parse json string with a list of different kind of models. See example below

test_object = """
{
  "distributions":
    [
      {
        "param_name": "test1",
        "attributes":
          {
            "distribution_name": "UniformDistribution",
            "low": "1.0",
            "high": "2.0"
          }
      },
      {
        "param_name": "test2",
        "attributes":
          {
            "distribution_name": "UniformDistribution",
            "low": "1.0",
            "high":"2.0"
          }
      },
      {
        "param_name": "test3",
        "attributes":
          {
            "distribution_name": "IntUniformDistribution",
            "low": "1",
            "high": "2",
            "q": 4
          }
      },
      {
        "param_name": "test4",
        "attributes":
          {
            "distribution_name": "DiscreteUniformDistribution",
            "low": "1.0",
            "high": "2.0",
            "step": ".1"
          }
      }
    ]
}
"""

This is my pydantic model to parse the above string.

from pydantic import BaseModel, conint, confloat, ValidationError
from typing import List, Literal, Union


class DiscreteUniformDistribution(BaseModel):
    distribution_name: Literal["DiscreteUniformDistribution"]
    low: float
    high: float
    q: confloat(gt=0)

class IntUniformDistribution(BaseModel):
    distribution_name: Literal["IntUniformDistribution"]
    low: int
    high: int
    step: conint(gt=0)

class UniformDistribution(BaseModel):
    distribution_name: Literal["UniformDistribution"]
    low: float
    high: float

class Distribution(BaseModel):
    param_name: str
    attributes: Union[
        DiscreteUniformDistribution,
        IntUniformDistribution,
        UniformDistribution,
    ]

class Distributions(BaseModel):
    distributions: List[Distribution]


try:
    Distributions.parse_raw(test_object)
except ValidationError as e:
    print(e)

However I am getting an error

9 validation errors for Distributions
distributions -> 2 -> attributes -> distribution_name
  unexpected value; permitted: 'DiscreteUniformDistribution' (type=value_error.const; given=IntUniformDistribution; permitted=('DiscreteUniformDistribution',))
distributions -> 2 -> attributes -> step
  field required (type=value_error.missing)
distributions -> 2 -> attributes -> distribution_name
  unexpected value; permitted: 'UniformDistribution' (type=value_error.const; given=IntUniformDistribution; permitted=('UniformDistribution',))
distributions -> 3 -> attributes -> q
  field required (type=value_error.missing)
distributions -> 3 -> attributes -> distribution_name
  unexpected value; permitted: 'IntUniformDistribution' (type=value_error.const; given=DiscreteUniformDistribution; permitted=('IntUniformDistribution',))
distributions -> 3 -> attributes -> low
  value is not a valid integer (type=type_error.integer)
distributions -> 3 -> attributes -> high
  value is not a valid integer (type=type_error.integer)
distributions -> 3 -> attributes -> step
  value is not a valid integer (type=type_error.integer)
distributions -> 3 -> attributes -> distribution_name
  unexpected value; permitted: 'UniformDistribution' (type=value_error.const; given=DiscreteUniformDistribution; permitted=('UniformDistribution',))

If works fine if there is only element in distributions list, like shown below.

test_object = """
{
  "distributions": 
    [
      {
        "param_name": "test1",
        "attributes":
          {
            "distribution_name": "UniformDistribution",
            "low": "1.0",
            "high": "2.0"
          }
      }
    ]
}
"""

I am new to pydantic. I suspect the error is do with my improper usage of Union.

1 Answer 1

1

Your usage of Union[] looks good, however, there is a typo in your model definitions.

You need to swap q in DiscreteUniformDistribution() with step in IntUniformDistribution() (only the field names, not the types), i.e.:

class DiscreteUniformDistribution(BaseModel):
    distribution_name: Literal['DiscreteUniformDistribution']
    low: float
    high: float
    step: confloat(gt=0)
#   ^^^^
#   This is called q in your definition

class IntUniformDistribution(BaseModel):
    distribution_name: Literal['IntUniformDistribution']
    low: int
    high: int
    q: conint(gt=0)
#   ^
#   This is called step in your definition
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.