Пример #1
0
    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
Пример #2
0
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
Пример #3
0
    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
Пример #4
0
 class Result:
     result: t.Dict[str, t.Any] = dataclasses.field(
         default_factory=lambda: make_dict(definitions=make_dict())
     )
Пример #5
0
    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