pydantic-openapi-generator 2.3.0__tar.gz → 2.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/PKG-INFO +2 -1
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/pyproject.toml +2 -1
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/__main__.py +8 -0
- pydantic_openapi_generator-2.5.0/src/pydantic_openapi_generator/config/__init__.py +5 -0
- pydantic_openapi_generator-2.5.0/src/pydantic_openapi_generator/config/base_parameter.py +73 -0
- pydantic_openapi_generator-2.5.0/src/pydantic_openapi_generator/config/class_var_parameter.py +60 -0
- pydantic_openapi_generator-2.5.0/src/pydantic_openapi_generator/config/function_parameter.py +47 -0
- pydantic_openapi_generator-2.5.0/src/pydantic_openapi_generator/config/generator_config.py +33 -0
- pydantic_openapi_generator-2.5.0/src/pydantic_openapi_generator/config/kwarg_parameter.py +56 -0
- pydantic_openapi_generator-2.5.0/src/pydantic_openapi_generator/config/loader.py +17 -0
- pydantic_openapi_generator-2.5.0/src/pydantic_openapi_generator/config/parameter_source.py +7 -0
- pydantic_openapi_generator-2.5.0/src/pydantic_openapi_generator/config/parameter_union.py +16 -0
- pydantic_openapi_generator-2.5.0/src/pydantic_openapi_generator/config/utils.py +56 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/generate_data.py +7 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/client_generator.py +266 -9
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/generator.py +5 -1
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/templates/async_client_httpx_pydantic_2.jinja2 +86 -25
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/templates/sync_client_httpx_pydantic_2.jinja2 +86 -25
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/models.py +32 -3
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/parsers/openapi_30.py +5 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/parsers/openapi_31.py +5 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/.gitignore +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/LICENSE +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/README.md +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/__init__.py +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/common.py +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/__init__.py +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/__init__.py +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/common.py +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/exception_generator.py +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/jinja_config.py +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/model_generator.py +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/templates/alias_union.jinja2 +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/templates/discriminator_enum.jinja2 +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/templates/enum.jinja2 +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/templates/http_exception.jinja2 +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/templates/models.jinja2 +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/language_converters/python/templates/models_pydantic_2.jinja2 +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/parsers/__init__.py +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/py.typed +0 -0
- {pydantic_openapi_generator-2.3.0 → pydantic_openapi_generator-2.5.0}/src/pydantic_openapi_generator/version_detector.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pydantic-openapi-generator
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.0
|
|
4
4
|
Summary: Openapi Python Generator
|
|
5
5
|
Project-URL: Homepage, https://github.com/mattcoulter7/pydantic-openapi-generator
|
|
6
6
|
Project-URL: Repository, https://github.com/mattcoulter7/pydantic-openapi-generator
|
|
@@ -20,6 +20,7 @@ Requires-Dist: isort>=5.10.1
|
|
|
20
20
|
Requires-Dist: jinja2<4,>=3.1.2
|
|
21
21
|
Requires-Dist: openapi-pydantic<0.6,>=0.5.1
|
|
22
22
|
Requires-Dist: orjson<4,>=3.9.15
|
|
23
|
+
Requires-Dist: pydantic-di>=0.3.1
|
|
23
24
|
Requires-Dist: pydantic<3,>=2.10.2
|
|
24
25
|
Requires-Dist: pyyaml<7,>=6.0.2
|
|
25
26
|
Description-Content-Type: text/markdown
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pydantic-openapi-generator"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.5.0"
|
|
4
4
|
description = "Openapi Python Generator"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Marco Müllner", email = "muellnermarco@gmail.com" },
|
|
@@ -27,6 +27,7 @@ dependencies = [
|
|
|
27
27
|
"openapi-pydantic>=0.5.1,<0.6",
|
|
28
28
|
"pyyaml>=6.0.2,<7",
|
|
29
29
|
"importlib-metadata>=8.7.0,<9",
|
|
30
|
+
"pydantic-di>=0.3.1",
|
|
30
31
|
]
|
|
31
32
|
|
|
32
33
|
[project.urls]
|
|
@@ -52,6 +52,12 @@ from pydantic_openapi_generator.generate_data import generate_data
|
|
|
52
52
|
show_default=True,
|
|
53
53
|
help="Option to choose which auto formatter is applied.",
|
|
54
54
|
)
|
|
55
|
+
@click.option(
|
|
56
|
+
"--config-path",
|
|
57
|
+
type=click.Path(exists=True, dir_okay=False),
|
|
58
|
+
default=None,
|
|
59
|
+
help="Optional YAML configuration for generated client parameters.",
|
|
60
|
+
)
|
|
55
61
|
@click.version_option(version=__version__)
|
|
56
62
|
def main(
|
|
57
63
|
source: str,
|
|
@@ -62,6 +68,7 @@ def main(
|
|
|
62
68
|
custom_template_path: Optional[str] = None,
|
|
63
69
|
pydantic_version: PydanticVersion = PydanticVersion.V2,
|
|
64
70
|
formatter: Formatter = Formatter.BLACK,
|
|
71
|
+
config_path: Optional[str] = None,
|
|
65
72
|
) -> None:
|
|
66
73
|
"""
|
|
67
74
|
Generate Python code from an OpenAPI 3.0+ specification.
|
|
@@ -78,6 +85,7 @@ def main(
|
|
|
78
85
|
custom_template_path,
|
|
79
86
|
pydantic_version,
|
|
80
87
|
formatter,
|
|
88
|
+
config_path,
|
|
81
89
|
)
|
|
82
90
|
|
|
83
91
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, ConfigDict
|
|
5
|
+
|
|
6
|
+
from pydantic_openapi_generator.config.utils import Parameter, parameter_base_type_hint
|
|
7
|
+
from pydantic_openapi_generator.language_converters.python import common
|
|
8
|
+
from pydantic_openapi_generator.models import GeneratedParameter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseArgumentConfiguration(BaseModel, ABC):
|
|
12
|
+
model_config = ConfigDict(extra="forbid")
|
|
13
|
+
|
|
14
|
+
name: str
|
|
15
|
+
code_name: Optional[str] = None
|
|
16
|
+
|
|
17
|
+
def resolve_parameter(self, param: Parameter) -> GeneratedParameter:
|
|
18
|
+
code_name = self.resolved_code_name(param)
|
|
19
|
+
type_hint, default = self.method_type_and_default(param)
|
|
20
|
+
|
|
21
|
+
return GeneratedParameter(
|
|
22
|
+
wire_name=param.name,
|
|
23
|
+
code_name=code_name,
|
|
24
|
+
location=param.param_in, # type: ignore[arg-type]
|
|
25
|
+
type_hint=type_hint,
|
|
26
|
+
base_type_hint=parameter_base_type_hint(param),
|
|
27
|
+
required=param.required,
|
|
28
|
+
default=default,
|
|
29
|
+
source=self.type, # type: ignore[attr-defined]
|
|
30
|
+
is_secret=self.is_secret_parameter(),
|
|
31
|
+
field_type_hint=self.field_type_hint(param),
|
|
32
|
+
field_default=self.field_default(param),
|
|
33
|
+
getter_name=self.getter_name(code_name),
|
|
34
|
+
local_name=self.local_name(code_name),
|
|
35
|
+
value_expression=self.value_expression(code_name),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def resolved_code_name(self, param: Parameter) -> str:
|
|
39
|
+
if self.code_name:
|
|
40
|
+
return common.normalize_symbol(self.code_name)
|
|
41
|
+
return self.default_code_name(param.name)
|
|
42
|
+
|
|
43
|
+
@abstractmethod
|
|
44
|
+
def default_code_name(self, param_name: str) -> str:
|
|
45
|
+
raise NotImplementedError
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def method_type_and_default(self, param: Parameter) -> tuple[str, Optional[str]]:
|
|
49
|
+
raise NotImplementedError
|
|
50
|
+
|
|
51
|
+
@abstractmethod
|
|
52
|
+
def field_type_hint(self, param: Parameter) -> Optional[str]:
|
|
53
|
+
raise NotImplementedError
|
|
54
|
+
|
|
55
|
+
@abstractmethod
|
|
56
|
+
def field_default(self, param: Parameter) -> Optional[str]:
|
|
57
|
+
raise NotImplementedError
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def getter_name(self, code_name: str) -> Optional[str]:
|
|
61
|
+
raise NotImplementedError
|
|
62
|
+
|
|
63
|
+
@abstractmethod
|
|
64
|
+
def local_name(self, code_name: str) -> Optional[str]:
|
|
65
|
+
raise NotImplementedError
|
|
66
|
+
|
|
67
|
+
@abstractmethod
|
|
68
|
+
def value_expression(self, code_name: str) -> str:
|
|
69
|
+
raise NotImplementedError
|
|
70
|
+
|
|
71
|
+
@abstractmethod
|
|
72
|
+
def is_secret_parameter(self) -> bool:
|
|
73
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from typing import Literal, Optional, override
|
|
2
|
+
|
|
3
|
+
from pydantic_openapi_generator.config.base_parameter import (
|
|
4
|
+
BaseArgumentConfiguration,
|
|
5
|
+
)
|
|
6
|
+
from pydantic_openapi_generator.config.parameter_source import ParameterSource
|
|
7
|
+
from pydantic_openapi_generator.config.utils import (
|
|
8
|
+
Parameter,
|
|
9
|
+
lower_code_name,
|
|
10
|
+
optional_override_type_and_default,
|
|
11
|
+
optional_type,
|
|
12
|
+
parameter_base_type_hint,
|
|
13
|
+
parameter_default,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ClassVarArgumentConfiguration(BaseArgumentConfiguration):
|
|
18
|
+
type: Literal[ParameterSource.CLASS_VAR] = ParameterSource.CLASS_VAR
|
|
19
|
+
is_secret: bool = False
|
|
20
|
+
|
|
21
|
+
@override
|
|
22
|
+
def default_code_name(self, param_name: str) -> str:
|
|
23
|
+
return lower_code_name(param_name)
|
|
24
|
+
|
|
25
|
+
@override
|
|
26
|
+
def method_type_and_default(self, param: Parameter) -> tuple[str, Optional[str]]:
|
|
27
|
+
return optional_override_type_and_default(param)
|
|
28
|
+
|
|
29
|
+
@override
|
|
30
|
+
def field_type_hint(self, param: Parameter) -> str:
|
|
31
|
+
default = parameter_default(param)
|
|
32
|
+
base_type = "SecretStr" if self.is_secret else parameter_base_type_hint(param)
|
|
33
|
+
|
|
34
|
+
if param.required or default is not None:
|
|
35
|
+
return base_type
|
|
36
|
+
|
|
37
|
+
return optional_type(base_type)
|
|
38
|
+
|
|
39
|
+
@override
|
|
40
|
+
def field_default(self, param: Parameter) -> Optional[str]:
|
|
41
|
+
default = parameter_default(param)
|
|
42
|
+
if param.required:
|
|
43
|
+
return None
|
|
44
|
+
return default if default is not None else "None"
|
|
45
|
+
|
|
46
|
+
@override
|
|
47
|
+
def getter_name(self, code_name: str) -> Optional[str]:
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
@override
|
|
51
|
+
def local_name(self, code_name: str) -> str:
|
|
52
|
+
return f"_{code_name}"
|
|
53
|
+
|
|
54
|
+
@override
|
|
55
|
+
def value_expression(self, code_name: str) -> str:
|
|
56
|
+
return self.local_name(code_name)
|
|
57
|
+
|
|
58
|
+
@override
|
|
59
|
+
def is_secret_parameter(self) -> bool:
|
|
60
|
+
return self.is_secret
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from typing import Literal, Optional, override
|
|
2
|
+
|
|
3
|
+
from pydantic_openapi_generator.config.base_parameter import (
|
|
4
|
+
BaseArgumentConfiguration,
|
|
5
|
+
)
|
|
6
|
+
from pydantic_openapi_generator.config.parameter_source import ParameterSource
|
|
7
|
+
from pydantic_openapi_generator.config.utils import (
|
|
8
|
+
Parameter,
|
|
9
|
+
lower_code_name,
|
|
10
|
+
optional_override_type_and_default,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FunctionArgumentConfiguration(BaseArgumentConfiguration):
|
|
15
|
+
type: Literal[ParameterSource.FUNCTION] = ParameterSource.FUNCTION
|
|
16
|
+
|
|
17
|
+
@override
|
|
18
|
+
def default_code_name(self, param_name: str) -> str:
|
|
19
|
+
return lower_code_name(param_name)
|
|
20
|
+
|
|
21
|
+
@override
|
|
22
|
+
def method_type_and_default(self, param: Parameter) -> tuple[str, Optional[str]]:
|
|
23
|
+
return optional_override_type_and_default(param)
|
|
24
|
+
|
|
25
|
+
@override
|
|
26
|
+
def field_type_hint(self, param: Parameter) -> Optional[str]:
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
@override
|
|
30
|
+
def field_default(self, param: Parameter) -> Optional[str]:
|
|
31
|
+
return None
|
|
32
|
+
|
|
33
|
+
@override
|
|
34
|
+
def getter_name(self, code_name: str) -> str:
|
|
35
|
+
return f"get_{code_name}"
|
|
36
|
+
|
|
37
|
+
@override
|
|
38
|
+
def local_name(self, code_name: str) -> str:
|
|
39
|
+
return f"_{code_name}"
|
|
40
|
+
|
|
41
|
+
@override
|
|
42
|
+
def value_expression(self, code_name: str) -> str:
|
|
43
|
+
return self.local_name(code_name)
|
|
44
|
+
|
|
45
|
+
@override
|
|
46
|
+
def is_secret_parameter(self) -> bool:
|
|
47
|
+
return False
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
2
|
+
|
|
3
|
+
from pydantic_openapi_generator.config.base_parameter import BaseArgumentConfiguration
|
|
4
|
+
from pydantic_openapi_generator.config.kwarg_parameter import KwargArgumentConfiguration
|
|
5
|
+
from pydantic_openapi_generator.config.parameter_union import ArgumentConfiguration
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PydanticOpenAPIGeneratorConfig(BaseModel):
|
|
9
|
+
model_config = ConfigDict(extra="forbid")
|
|
10
|
+
|
|
11
|
+
parameters: list[ArgumentConfiguration] = Field(default_factory=list)
|
|
12
|
+
|
|
13
|
+
def parameter_configuration_for(self, parameter_name: str) -> BaseArgumentConfiguration:
|
|
14
|
+
configured = self.parameters_by_name().get(parameter_name)
|
|
15
|
+
return configured if configured is not None else KwargArgumentConfiguration(name=parameter_name)
|
|
16
|
+
|
|
17
|
+
def parameters_by_name(self) -> dict[str, ArgumentConfiguration]:
|
|
18
|
+
return {parameter.name: parameter for parameter in self.parameters}
|
|
19
|
+
|
|
20
|
+
@model_validator(mode="after")
|
|
21
|
+
def validate_unique_parameter_names(self) -> "PydanticOpenAPIGeneratorConfig":
|
|
22
|
+
names: set[str] = set()
|
|
23
|
+
duplicates: set[str] = set()
|
|
24
|
+
for parameter in self.parameters:
|
|
25
|
+
if parameter.name in names:
|
|
26
|
+
duplicates.add(parameter.name)
|
|
27
|
+
names.add(parameter.name)
|
|
28
|
+
|
|
29
|
+
if duplicates:
|
|
30
|
+
duplicate_list = ", ".join(sorted(duplicates))
|
|
31
|
+
raise ValueError(f"Duplicate parameter configuration for: {duplicate_list}")
|
|
32
|
+
|
|
33
|
+
return self
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from typing import Literal, Optional, override
|
|
2
|
+
|
|
3
|
+
from pydantic_openapi_generator.config.base_parameter import BaseArgumentConfiguration
|
|
4
|
+
from pydantic_openapi_generator.config.parameter_source import ParameterSource
|
|
5
|
+
from pydantic_openapi_generator.config.utils import (
|
|
6
|
+
Parameter,
|
|
7
|
+
optional_type,
|
|
8
|
+
parameter_base_type_hint,
|
|
9
|
+
parameter_default,
|
|
10
|
+
)
|
|
11
|
+
from pydantic_openapi_generator.language_converters.python import common
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class KwargArgumentConfiguration(BaseArgumentConfiguration):
|
|
15
|
+
type: Literal[ParameterSource.KWARG] = ParameterSource.KWARG
|
|
16
|
+
|
|
17
|
+
@override
|
|
18
|
+
def default_code_name(self, param_name: str) -> str:
|
|
19
|
+
return common.normalize_symbol(param_name)
|
|
20
|
+
|
|
21
|
+
@override
|
|
22
|
+
def method_type_and_default(self, param: Parameter) -> tuple[str, Optional[str]]:
|
|
23
|
+
base_type = parameter_base_type_hint(param)
|
|
24
|
+
default = parameter_default(param)
|
|
25
|
+
|
|
26
|
+
if param.required:
|
|
27
|
+
return base_type, None
|
|
28
|
+
|
|
29
|
+
if default is not None:
|
|
30
|
+
return base_type, default
|
|
31
|
+
|
|
32
|
+
return optional_type(base_type), "None"
|
|
33
|
+
|
|
34
|
+
@override
|
|
35
|
+
def field_type_hint(self, param: Parameter) -> Optional[str]:
|
|
36
|
+
return None
|
|
37
|
+
|
|
38
|
+
@override
|
|
39
|
+
def field_default(self, param: Parameter) -> Optional[str]:
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
@override
|
|
43
|
+
def getter_name(self, code_name: str) -> Optional[str]:
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
@override
|
|
47
|
+
def local_name(self, code_name: str) -> Optional[str]:
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
@override
|
|
51
|
+
def value_expression(self, code_name: str) -> str:
|
|
52
|
+
return code_name
|
|
53
|
+
|
|
54
|
+
@override
|
|
55
|
+
def is_secret_parameter(self) -> bool:
|
|
56
|
+
return False
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from pydantic_di.loaders import ObjectLoaderYaml
|
|
5
|
+
|
|
6
|
+
from pydantic_openapi_generator.config.generator_config import (
|
|
7
|
+
PydanticOpenAPIGeneratorConfig,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def load_config(config_path: Optional[str | Path]) -> PydanticOpenAPIGeneratorConfig:
|
|
12
|
+
if config_path is None:
|
|
13
|
+
return PydanticOpenAPIGeneratorConfig()
|
|
14
|
+
|
|
15
|
+
return ObjectLoaderYaml[PydanticOpenAPIGeneratorConfig](
|
|
16
|
+
path=Path(config_path),
|
|
17
|
+
).load()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
from pydantic_openapi_generator.config.class_var_parameter import (
|
|
6
|
+
ClassVarArgumentConfiguration,
|
|
7
|
+
)
|
|
8
|
+
from pydantic_openapi_generator.config.function_parameter import (
|
|
9
|
+
FunctionArgumentConfiguration,
|
|
10
|
+
)
|
|
11
|
+
from pydantic_openapi_generator.config.kwarg_parameter import KwargArgumentConfiguration
|
|
12
|
+
|
|
13
|
+
ArgumentConfiguration = Annotated[
|
|
14
|
+
KwargArgumentConfiguration | ClassVarArgumentConfiguration | FunctionArgumentConfiguration,
|
|
15
|
+
Field(discriminator="type"),
|
|
16
|
+
]
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Any, Optional, Union
|
|
3
|
+
|
|
4
|
+
from openapi_pydantic.v3.v3_0 import Reference as Reference30
|
|
5
|
+
from openapi_pydantic.v3.v3_0 import Schema as Schema30
|
|
6
|
+
from openapi_pydantic.v3.v3_0.parameter import Parameter as Parameter30
|
|
7
|
+
from openapi_pydantic.v3.v3_1 import Reference as Reference31
|
|
8
|
+
from openapi_pydantic.v3.v3_1 import Schema as Schema31
|
|
9
|
+
from openapi_pydantic.v3.v3_1.parameter import Parameter as Parameter31
|
|
10
|
+
|
|
11
|
+
from pydantic_openapi_generator.language_converters.python import common
|
|
12
|
+
from pydantic_openapi_generator.language_converters.python.model_generator import (
|
|
13
|
+
type_converter,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
Parameter = Union[Parameter30, Parameter31]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def lower_code_name(value: str) -> str:
|
|
20
|
+
normalized = common.normalize_symbol(value)
|
|
21
|
+
parts = re.findall(r"[A-Z]+(?=[A-Z][a-z0-9]|$)|[A-Z]?[a-z0-9]+", normalized)
|
|
22
|
+
return "_".join(part.lower() for part in parts) or normalized.lower()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def literal_default(schema: Any) -> Optional[str]:
|
|
26
|
+
default = getattr(schema, "default", None)
|
|
27
|
+
return f"{default!r}" if default is not None else None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def optional_type(type_hint: str) -> str:
|
|
31
|
+
if type_hint.startswith("Optional[") and type_hint.endswith("]"):
|
|
32
|
+
return type_hint
|
|
33
|
+
return f"Optional[{type_hint}]"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def parameter_type_hint(param: Parameter, required: bool) -> str:
|
|
37
|
+
if isinstance(param.param_schema, (Schema30, Schema31)):
|
|
38
|
+
return type_converter(param.param_schema, required).converted_type
|
|
39
|
+
if isinstance(param.param_schema, (Reference30, Reference31)):
|
|
40
|
+
model_name = common.normalize_symbol(param.param_schema.ref.split("/")[-1])
|
|
41
|
+
return model_name if required else f"Optional[{model_name}]"
|
|
42
|
+
return "Any"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def parameter_base_type_hint(param: Parameter) -> str:
|
|
46
|
+
return parameter_type_hint(param, True)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def parameter_default(param: Parameter) -> Optional[str]:
|
|
50
|
+
if isinstance(param.param_schema, (Schema30, Schema31)):
|
|
51
|
+
return literal_default(param.param_schema)
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def optional_override_type_and_default(param: Parameter) -> tuple[str, Optional[str]]:
|
|
56
|
+
return optional_type(parameter_base_type_hint(param)), "None"
|
|
@@ -12,6 +12,8 @@ from httpx import ConnectError, ConnectTimeout
|
|
|
12
12
|
from pydantic import ValidationError
|
|
13
13
|
|
|
14
14
|
from .common import FormatOptions, Formatter, HTTPLibrary, PydanticVersion
|
|
15
|
+
from .config.generator_config import PydanticOpenAPIGeneratorConfig
|
|
16
|
+
from .config.loader import load_config
|
|
15
17
|
from .models import ConversionResult
|
|
16
18
|
from .parsers import (
|
|
17
19
|
generate_code_3_0,
|
|
@@ -203,11 +205,14 @@ def generate_data(
|
|
|
203
205
|
custom_template_path: Optional[str] = None,
|
|
204
206
|
pydantic_version: PydanticVersion = PydanticVersion.V2,
|
|
205
207
|
formatter: Formatter = Formatter.BLACK,
|
|
208
|
+
config_path: Optional[Union[str, Path]] = None,
|
|
209
|
+
config: Optional[PydanticOpenAPIGeneratorConfig] = None,
|
|
206
210
|
) -> None:
|
|
207
211
|
"""
|
|
208
212
|
Generate Python code from an OpenAPI 3.0+ specification.
|
|
209
213
|
"""
|
|
210
214
|
openapi_obj, version = get_open_api(source)
|
|
215
|
+
loaded_config = config if config is not None else load_config(config_path)
|
|
211
216
|
click.echo(f"Generating data from {source} (OpenAPI {version})")
|
|
212
217
|
|
|
213
218
|
# Use version-specific generator
|
|
@@ -219,6 +224,7 @@ def generate_data(
|
|
|
219
224
|
use_orjson,
|
|
220
225
|
custom_template_path,
|
|
221
226
|
pydantic_version,
|
|
227
|
+
loaded_config,
|
|
222
228
|
)
|
|
223
229
|
elif version == "3.1":
|
|
224
230
|
result = generate_code_3_1(
|
|
@@ -228,6 +234,7 @@ def generate_data(
|
|
|
228
234
|
use_orjson,
|
|
229
235
|
custom_template_path,
|
|
230
236
|
pydantic_version,
|
|
237
|
+
loaded_config,
|
|
231
238
|
)
|
|
232
239
|
else:
|
|
233
240
|
raise ValueError(f"Unsupported OpenAPI version: {version}")
|