Example #1
0
 def _visited_union(self, results: Sequence[JsonSchema]) -> JsonSchema:
     if len(results) == 1:
         return results[0]
     elif any(alt == {} for alt in results):
         return JsonSchema()
     elif all(alt.keys() == {"type"} for alt in results):
         types: Any = chain.from_iterable(
             [res["type"]] if isinstance(res["type"], (
                 str, JsonType)) else res["type"] for res in results)
         return json_schema(type=list(types))
     elif (len(results) == 2 and all("type" in res for res in results) and {
             "type": "null"
     } in results):
         for result in results:
             if result != {"type": "null"}:
                 types = result["type"]
                 if isinstance(types, (str, JsonType)):
                     types = [types]
                 if "null" not in types:
                     result = JsonSchema({
                         **result, "type": [*types, "null"]
                     })
                 return result
         else:
             raise NotImplementedError
     else:
         return json_schema(anyOf=results)
Example #2
0
 def wrapper(self: "SchemaBuilder", *args, **kwargs):
     if self._schema is None:
         return method(self, *args, **kwargs)
     elif self._schema.override:
         return JsonSchema(**self._schema.as_dict())
     else:
         return JsonSchema(method(self, *args, **kwargs),
                           **self._schema.as_dict())
Example #3
0
def _set_missing_properties(schema: JsonSchema,
                            properties: Optional[Mapping[str, JsonSchema]],
                            key: str) -> JsonSchema:
    if properties is None:
        return schema
    missing = {
        name: prop
        for name, prop in properties.items() if prop.get(key, False)
    }
    schema.setdefault("properties", {}).update(missing)
    return schema
Example #4
0
 def _union_result(self, results: Iterable[JsonSchema]) -> JsonSchema:
     results = list(results)
     if len(results) == 1:
         return results[0]
     elif all(alt.keys() == {"type"} for alt in results):
         types = chain.from_iterable(
             [res["type"]] if isinstance(res["type"], JsonType
                                         ) else res["type"]
             for res in results)
         return json_schema(type=list(types))
     elif (len(results) == 2 and all("type" in res for res in results) and {
             "type": "null"
     } in results):
         for result in results:
             if result != {"type": "null"}:
                 types = result["type"]
                 if isinstance(types, str):
                     types = [types]  # type: ignore
                 if "null" not in types:
                     result = JsonSchema({
                         **result, "type": [*types, "null"]
                     })
                 return result
         else:
             raise NotImplementedError()
     else:
         return json_schema(anyOf=results)
Example #5
0
 def ref_schema(self, ref: Optional[str]) -> Optional[JsonSchema]:
     if ref not in self.refs:
         return None
     elif self._ignore_first_ref:
         self._ignore_first_ref = False
         return None
     else:
         assert isinstance(ref, str)
         return JsonSchema({"$ref": self.ref_factory(ref)})
Example #6
0
def to_json_schema_7(schema: JsonSchema) -> JsonSchema7:
    result = schema.copy()
    isolate_ref(result)
    if "$defs" in result:
        result["definitions"] = {
            **result.pop("$defs"),
            **result.get("definitions", {})
        }
    if "dependentRequired" in result:
        result["dependencies"] = {
            **result.pop("dependentRequired"),
            **result.get("dependencies", {}),
        }
    return JsonSchema7(result)
Example #7
0
 def visit_field(self, field: ObjectField) -> JsonSchema:
     result = full_schema(
         self.visit_with_conv(field.type, self._field_conversion(field)),
         field.schema,
     )
     if (not field.flattened and not field.pattern_properties
             and not field.additional_properties and not field.required
             and "default" not in result):
         result = JsonSchema(result)
         with suppress(Exception):
             result["default"] = serialize(
                 field.type,
                 field.get_default(),
                 fall_back_on_any=False,
                 check_type=True,
                 conversion=field.serialization,
             )
     return result
Example #8
0
def to_open_api_3_0(schema: JsonSchema) -> OpenAPI30:
    result = schema.copy()
    for key in ("dependentRequired", "unevaluatedProperties", "$defs"):
        result.pop(key, ...)
    isolate_ref(result)
    if "null" in result.get("type", ()):
        result.setdefault("nullable", True)
        if result["type"] == "null":
            result.pop("type")
        else:
            types = [t for t in result["type"] if t != "null"]
            result["type"] = types if len(types) > 1 else types[0]
    if {"type": "null"} in result.get("anyOf", ()):
        result.setdefault("nullable", True)
        result["anyOf"] = [a for a in result["anyOf"] if a != {"type": "null"}]
    if "examples" in result:
        result.setdefault("example", result.pop("examples")[0])
    return OpenAPI30(result)
Example #9
0
 def _properties_schema(self, field: Field,
                        field_type: AnyType) -> JsonSchema:
     with self._without_ref():
         props_schema = self.visit_field(field, field_type)
     if not props_schema.get("type") == JsonType.OBJECT:
         raise TypeError("properties field must have an 'object' type")
     if "patternProperties" in props_schema:
         if (len(props_schema["patternProperties"]) != 1
                 or "additionalProperties"
                 in props_schema):  # don't try to merge the schemas
             pass
         else:
             return next(iter(props_schema["patternProperties"].values()))
     elif "additionalProperties" in props_schema:
         if isinstance(props_schema["additionalProperties"], JsonSchema):
             return props_schema["additionalProperties"]
         else:  # there is maybe only properties
             pass
     return JsonSchema()
Example #10
0
 def _properties_schema(self, field: ObjectField) -> JsonSchema:
     assert field.pattern_properties is not None or field.additional_properties
     with context_setter(self):
         self._ignore_first_ref = True
         props_schema = self.visit_field(field)
     if not props_schema.get("type") == JsonType.OBJECT:
         raise TypeError("properties field must have an 'object' type")
     if "patternProperties" in props_schema:
         if (len(props_schema["patternProperties"]) != 1
                 or "additionalProperties"
                 in props_schema):  # don't try to merge the schemas
             pass
         else:
             return next(iter(props_schema["patternProperties"].values()))
     elif "additionalProperties" in props_schema:
         if isinstance(props_schema["additionalProperties"], JsonSchema):
             return props_schema["additionalProperties"]
         else:  # there is maybe only properties
             pass
     return JsonSchema()
Example #11
0
def full_schema(base_schema: JsonSchema,
                schema: Optional[Schema]) -> JsonSchema:
    if schema is not None:
        base_schema = JsonSchema(base_schema)
        schema.merge_into(base_schema)
    return base_schema
Example #12
0
 def primitive(self, cls: Type) -> JsonSchema:
     return JsonSchema(type=JsonType.from_type(cls))
Example #13
0
 def any(self) -> JsonSchema:
     return JsonSchema()
Example #14
0
 def primitive(self, cls: Type) -> JsonSchema:
     if cls in constraint_by_type:
         self._check_constraints(constraint_by_type[cls])
     return JsonSchema(type=JsonType.from_type(cls))
Example #15
0
 def _ref_schema(self, ref: str) -> JsonSchema:
     return JsonSchema({"$ref": self.ref_factory(ref)})