ghandic/jsf

Add support for schema composition

Closed this issue · 11 comments

Do you have any full examples of this? The docs don't really give muc detail on it imo.

This is an example from the documentation

{
  "anyOf": [
    { "type": "string", "maxLength": 5 },
    { "type": "number", "minimum": 0 }
  ]
}

On my project I have something like this

{
	"$ref": "#/definitions/objOrString",
	"definitions": {
		"refObj": {
			"type": "object",
			"properties": {
				"field_1": {
					"type": ["string", "null"]
				},
				"field_2": {
					"type": ["string", "null"]
				}
			},
		},
		"objOrString": {
			"anyOf": [
			  { "$ref": "#/definitions/refObj" },
			  { "type": "string" }
			]
		  }
	}
}

I will make pull request, review it when you have time

Have a similar issue. Using JSF to generate data for Pydantic models for unint tests via:

from typing import List, Type, TypeVar

from jsf import JSF  # type: ignore
from pydantic import BaseModel

TModel = TypeVar("TModel", bound=BaseModel)


class AutoFixture:
    @staticmethod
    def create(model_type: Type[TModel]) -> TModel:
        schema = model_type.schema()
        data = JSF(schema).generate()
        return model_type(**data)

Everything works fine for built-in types and flat models, but fails immediately with something else.
For example, having model with a field of Enum type:

class Model(BaseModel):
    environment: Environment
    version: str

Where first field type is:

from enum import Enum

class Environment(str, Enum):
    LOCAL = "local"
    DEV = "development"

Throws with:
ValueError: Cannot parse schema {'env_names': {'app_environment'}, 'allOf': [{'$ref': '#/definitions/Environment'}]}

Could you add a minimal json schema you're using and wa hat you expect it to produce? Can add into the tests then get green. PR's welcome

@ghandic for sure, here it is:

{
   "title":"AppSettings",
   "description":"test",
   "type":"object",
   "properties":{
      "environment":{
         "env_names":[
            "environment"
         ],
         "allOf":[
            {
               "$ref":"#/definitions/Environment"
            }
         ]
      }
   },
   "required":[
      "environment"
   ],
   "additionalProperties":false,
   "definitions":{
      "Environment":{
         "title":"Environment",
         "description":"Defines application environment",
         "enum":[
            "local",
            "development"
         ],
         "type":"string"
      }
   }
}

I think it is not because of inner schema, but just because it can not work with Enums for some reason.

Was this issue picked up / resolved? I am facing the same issue with allOf key.

Could you add an example and what you expect?

I'm a little confused by the original example

Please see the following code and output. I am trying to use jsf in conjunction with Pydantic

Code

import json
from typing import Optional

from jsf import JSF
from pydantic import schema_of, BaseModel, Field


class Prometheus(BaseModel):
    port: int = Field(..., description="Port at which Prometheus metrics are exposed")
    path: str = Field(..., description="Path at which Prometheus metrics are exposed")


class PodConfig(BaseModel):
    prometheus: Optional[Prometheus] = Field(None, description="Prometheus details")


if __name__ == '__main__':
    obj = schema_of(PodConfig)
    print(json.dumps(obj, indent=2))
    faker = JSF(obj)
    fake_json = faker.generate()
    print(fake_json)

Logs

/Users/gautamsinghania/Desktop/work/envs/seldon/bin/python /Users/gautamsinghania/Desktop/work/repos/holmes/services/seldon/main_schema.py
Traceback (most recent call last):
  File "/Users/gautamsinghania/Desktop/work/repos/holmes/services/seldon/main_schema.py", line 27, in <module>
    faker = JSF(obj)
  File "/Users/gautamsinghania/Desktop/work/envs/seldon/lib/python3.9/site-packages/jsf/parser.py", line 42, in __init__
    self._parse(schema)
  File "/Users/gautamsinghania/Desktop/work/envs/seldon/lib/python3.9/site-packages/jsf/parser.py", line 126, in _parse
    item = self.__parse_definition(name, path="#/definitions", schema=definition)
  File "/Users/gautamsinghania/Desktop/work/envs/seldon/lib/python3.9/site-packages/jsf/parser.py", line 97, in __parse_definition
    return self.__parse_object(name, path, schema)
  File "/Users/gautamsinghania/Desktop/work/envs/seldon/lib/python3.9/site-packages/jsf/parser.py", line 54, in __parse_object
    props.append(self.__parse_definition(_name, path=f"{path}/{_name}", schema=definition))
  File "/Users/gautamsinghania/Desktop/work/envs/seldon/lib/python3.9/site-packages/jsf/parser.py", line 122, in __parse_definition
    raise ValueError(f"Cannot parse schema {repr(schema)}")  # pragma: no cover
ValueError: Cannot parse schema {'title': 'Prometheus', 'description': 'Prometheus details', 'allOf': [{'$ref': '#/definitions/Prometheus'}]}
{
  "title": "ParsingModel[PodConfig]",
  "$ref": "#/definitions/PodConfig",
  "definitions": {
    "Prometheus": {
      "title": "Prometheus",
      "type": "object",
      "properties": {
        "port": {
          "title": "Port",
          "description": "Port at which Prometheus metrics are exposed",
          "type": "integer"
        },
        "path": {
          "title": "Path",
          "description": "Path at which Prometheus metrics are exposed",
          "type": "string"
        }
      },
      "required": [
        "port",
        "path"
      ]
    },
    "PodConfig": {
      "title": "PodConfig",
      "type": "object",
      "properties": {
        "prometheus": {
          "title": "Prometheus",
          "description": "Prometheus details",
          "allOf": [
            {
              "$ref": "#/definitions/Prometheus"
            }
          ]
        }
      }
    }
  }
}

Process finished with exit code 1

@ghandic any updates?

I'm not free to work on this this month as I'm maxed out at work. However the repo is open for PR's if you have some suggestions :)

See #54

If acceptable, will be released in next minor version