11"""Core apispec classes and functions."""
22
33from __future__ import annotations
4- from collections .abc import Sequence
5-
64
7- import typing
5+ from collections . abc import Sequence
86from copy import deepcopy
97import warnings
8+ import typing
9+
10+ from packaging .version import Version
1011
1112from .exceptions import (
1213 APISpecError ,
1516 DuplicateParameterError ,
1617 InvalidParameterError ,
1718)
18- from .utils import OpenAPIVersion , deepupdate , COMPONENT_SUBSECTIONS , build_reference
19+ from .utils import deepupdate , COMPONENT_SUBSECTIONS , build_reference
1920
2021if typing .TYPE_CHECKING :
2122 from .plugin import BasePlugin
2728
2829VALID_METHODS = {2 : VALID_METHODS_OPENAPI_V2 , 3 : VALID_METHODS_OPENAPI_V3 }
2930
31+ MIN_INCLUSIVE_OPENAPI_VERSION = Version ("2.0" )
32+ MAX_EXCLUSIVE_OPENAPI_VERSION = Version ("4.0" )
33+
3034
3135class Components :
3236 """Stores OpenAPI components
@@ -38,7 +42,7 @@ class Components:
3842 def __init__ (
3943 self ,
4044 plugins : Sequence [BasePlugin ],
41- openapi_version : OpenAPIVersion ,
45+ openapi_version : Version ,
4246 ) -> None :
4347 self ._plugins = plugins
4448 self .openapi_version = openapi_version
@@ -405,7 +409,7 @@ class APISpec:
405409 :param str version: API version
406410 :param list|tuple plugins: Plugin instances.
407411 See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#infoObject
408- :param str|OpenAPIVersion openapi_version: OpenAPI Specification version.
412+ :param str openapi_version: OpenAPI Specification version.
409413 Should be in the form '2.x' or '3.x.x' to comply with the OpenAPI standard.
410414 :param options: Optional top-level keys
411415 See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#openapi-object
@@ -415,15 +419,21 @@ def __init__(
415419 self ,
416420 title : str ,
417421 version : str ,
418- openapi_version : OpenAPIVersion | str ,
422+ openapi_version : str ,
419423 plugins : Sequence [BasePlugin ] = (),
420424 ** options : typing .Any ,
421425 ) -> None :
422426 self .title = title
423427 self .version = version
424- self .openapi_version = OpenAPIVersion (openapi_version )
425428 self .options = options
426429 self .plugins = plugins
430+ self .openapi_version = Version (openapi_version )
431+ if not (
432+ MIN_INCLUSIVE_OPENAPI_VERSION
433+ <= self .openapi_version
434+ < MAX_EXCLUSIVE_OPENAPI_VERSION
435+ ):
436+ raise APISpecError (f"Not a valid OpenAPI version number: { openapi_version } " )
427437
428438 # Metadata
429439 self ._tags : list [dict ] = []
@@ -444,10 +454,10 @@ def to_dict(self) -> dict[str, typing.Any]:
444454 if self ._tags :
445455 ret ["tags" ] = self ._tags
446456 if self .openapi_version .major < 3 :
447- ret ["swagger" ] = self .openapi_version . vstring
457+ ret ["swagger" ] = str ( self .openapi_version )
448458 ret .update (self .components .to_dict ())
449459 else :
450- ret ["openapi" ] = self .openapi_version . vstring
460+ ret ["openapi" ] = str ( self .openapi_version )
451461 components_dict = self .components .to_dict ()
452462 if components_dict :
453463 ret ["components" ] = components_dict
0 commit comments