Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advice for setting schema_extra on primitive types #1564

Closed
lewisbelcher opened this issue May 26, 2020 · 2 comments
Closed

Advice for setting schema_extra on primitive types #1564

lewisbelcher opened this issue May 26, 2020 · 2 comments
Labels

Comments

@lewisbelcher
Copy link

lewisbelcher commented May 26, 2020

I'm trying to set a format field in the JSON schema on generic elements of array. I think the best way to describe it is with an example; I have a generic model Samples[T], which is currently implemented as:

from types import Generic, List, TypeVar
from pydantic import Field
from pydantic.generics import GenericModel

T = TypeVar("T")

class Samples(GenericModel, Generic[T]):
    samples: List[T] = Field(..., description="Array of samples.")

I can produce the following JSON schema from a concrete type of this (say Samples[str]) which gives:

{
  "title": "Samples[str]",
  "type": "object",
  "properties": {
    "samples": {
      "title": "Samples",
      "description": "Array of samples.",
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  },
  "required": [
    "samples"
  ]
}

I would like to add a format field into the items element of this schema (giving "items": {"type": "string", "format": "my-format"}) in a generic way. So far I've tried:

  • Customising the schema by implementing a config on Samples with a schema_extra static function (as per the docs) which targets a specific case (schema["properties"]["samples"]["items"]["format"] = "my-format"), but this doesn't generalise for any T (T may be a nested array of strings which also require specifying format on their elements).
  • Using a BaseModel with a __root__ element for T and implementing a config with a schema_extra on that. This would be the ideal solution, but it promotes the type of items to object, rather than string (this causes issues with FastAPI either which is my target in this case).

I could create a Pydantic model factory and dynamically create schema_extra functions which do the appropriate changes to each specific model (with the aid of some arguments to the factory), this seems like an ugly solution though. Is there anything else I can try?

@PrettyWood
Copy link
Member

Hey @lewisbelcher ,
Have you considered using __modify_schema__ ? Here is an example on the #1562 branch that fixes duplicated field

from typing import Generic, List, TypeVar, Type
from pydantic import Field
from pydantic.generics import GenericModel

T = TypeVar("T")

def with_modified_schema(type_: T, **kwargs) -> Type[T]:
    class WithModifiedSchema(type_):
        @classmethod
        def __modify_schema__(cls, schema):
            schema.update(**kwargs)
    return WithModifiedSchema

class Samples(GenericModel, Generic[T]):
    samples: List[T] = Field(..., description="Array of samples.")


print(Samples[with_modified_schema(str, format='my-string-format')].schema_json(indent=2))
{
  "title": "Samples[WithModifiedSchema]",
  "type": "object",
  "properties": {
    "samples": {
      "title": "Samples",
      "description": "Array of samples.",
      "type": "array",
      "items": {
        "type": "string",
        "format": "my-string-format"
      }
    }
  },
  "required": [
    "samples"
  ]
}

Does it solve your problem?

@lewisbelcher
Copy link
Author

Yes this looks like exactly what I need @PrettyWood! Thanks!

@lewisbelcher lewisbelcher changed the title Advice for setting schema_extra on primative types Advice for setting schema_extra on primitive types Jun 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants