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

Evaluate, improve and document compatibility with JSON Schema #59

Open
apirogov opened this issue Sep 24, 2022 · 1 comment
Open

Evaluate, improve and document compatibility with JSON Schema #59

apirogov opened this issue Sep 24, 2022 · 1 comment
Labels
enhancement New feature or request prio:B standards!!! Standard-compliance and best-practice related

Comments

@apirogov
Copy link
Collaborator

Functionality

Documentation

  • Both directions should be explained in one of the tutorials, e.g. to the one explaining JSON-LD

Testing

@apirogov apirogov added enhancement New feature or request standards!!! Standard-compliance and best-practice related labels Sep 24, 2022
@github-actions github-actions bot added the triage Freshly opened or reopened issue label Sep 24, 2022
@apirogov apirogov added prio:B and removed triage Freshly opened or reopened issue labels Sep 26, 2022
@apirogov
Copy link
Collaborator Author

apirogov commented Oct 7, 2022

@broeder-j

example input:

from __future__ import annotations

from typing import Literal, List, Union, Optional
from metador_core.schema.core import MetadataSchema
from metador_core.schema.ld import ld

@ld(context="https://www.schema.org")
class ModelA(MetadataSchema):
    """Model A"""
    foo: str
    bar: Optional[int]

class ModelB(ModelA):
    """Model B (subclass of Model A)"""

    bar: Literal[5]
    qux: float

class ModelC(MetadataSchema):
    """Model C (contains object of Model B)"""

    quux: bool
    blub: List[ModelB]
    bla: ModelA


class ModelD(ModelC):
    "subclass of Model D"

    class Config:
        extra = "forbid"

exported JSON Schema test.schema.json:

{
  "title": "ModelD",
  "description": "subclass of Model D",
  "type": "object",
  "additionalProperties": false,
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "allOf": [
    {
      "$ref": "#/$defs/71ffe60db66eb197"
    },
    {}
  ],
  "$metador_hash": "ea6634d2659b8ab2",
  "$defs": {
    "5f1c8d6cd5671a9c": {
      "title": "ModelB",
      "description": "Model B (subclass of Model A)",
      "type": "object",
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "$metador_plugin": {
        "name": "blub",
        "version": [
          0,
          1,
          1
        ]
      },
      "$metador_constants": {
        "@context": "https://www.schema.org"
      },
      "allOf": [
        {
          "$ref": "#/$defs/fc1b2f2509ac7477"
        },
        {
          "properties": {
            "bar": {
              "title": "Bar",
              "enum": [
                5
              ],
              "type": "integer"
            },
            "qux": {
              "title": "Qux",
              "type": "number"
            }
          },
          "required": [
            "bar",
            "qux"
          ]
        }
      ],
      "$metador_hash": "5f1c8d6cd5671a9c"
    },
    "fc1b2f2509ac7477": {
      "title": "ModelA",
      "description": "Model A",
      "type": "object",
      "properties": {
        "foo": {
          "title": "Foo",
          "type": "string"
        },
        "bar": {
          "title": "Bar",
          "type": "integer"
        },
        "@context": {}
      },
      "required": [
        "foo"
      ],
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "$metador_constants": {
        "@context": "https://www.schema.org"
      },
      "$metador_hash": "fc1b2f2509ac7477"
    },
    "71ffe60db66eb197": {
      "title": "ModelC",
      "description": "Model C (contains object of Model B)",
      "type": "object",
      "properties": {
        "quux": {
          "title": "Quux",
          "type": "boolean"
        },
        "blub": {
          "title": "Blub",
          "type": "array",
          "items": {
            "$ref": "#/$defs/5f1c8d6cd5671a9c"
          }
        },
        "bla": {
          "$ref": "#/$defs/fc1b2f2509ac7477",
          "description": "Model A"
        }
      },
      "required": [
        "quux",
        "blub",
        "bla"
      ],
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "$metador_hash": "71ffe60db66eb197"
    }
  }
}

Run generator with

datamodel-codegen --use-annotated --use-schema-description --use-title-as-name --strict-types {str,bytes,int,float,bool} --strip-default-none --base-class metador_core.schema.core.MetadataSchema --input-file-type=jsonschema --input test.schema.json

Result:

# generated by datamodel-codegen:
#   filename:  test.schema.json
#   timestamp: 2022-10-07T12:06:16+00:00

from __future__ import annotations

from enum import Enum
from typing import Annotated, Any, List, Optional

from pydantic import Extra, Field, StrictBool, StrictFloat, StrictInt, StrictStr

from metador_core.schema.core import MetadataSchema


class Bar(Enum):
    integer_5 = 5


class ModelA(MetadataSchema):
    """
    Model A
    """

    foo: Annotated[StrictStr, Field(title='Foo')]
    bar: Annotated[Optional[StrictInt], Field(title='Bar')]
    _context: Annotated[Optional[Any], Field(alias='@context')]


class ModelB(ModelA):
    """
    Model B (subclass of Model A)
    """

    bar: Annotated[Bar, Field(title='Bar')]
    qux: Annotated[StrictFloat, Field(title='Qux')]


class ModelC(MetadataSchema):
    """
    Model C (contains object of Model B)
    """

    quux: Annotated[StrictBool, Field(title='Quux')]
    blub: Annotated[List[ModelB], Field(title='Blub')]
    bla: Annotated[ModelA, Field(description='Model A')]


class ModelD(ModelC):
    """
    subclass of Model D
    """

    pass

    class Config:
        extra = Extra.forbid

Observations:

  • in general, it seems to work
  • surprisingly, it even picks up inheritance
  • of course, it does not reconstruct the original type annotations
  • of course, it cannot reconstruct the decorators etc.
  • of course, it does not know the type hints we use in metador and uses default hints

Summary:

  • a full 1-to-1 reconstruction is of course not possible (even though it would be cool), but it does recover substructures, which is good
  • a better mapping to Metador and phantom type hints seems like a thing one could try hacking into it (like the strict types option)
  • as is, it still produces a kind of useful draft (that must be worked over manually to make the schemas "nice")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request prio:B standards!!! Standard-compliance and best-practice related
Projects
None yet
Development

No branches or pull requests

1 participant