Skip to content

OpenAPI 3.0.4 and 3.1.1 support #48

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

Merged
merged 2 commits into from
Nov 4, 2024
Merged
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
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
OpenAPI schema implemented in [Pydantic](https://github.com/samuelcolvin/pydantic). Both Pydantic 1.8+ and 2.x are supported.

The naming of the classes follows the schema in
[OpenAPI specification](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#schema).
[OpenAPI specification](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.1.md#schema).

> This library is forked from [OpenAPI Schema Pydantic](https://github.com/kuimono/openapi-schema-pydantic) (at version [1.2.4](https://github.com/kuimono/openapi-schema-pydantic/releases/tag/v1.2.4)) which is no longer actively maintained.

Expand Down Expand Up @@ -45,7 +45,7 @@ Result:

```json
{
"openapi": "3.1.0",
"openapi": "3.1.1",
"info": {
"title": "My own API",
"version": "v0.0.1"
Expand Down Expand Up @@ -81,7 +81,7 @@ from openapi_pydantic import parse_obj, OpenAPI, PathItem, Response

# Construct OpenAPI from dict, inferring the correct schema version
open_api = parse_obj({
"openapi": "3.1.0",
"openapi": "3.1.1",
"info": {"title": "My own API", "version": "v0.0.1"},
"paths": {
"/ping": {
Expand All @@ -91,7 +91,7 @@ open_api = parse_obj({
})


# Construct OpenAPI v3.1.0 schema from dict
# Construct OpenAPI v3.1 schema from dict
# Note: for Pydantic 1.x, replace `model_validate` with `parse_obj`
open_api = OpenAPI.model_validate({
"info": {"title": "My own API", "version": "v0.0.1"},
Expand All @@ -116,7 +116,7 @@ open_api = OpenAPI.model_validate({

## Use Pydantic classes as schema

- The [Schema Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#schemaObject)
- The [Schema Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.4.md#schemaObject)
in OpenAPI has definitions and tweaks in JSON Schema, which are hard to comprehend and define a good data class
- Pydantic already has a good way to [create JSON schema](https://pydantic-docs.helpmanual.io/usage/schema/).
Let's not reinvent the wheel.
Expand Down Expand Up @@ -175,7 +175,7 @@ Result:

```json
{
"openapi": "3.1.0",
"openapi": "3.1.1",
"info": {
"title": "My own API",
"version": "v0.0.1"
Expand Down Expand Up @@ -286,8 +286,8 @@ More info about field aliases:

| OpenAPI version | Field alias info |
| --------------- | ---------------- |
| 3.1.0 | [here](https://github.com/mike-oakley/openapi-pydantic/blob/main/openapi_pydantic/v3/v3_1_0/README.md#alias) |
| 3.0.3 | [here](https://github.com/mike-oakley/openapi-pydantic/blob/main/openapi_pydantic/v3/v3_0_3/README.md#alias) |
| 3.1 | [here](https://github.com/mike-oakley/openapi-pydantic/blob/main/openapi_pydantic/v3/v3_1/README.md#alias) |
| 3.0 | [here](https://github.com/mike-oakley/openapi-pydantic/blob/main/openapi_pydantic/v3/v3_0/README.md#alias) |

### Non-pydantic schema types

Expand All @@ -296,17 +296,17 @@ Please refer to the following for more info:

| OpenAPI version | Non-pydantic schema type info |
| --------------- | ----------------------------- |
| 3.1.0 | [here](https://github.com/mike-oakley/openapi-pydantic/blob/main/openapi_pydantic/v3/v3_1_0/README.md#non-pydantic-schema-types) |
| 3.0.3 | [here](https://github.com/mike-oakley/openapi-pydantic/blob/main/openapi_pydantic/v3/v3_0_3/README.md#non-pydantic-schema-types) |
| 3.1 | [here](https://github.com/mike-oakley/openapi-pydantic/blob/main/openapi_pydantic/v3/v3_1/README.md#non-pydantic-schema-types) |
| 3.0 | [here](https://github.com/mike-oakley/openapi-pydantic/blob/main/openapi_pydantic/v3/v3_0/README.md#non-pydantic-schema-types) |

### Use OpenAPI 3.0.3 instead of 3.1.0
### Use OpenAPI 3.0 instead of 3.1

Some UI renderings (e.g. Swagger) still do not support OpenAPI 3.1.0.
The old 3.0.3 version is available by importing from different paths:
Some UI renderings (e.g. Swagger) still do not support OpenAPI 3.1.x.
The old 3.0.x version is available by importing from different paths:

```python
from openapi_pydantic.v3.v3_0_3 import OpenAPI, ...
from openapi_pydantic.v3.v3_0_3.util import PydanticSchema, construct_open_api_with_schema_class
from openapi_pydantic.v3.v3_0 import OpenAPI, ...
from openapi_pydantic.v3.v3_0.util import PydanticSchema, construct_open_api_with_schema_class
```

### Pydantic version compatibility
Expand Down
66 changes: 33 additions & 33 deletions openapi_pydantic/v3/__init__.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
from .parser import parse_obj as parse_obj
from .v3_1_0 import XML as XML
from .v3_1_0 import Callback as Callback
from .v3_1_0 import Components as Components
from .v3_1_0 import Contact as Contact
from .v3_1_0 import DataType as DataType
from .v3_1_0 import Discriminator as Discriminator
from .v3_1_0 import Encoding as Encoding
from .v3_1_0 import Example as Example
from .v3_1_0 import ExternalDocumentation as ExternalDocumentation
from .v3_1_0 import Header as Header
from .v3_1_0 import Info as Info
from .v3_1_0 import License as License
from .v3_1_0 import Link as Link
from .v3_1_0 import MediaType as MediaType
from .v3_1_0 import OAuthFlow as OAuthFlow
from .v3_1_0 import OAuthFlows as OAuthFlows
from .v3_1_0 import OpenAPI as OpenAPI
from .v3_1_0 import Operation as Operation
from .v3_1_0 import Parameter as Parameter
from .v3_1_0 import ParameterLocation as ParameterLocation
from .v3_1_0 import PathItem as PathItem
from .v3_1_0 import Paths as Paths
from .v3_1_0 import Reference as Reference
from .v3_1_0 import RequestBody as RequestBody
from .v3_1_0 import Response as Response
from .v3_1_0 import Responses as Responses
from .v3_1_0 import Schema as Schema
from .v3_1_0 import SecurityRequirement as SecurityRequirement
from .v3_1_0 import SecurityScheme as SecurityScheme
from .v3_1_0 import Server as Server
from .v3_1_0 import ServerVariable as ServerVariable
from .v3_1_0 import Tag as Tag
from .v3_1_0 import schema_validate as schema_validate
from .v3_1 import XML as XML
from .v3_1 import Callback as Callback
from .v3_1 import Components as Components
from .v3_1 import Contact as Contact
from .v3_1 import DataType as DataType
from .v3_1 import Discriminator as Discriminator
from .v3_1 import Encoding as Encoding
from .v3_1 import Example as Example
from .v3_1 import ExternalDocumentation as ExternalDocumentation
from .v3_1 import Header as Header
from .v3_1 import Info as Info
from .v3_1 import License as License
from .v3_1 import Link as Link
from .v3_1 import MediaType as MediaType
from .v3_1 import OAuthFlow as OAuthFlow
from .v3_1 import OAuthFlows as OAuthFlows
from .v3_1 import OpenAPI as OpenAPI
from .v3_1 import Operation as Operation
from .v3_1 import Parameter as Parameter
from .v3_1 import ParameterLocation as ParameterLocation
from .v3_1 import PathItem as PathItem
from .v3_1 import Paths as Paths
from .v3_1 import Reference as Reference
from .v3_1 import RequestBody as RequestBody
from .v3_1 import Response as Response
from .v3_1 import Responses as Responses
from .v3_1 import Schema as Schema
from .v3_1 import SecurityRequirement as SecurityRequirement
from .v3_1 import SecurityScheme as SecurityScheme
from .v3_1 import Server as Server
from .v3_1 import ServerVariable as ServerVariable
from .v3_1 import Tag as Tag
from .v3_1 import schema_validate as schema_validate
4 changes: 2 additions & 2 deletions openapi_pydantic/v3/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

from openapi_pydantic.compat import PYDANTIC_V2

from .v3_0_3 import OpenAPI as OpenAPIv3_0
from .v3_1_0 import OpenAPI as OpenAPIv3_1
from .v3_0 import OpenAPI as OpenAPIv3_0
from .v3_1 import OpenAPI as OpenAPIv3_1

OpenAPIv3 = Union[OpenAPIv3_1, OpenAPIv3_0]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# OpenAPI v3.0.3 schema classes
# OpenAPI v3.0 schema classes

## Alias

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""
OpenAPI v3.1.0 schema types, created according to the specification:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md
OpenAPI v3.0 schema types, created according to the specification:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.4.md

The type orders are according to the contents of the specification:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#table-of-contents
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.4.md#table-of-contents
"""

from typing import TYPE_CHECKING
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
class OpenAPI(BaseModel):
"""This is the root document object of the OpenAPI document."""

openapi: Literal["3.0.3", "3.0.2", "3.0.1", "3.0.0"] = "3.0.3"
openapi: Literal["3.0.4", "3.0.3", "3.0.2", "3.0.1", "3.0.0"] = "3.0.4"
"""
**REQUIRED**. This string MUST be the [semantic version number](https://semver.org/spec/v2.0.0.html)
of the [OpenAPI Specification version](#versions) that the OpenAPI document uses.
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# OpenAPI v3.1.0 schema classes
# OpenAPI v3.1 schema classes

## Alias

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""
OpenAPI v3.0.3 schema types, created according to the specification:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md
OpenAPI v3.1 schema types, created according to the specification:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.1.md

The type orders are according to the contents of the specification:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#table-of-contents
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.1.md#table-of-contents
"""

from typing import TYPE_CHECKING
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
class OpenAPI(BaseModel):
"""This is the root document object of the OpenAPI document."""

openapi: Literal["3.1.0"] = "3.1.0"
openapi: Literal["3.1.1", "3.1.0"] = "3.1.1"
"""
**REQUIRED**. This string MUST be the [version number](#versions)
of the OpenAPI Specification that the OpenAPI document uses.
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
50 changes: 23 additions & 27 deletions tests/test_openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import pytest

from openapi_pydantic.compat import PYDANTIC_V2
from openapi_pydantic.v3 import v3_0_3, v3_1_0
from openapi_pydantic.v3 import v3_0, v3_1


@pytest.mark.parametrize("version", ["3.0.3", "3.1.0"])
@pytest.mark.parametrize("version", ["3.0.4", "3.1.1"])
def test_parse_with_callback(version: str) -> None:
data = {
"openapi": version,
Expand All @@ -29,24 +29,22 @@ def test_parse_with_callback(version: str) -> None:
},
}

if version == "3.0.3":
model_validate_3_0: Callable[[dict], v3_0_3.OpenAPI] = getattr(
v3_0_3.OpenAPI, "model_validate" if PYDANTIC_V2 else "parse_obj"
if version == "3.0.4":
model_validate_3_0: Callable[[dict], v3_0.OpenAPI] = getattr(
v3_0.OpenAPI, "model_validate" if PYDANTIC_V2 else "parse_obj"
)
assert model_validate_3_0(data) == v3_0_3.OpenAPI(
info=v3_0_3.Info(title="API with Callback", version=""),
assert model_validate_3_0(data) == v3_0.OpenAPI(
info=v3_0.Info(title="API with Callback", version=""),
paths={
"/create": v3_0_3.PathItem(
post=v3_0_3.Operation(
responses={"200": v3_0_3.Response(description="Success")},
"/create": v3_0.PathItem(
post=v3_0.Operation(
responses={"200": v3_0.Response(description="Success")},
callbacks={
"event": {
"callback": v3_0_3.PathItem(
post=v3_0_3.Operation(
"callback": v3_0.PathItem(
post=v3_0.Operation(
responses={
"200": v3_0_3.Response(
description="Success"
)
"200": v3_0.Response(description="Success")
}
)
)
Expand All @@ -57,23 +55,21 @@ def test_parse_with_callback(version: str) -> None:
},
)
else:
model_validate_3_1: Callable[[dict], v3_1_0.OpenAPI] = getattr(
v3_1_0.OpenAPI, "model_validate" if PYDANTIC_V2 else "parse_obj"
model_validate_3_1: Callable[[dict], v3_1.OpenAPI] = getattr(
v3_1.OpenAPI, "model_validate" if PYDANTIC_V2 else "parse_obj"
)
assert model_validate_3_1(data) == v3_1_0.OpenAPI(
info=v3_1_0.Info(title="API with Callback", version=""),
assert model_validate_3_1(data) == v3_1.OpenAPI(
info=v3_1.Info(title="API with Callback", version=""),
paths={
"/create": v3_1_0.PathItem(
post=v3_1_0.Operation(
responses={"200": v3_1_0.Response(description="Success")},
"/create": v3_1.PathItem(
post=v3_1.Operation(
responses={"200": v3_1.Response(description="Success")},
callbacks={
"event": {
"callback": v3_1_0.PathItem(
post=v3_1_0.Operation(
"callback": v3_1.PathItem(
post=v3_1.Operation(
responses={
"200": v3_1_0.Response(
description="Success"
)
"200": v3_1.Response(description="Success")
}
)
)
Expand Down
27 changes: 15 additions & 12 deletions tests/test_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import pytest

from openapi_pydantic import parse_obj
from openapi_pydantic.v3 import v3_0_3, v3_1_0
from openapi_pydantic.v3 import v3_0, v3_1


@pytest.mark.parametrize("version", ["3.0.3", "3.0.2", "3.0.1", "3.0.0"])
def test_parse_obj_3_0_3(version: Literal["3.0.3", "3.0.2", "3.0.1", "3.0.0"]) -> None:
@pytest.mark.parametrize("version", ["3.0.4", "3.0.3", "3.0.2", "3.0.1", "3.0.0"])
def test_parse_obj_3_0(
version: Literal["3.0.4", "3.0.3", "3.0.2", "3.0.1", "3.0.0"]
) -> None:
result = parse_obj(
{
"openapi": version,
Expand All @@ -16,24 +18,25 @@ def test_parse_obj_3_0_3(version: Literal["3.0.3", "3.0.2", "3.0.1", "3.0.0"]) -
}
)

assert result == v3_0_3.OpenAPI(
assert result == v3_0.OpenAPI(
openapi=version,
info=v3_0_3.Info(title="foo", version="0.1.0"),
paths={"/": v3_0_3.PathItem()},
info=v3_0.Info(title="foo", version="0.1.0"),
paths={"/": v3_0.PathItem()},
)


def test_parse_obj_3_1_0() -> None:
@pytest.mark.parametrize("version", ["3.1.1", "3.1.0"])
def test_parse_obj_3_1(version: Literal["3.1.1", "3.1.0"]) -> None:
result = parse_obj(
{
"openapi": "3.1.0",
"openapi": version,
"info": {"title": "foo", "version": "0.1.0"},
"paths": {"/": {}},
}
)

assert result == v3_1_0.OpenAPI(
openapi="3.1.0",
info=v3_1_0.Info(title="foo", version="0.1.0"),
paths={"/": v3_1_0.PathItem()},
assert result == v3_1.OpenAPI(
openapi=version,
info=v3_1.Info(title="foo", version="0.1.0"),
paths={"/": v3_1.PathItem()},
)
2 changes: 1 addition & 1 deletion tests/test_swagger_openapi_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from pydantic import Field

from openapi_pydantic.compat import PYDANTIC_V2, ConfigDict
from openapi_pydantic.v3.v3_0_3 import OpenAPI, Operation, PathItem
from openapi_pydantic.v3.v3_0 import OpenAPI, Operation, PathItem


def test_swagger_openapi_v3() -> None:
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Any

from openapi_pydantic.compat import PYDANTIC_V2
from openapi_pydantic.v3.v3_0_3 import (
from openapi_pydantic.v3.v3_0 import (
XML,
Callback,
Components,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest
from pydantic import ValidationError

from openapi_pydantic.v3.v3_0_3 import Schema
from openapi_pydantic.v3.v3_0 import Schema


@pytest.mark.parametrize(
Expand Down
Loading
Loading