Skip to content

Commit

Permalink
Merge pull request #48 from mike-oakley/u/mike/oas-bump
Browse files Browse the repository at this point in the history
OpenAPI 3.0.4 and 3.1.1 support
  • Loading branch information
mike-oakley authored Nov 4, 2024
2 parents e93752c + 238019e commit 3c068e9
Show file tree
Hide file tree
Showing 81 changed files with 109 additions and 110 deletions.
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.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
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
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.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
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.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
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
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.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
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

0 comments on commit 3c068e9

Please sign in to comment.