def build_schema_data(self, cls: Member) -> SchemaDict: ctx = self.ctx walker = self.walker resolver = self.ctx.resolver metadata_resolver = resolver.metadata required: t.List[str] = [] properties: t.Dict[str, t.Any] = make_dict() description: str = metadata_resolver.resolve_doc(cls, verbose=ctx.verbose) schema: SchemaDict = make_dict( type="object", properties=properties, required=required, description=description, ) for field_name, info, metadata in walker.walk_fields(cls): field_name = metadata_resolver.resolve_name(metadata, default=field_name) if not info.is_optional: required.append(field_name) properties[field_name] = self.build_property_data( info, metadata=metadata) # simplify if len(required) <= 0: schema.pop("required") if not description: schema.pop("description") if ctx.strict and "additionalProperties" not in schema: schema["additionalProperties"] = False return schema
def scan(walker: Walker) -> Context: ctx = Context(walker) resolver = ctx.walker.resolver result = ctx.result scanned = _scan(walker) for enum in scanned.enums: result.enums[enum.__name__] = enum for cls in scanned.objects: schema = make_dict() typename = resolver.resolve_typename(cls) for field_name, info, metadata in walker.walk_fields(cls): field_name = resolver.metadata.resolve_name(metadata, default=field_name) prop = {"type": (scanned.get_name(info.type_) or detect.schema_type(info))} resolver.metadata.fill_extra_metadata(prop, metadata, name="graphql") schema[field_name] = prop result.types[typename] = schema return ctx
def scan(self, cls: Member) -> None: ctx = self.ctx walker = self.ctx.walker resolver = self.ctx.walker.resolver typename = resolver.resolve_typename(cls) required: t.List[str] = [] properties: t.Dict[str, t.Any] = make_dict() description = resolver.metadata.resolve_doc(cls, verbose=ctx.verbose) schema: t.Dict[str, t.Any] = make_dict( properties=properties, required=required, description=description ) for field_name, info, metadata in walker.walk_fields(cls): field_name = resolver.metadata.resolve_name(metadata, default=field_name) if not info.is_optional: required.append(field_name) # TODO: self recursion check (warning) if resolver.is_member(info.type_): walker.append(info.type_) properties[field_name] = self._build_ref_data(info.type_) continue if info.is_combined: properties[field_name] = prop = self._build_one_of_data(info) else: prop = properties[field_name] = {"type": detect.schema_type(info)} enum = detect.enum(info) if enum: prop["enum"] = enum # default if resolver.metadata.has_default(metadata): prop["default"] = resolver.metadata.resolve_default(metadata) resolver.metadata.fill_extra_metadata(prop, metadata, name="jsonschema") if prop.get("type") == "array": # todo: simplify with recursion assert len(info.args) == 1 first = info.args[0] if first.is_combined: prop["items"] = self._build_one_of_data(first) else: user_defined_type = first.user_defined_type if user_defined_type is None: prop["items"] = detect.schema_type(first) else: prop["items"] = self._build_ref_data(user_defined_type) if len(required) <= 0: schema.pop("required") if not description: schema.pop("description") if ctx.strict and "additionalProperties" not in schema: schema["additionalProperties"] = False ctx.state.schemas[typename] = ctx.result.result["definitions"][ typename ] = schema
class Result: result: t.Dict[str, t.Any] = dataclasses.field( default_factory=lambda: make_dict(definitions=make_dict()) )
def build_property_data( self, info: TypeInfo, *, metadata: MetaData) -> t.Union[PropertyDict, RefDict]: resolver = self.ctx.resolver metadata_resolver = resolver.metadata # TODO: self recursion check (warning) if (resolver.is_member(info.type_) or (info.user_defined_type is not None and not info.is_container and not info.is_newtype)) and resolver.resolve_typename(info.type_): return self.build_ref_data(info.type_) prop: PropertyDict = make_dict() if info.is_combined: prop.update(self.build_one_of_data(info)) # type: ignore else: prop["type"] = detect.schema_type(info) enum = detect.enum(info) if enum: prop["enum"] = enum # description if metadata.get("description"): prop["description"] = metadata_resolver.resolve_doc( info.type_, verbose=True, value=metadata["description"]) # default if metadata_resolver.has_default(metadata): prop["default"] = metadata_resolver.resolve_default(metadata) # inject extra data metadata_resolver.fill_extra_metadata( prop, metadata, name="openapi" # type:ignore ) if prop.get("type") == "array": # todo: simplify with recursion assert len(info.args) == 1 first = info.args[0] if first.is_combined and first.is_container: prop["items"] = self.build_one_of_data(first) elif first.user_defined_type is None: prop["items"] = {"type": detect.schema_type(first)} else: if first.user_defined_type is not None: prop["items"] = self.build_ref_data( first.user_defined_type) if info.is_newtype: if info.user_defined_type is not None: if prop.get("type") == "object": return self.build_ref_data(info.user_defined_type) else: if hasattr(info.supertypes[0], "__name__"): prop["format"] = resolver.resolve_typeformat(info) if info.container_type == "dict": prop[ "additionalProperties"] = self.build_property_data( # type: ignore info.args[1], metadata={}) return prop