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

Fix: Minimum required props using oneOf #114

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions jsf/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,8 @@ def __parse_definition(
enum_list = schema["enum"]
assert len(enum_list) > 0, "Enum List is Empty"
assert all(
isinstance(item, (int, float, str, dict, type(None))) for item in enum_list
), "Enum Type is not null, int, float, string or dict"
isinstance(item, (bool, int, float, str, dict, type(None))) for item in enum_list
), "Enum Type is not null, bool, int, float, string or dict"
return JSFEnum.from_dict(
{
"name": name,
Expand Down
19 changes: 19 additions & 0 deletions jsf/schema_types/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import random
import uuid
from collections import ChainMap
from typing import Any, Dict, List, Optional, Tuple, Type, Union

from pydantic import BaseModel, Field
Expand Down Expand Up @@ -28,6 +29,10 @@ class BaseSchema(BaseModel):
# The $comment keyword is strictly intended for adding comments to the JSON schema source. Its value must always be a string. Unlike the annotations title, description and examples, JSON schema implementations aren't allowed to attach any meaning or behavior to it whatsoever, and may even strip them at any time. Therefore, they are useful for leaving notes to future editors of a JSON schema, (which is quite likely your future self), but should not be used to communicate to users of the schema.
comments: Optional[str] = Field(None, alias="$comments")

oneOf: Optional[List[Dict[str, Any]]] = None
anyOf: Optional[List[Dict[str, Any]]] = None
allOf: Optional[List[Dict[str, Any]]] = None

# JSF Custom fields
path: Optional[str] = None
name: Optional[str] = None
Expand All @@ -49,6 +54,20 @@ def generate(self, context: Dict[str, Any]) -> Any:
if self.set_state is not None:
context["state"][self.path] = {k: eval(v, context)() for k, v in self.set_state.items()}

if self.oneOf is not None and self.__class__.__name__ != "OneOf":
additional_validations = random.choice(self.oneOf)
for k, v in additional_validations.items():
setattr(self, k, v)

if self.allOf is not None and self.__class__.__name__ != "AllOf":
additional_validations = dict(ChainMap(*self.allOf))
for k, v in additional_validations.items():
setattr(self, k, v)
if self.anyOf is not None and self.__class__.__name__ != "AnyOf":
additional_validations = dict(ChainMap(*random.choices(self.anyOf, k=len(self.anyOf))))
for k, v in additional_validations.items():
setattr(self, k, v)

if self.is_nullable and (
random.uniform(0, 1) < self.allow_none_optionals
or context["state"]["__depth__"] > self.max_recursive_depth
Expand Down
2 changes: 1 addition & 1 deletion jsf/schema_types/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@


class JSFEnum(BaseSchema):
enum: Optional[List[Union[str, int, float, dict, None]]] = []
enum: Optional[List[Union[bool, str, int, float, dict, None]]] = []
model_config = ConfigDict()

def generate(self, context: Dict[str, Any]) -> Optional[Union[str, int, float]]:
Expand Down
3 changes: 3 additions & 0 deletions jsf/tests/data/bool-enum.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"enum": [true]
}
15 changes: 15 additions & 0 deletions jsf/tests/data/min-required-props-oneof.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"type": "object",
"friendly_name": "Corporate Structure Changes",
"description": "Parameters for corporate structure changes",
"properties": {
"new_parent": { "const": true },
"new_subsidiary": { "const": true },
"new_sibling": { "const": true }
},
"oneOf": [
{ "required": ["new_parent"] },
{ "required": ["new_subsidiary"] },
{ "required": ["new_sibling"] }
]
}
24 changes: 24 additions & 0 deletions jsf/tests/test_default_fake.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,3 +544,27 @@ def test_use_defaults_and_examples(TestData):
assert d["name"] in ["Chop", "Luna", "Thanos"]
breed = d.get("breed")
assert breed is None or breed == "Mixed Breed"


def test_min_required_props_oneof(TestData):
with open(TestData / "min-required-props-oneof.json") as file:
schema = json.load(file)
p = JSF(schema)
fake_data = [p.generate(use_examples=True) for _ in range(100)]

for d in fake_data:
assert isinstance(d, dict)
assert len(d.keys()) >= 1
assert all(isinstance(v, bool) for v in d.values())
assert all(d.values())


def test_bool_enum(TestData):
with open(TestData / "bool-enum.json") as file:
schema = json.load(file)
p = JSF(schema)
fake_data = [p.generate() for _ in range(100)]

for d in fake_data:
assert isinstance(d, bool)
assert d
Loading