kuimono / openapi-schema-pydantic Goto Github PK
View Code? Open in Web Editor NEWOpenAPI (v3) specification schema as pydantic class
License: MIT License
OpenAPI (v3) specification schema as pydantic class
License: MIT License
Hi there,
The usage of Extra.forbid is difficult to work with in other libraries, because it requires sanitizing data before interacting with this library. Is it possible to change Extra.forbid to Extra.ignore? Especially for Schema but also other models.
Hey there!
I think this library would be a lot more flexible if the models allowed extra fields to be set so arbitrary extensions can be used. This will make it a lot more useful for downstream libraries such as client generators.
I noticed in #9 you mentioned that you preferred to disallow this to show the library doesn't support this, but as far as I can tell, allowing the extensions will not affect the way this library works. Granted, extensions will not have validation or typing, but as long as we add a disclaimer in the readme I don't see why these shouldn't be allowed?
Thanks 😄
See 3.1.0 OpenAPI specification:
Relative References in URLs
Unless specified otherwise, all properties that are URLs MAY be relative references as defined by RFC3986. Unless specified otherwise, relative references are resolved using the URLs defined in the Server Object as a Base URL. Note that these themselves MAY be relative to the referring document.
Because the required types for URLs in the Pydanic models are AnyURL
, setting them to a relative URL (e.g. setting components -> securitySchemes -> OAuth2PasswordBearer -> flows -> password -> tokenUrl
to auth/token
) causes the following:
pydantic.error_wrappers.ValidationError:
invalid or missing URL scheme (type=value_error.url.scheme)
For example, this will fail to validate the OpenAPI specs generated by FastAPI when following the OAuth2 security tutorial.
This breaks some cool cache-logic in the PDM package manager. Any change you could ship a version of this without the test/ folder? Thanks!
Versions:
$ pip list | rg pydantic
openapi-schema-pydantic 1.2.1
pydantic 1.9.0
Prior to pydantic 1.9.0, discriminator
was not a reserved attribute in the pydantic.Field
class. This meant the following definition was valid:
from typing import Literal, Union
from openapi_schema_pydantic import Discriminator
from pydantic import BaseModel, Field
class DataAModel(BaseModel):
kind: Literal["a"]
class DataBModel(BaseModel):
kind: Literal["b"]
class RequestModel(BaseModel):
data: Union[DataAModel, DataBModel] = Field(
...,
discriminator=Discriminator(
propertyName="kind",
mapping={
"a": "#/components/schemas/DataAModel",
"b": "#/components/schemas/DataBModel",
},
),
)
Now that discriminator
is reserved, this results in a TypeError on defining the class:
python repro.py
Traceback (most recent call last):
File "repro.py", line 15, in <module>
class RequestModel(BaseModel):
File "/home/tom/r/env/lib/python3.8/site-packages/pydantic/main.py", line 204, in __new__
fields[ann_name] = ModelField.infer(
File "/home/tom/r/env/lib/python3.8/site-packages/pydantic/fields.py", line 527, in infer
return cls(
File "/home/tom/r/env/lib/python3.8/site-packages/pydantic/fields.py", line 444, in __init__
self.prepare()
File "/home/tom/r/env/lib/python3.8/site-packages/pydantic/fields.py", line 577, in prepare
self._type_analysis()
File "/home/tom/r/env/lib/python3.8/site-packages/pydantic/fields.py", line 684, in _type_analysis
self.prepare_discriminated_union_sub_fields()
File "/home/tom/r/env/lib/python3.8/site-packages/pydantic/fields.py", line 824, in prepare_discriminated_union_sub_fields
alias, discriminator_values = get_discriminator_alias_and_values(
File "/home/tom/r/env/lib/python3.8/site-packages/pydantic/utils.py", line 733, in get_discriminator_alias_and_values
t_discriminator_type = tp.__fields__[discriminator_key].type_
TypeError: unhashable type: 'Discriminator'
Pydantic now expects discriminator
to be a string, specifying the field that contains the discriminating value (in this case, kind
). See the pydantic documentation on discriminated unions.
Would you accept a PR that adds an alias for this field, to still allow it to be loaded from the field definition - say, discriminatorMapping
?
I noticed that ref definitions are not present in the parse_obj result.
To reproduce:
from typing import *
from pydantic import Field
from openapi_schema_pydantic import OpenAPI
from pydantic.schema import schema as create_schema
schema = {
"info": {"title": "My own API", "version": "v0.0.1"},
"paths": {
"/ping": {
"post": {
"requestBody": {"content": {"application/json": {
"schema": ""
}}},
"responses": {"200": {"description": "pong"}
},
}
}
},
"components": {"schemas": {}}
}
schema["paths"]["/ping"]["post"]["requestBody"]["content"]["application/json"]["schema"] = DocumentPUTParameters.schema()
>>> DocumentPUTParameters.schema()
{'title': 'DocumentPUTParameters', 'type': 'object', 'properties': {'payment': {'$ref': '#/definitions/PaymentPUTParameters'}}, 'additionalProperties': False, 'definitions': {'PaymentPUTParameters': {'title': 'PaymentPUTParameters', 'type': 'object', 'properties': {'terms': {'title': 'Terms', 'example': '15 days', 'type': 'string'}}, 'additionalProperties': False}}}
>>> create_schema([DocumentPUTParameters], ref_prefix="#/components/schemas/" )
{'definitions': {'PaymentPUTParameters': {'title': 'PaymentPUTParameters', 'type': 'object', 'properties': {'terms': {'title': 'Terms', 'example': '15 days', 'type': 'string'}}, 'additionalProperties': False}, 'DocumentPUTParameters': {'title': 'DocumentPUTParameters', 'type': 'object', 'properties': {'payment': {'$ref': '#/components/schemas/PaymentPUTParameters'}}, 'additionalProperties': False}}}
schema
{'info': {'title': 'My own API', 'version': 'v0.0.1'}, 'paths': {'/ping': {'post': {'requestBody': {'content': {'application/json': {'schema': {'title': 'DocumentPUTParameters', 'type': 'object', 'properties': {'payment': {'$ref': '#/definitions/PaymentPUTParameters'}}, 'additionalProperties': False, 'definitions': {'PaymentPUTParameters': {'title': 'PaymentPUTParameters', 'type': 'object', 'properties': {'terms': {'title': 'Terms', 'example': '15 days', 'type': 'string'}}, 'additionalProperties': False}}}}}}, 'responses': {'200': {'description': 'pong'}}}}}, 'components': {'schemas': {}}}
>>>OpenAPI.parse_obj(schema)
OpenAPI(openapi='3.1.0', info=Info(title='My own API', summary=None, description=None, termsOfService=None, contact=None, license=None, version='v0.0.1'), jsonSchemaDialect=None, servers=[Server(url='/', description=None, variables=None)], paths={'/ping': PathItem(ref=None, summary=None, description=None, get=None, put=None, post=Operation(tags=None, summary=None, description=None, externalDocs=None, operationId=None, parameters=None, requestBody=RequestBody(description=None, content={'application/json': MediaType(media_type_schema=Schema(allOf=None, anyOf=None, oneOf=None, schema_not=None, schema_if=None, then=None, schema_else=None, dependentSchemas=None, prefixItems=None, items=None, contains=None, properties={'payment': Reference(ref='#/definitions/PaymentPUTParameters', summary=None, description=None)}, patternProperties=None, additionalProperties=False, propertyNames=None, unevaluatedItems=None, unevaluatedProperties=None, type='object', enum=None, const=None, multipleOf=None, maximum=None, exclusiveMaximum=None, minimum=None, exclusiveMinimum=None, maxLength=None, minLength=None, pattern=None, maxItems=None, minItems=None, uniqueItems=None, maxContains=None, minContains=None, maxProperties=None, minProperties=None, required=None, dependentRequired=None, schema_format=None, contentEncoding=None, contentMediaType=None, contentSchema=None, title='DocumentPUTParameters', description=None, default=None, deprecated=None, readOnly=None, writeOnly=None, examples=None, discriminator=None, xml=None, externalDocs=None, example=None), example=None, examples=None, encoding=None)}, required=False), responses={'200': Response(description='pong', headers=None, content=None, links=None)}, callbacks=None, deprecated=False, security=None, servers=None), delete=None, options=None, head=None, patch=None, trace=None, servers=None, parameters=None)}, webhooks=None, components=Components(schemas={}, responses=None, parameters=None, examples=None, requestBodies=None, headers=None, securitySchemes=None, links=None, callbacks=None, pathItems=None), security=None, tags=None, externalDocs=None)
As you can see, PaymentPUTParameters definition is missing from parse_obj result.
Hi, @kuimono. Due to various issues with typing and other implementation details we forked this library, on which we rely. This is our fork: https://github.com/starlite-api/pydantic-openapi-schema, you can see the the commit history. Please let me know if you would like to merge our changes (disregard the README changes, and some of the CI components, these we can drop).
If yes, I'll prepare a PR. We will release our fork as a separate package but will gladly merge back our improvements upstream.
There doesn't seem to have been any activity on this repo for a while @kuimono - are you still able to maintain it? I'd be happy to help or take it on if not
We had a user open this issue:
… and traced the cause back to here.
From docs for logging.debug()
:
This function (as well as info(), warning(), error() and critical()) will call basicConfig() if the root logger doesn’t have any handler attached.
So instead of logging.info(…)
, it is better to instantiate a named logger for your library, e.g.:
import logging
logger = logging.getLogger(__name__)
logger.debug(…)
Would you accept a PR?
I'm not sure if this is an "issue". In fact I don't think it is, but this is a use case scenario.
Our input variables are actually defined as pydantic schema objects.
My goal is to have a query input schema type map to openapi valid json ...
This (lovely) library offers the PydanticSchema class that handles a type, but is there a way to generate the params ONLY from an input schema type?
Thanks!
Hi!
Can you change the version of pydantic in the dependencies? There is a vulnerability in this version.
https://nvd.nist.gov/vuln/detail/CVE-2021-29510
See https://json-schema.org/draft/2020-12/json-schema-core.html#rfc.section.4.3.2 on the 2020-12 Draft, the values false
and true
are valid JSON Schemas.
Unless I'm mistaken, I think the Schema
model (in v3.1.0, not sure if this applies to v3.0.1) should support bool
as a type in all instances where Schema
is allowed. E.g. change Union[Reference, "Schema"]
to Union[Reference, "Schema", bool]
.
Without the support of boolean schemas, using Pydantic classes as schemas fails if the Pydantic schema is configured with extra = False
as this sets "additionalProperties": false
on the schema, but your model is only accepting Union[Reference, "Schema"]
.
First off, thanks for this great project!
It's great that this project has extensive typing support and a py.typed
marker. The only missing part is that the marker is not included in the distributed package.
Ref: https://mypy.readthedocs.io/en/stable/installed_packages.html#creating-pep-561-compatible-packages
I'll happily open a PR to include it!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.