Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.

Commit 3f62259

Browse files
authored
v3 adds generic type info to schema classes/properties/items (#174)
* Adds generic type T * Fixes broken python test * Fixes for vscode basic type checking * Adds new instacne casting * Sets ValidationMetadata new type * Makes ValidationMetadata a dataclass, fixes type issues in _process_schema_classes * Fixes XBase self type errors * Makes two methods static * Fixes IntBase as_int type error * Fixes type error in NumberBase * Adds needed typing.cast calls in new methods and get_new_class fn * Fixes exponent type error * Fixes type errors in _get_new_instance_without_conversion * Fixes typ error in FileIO new * Fixes type error in BytesSchema * Fixes another type error * Adds type ignore for _GenericAlias check and origin access * Removes _takes_ascii usage * Fixes septype error * Adds __parse_isotime type fix * Fixes more date/datetime parsing errors * Adds missing return types * Changes UnsetAnyType back to AnyType * Fixes AnyType init signature * Writes new method for all composed or anytype classes * Removes quote from refclass definitions * Removes a type ignore comment * Sample regen * Adds response body generic type to ApiResponse classes * Refactors response content template * Adds response content type hint * Fixes response header passing for deserialization * Moves content schema helper * Adds header and parameter content type type hint * Adds missing imports * Adds schema types for parameters and headers * Samples updated * Removes frozendict base class from ValidationMetadata * Removes __origin__ usage * Samples regenerated * Fixes python test
1 parent 923d138 commit 3f62259

1,164 files changed

Lines changed: 16877 additions & 5151 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

modules/openapi-json-schema-generator/src/main/resources/python/api_client.hbs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ class OpenApiResponse(JSONDetector, TypedDictInputVerifier, typing.Generic[T]):
782782
__filename_content_disposition_pattern = re.compile('filename="(.+?)"')
783783
response_cls: typing.Type[T]
784784
content: typing.Optional[typing.Dict[str, MediaType]] = None
785-
headers: typing.Optional[typing.Dict[str, HeaderParameterWithoutName]] = None
785+
headers: typing.Optional[typing.Dict[str, typing.Type[HeaderParameterWithoutName]]] = None
786786

787787
@staticmethod
788788
def __deserialize_json(response: urllib3.HTTPResponse) -> typing.Any:
@@ -1367,12 +1367,13 @@ class RequestBody(StyleFormSerializer, JSONDetector):
13671367
- encode_multipart and fields for multipart/form-data
13681368
"""
13691369
media_type = cls.content[content_type]
1370-
if isinstance(in_data, media_type.schema):
1370+
schema = schemas._get_class(media_type.schema)
1371+
if isinstance(in_data, schema):
13711372
cast_in_data = in_data
13721373
elif isinstance(in_data, (dict, frozendict.frozendict)) and in_data:
1373-
cast_in_data = media_type.schema(**in_data)
1374+
cast_in_data = schema(**in_data)
13741375
else:
1375-
cast_in_data = media_type.schema(in_data)
1376+
cast_in_data = schema(in_data)
13761377
# TODO check for and use encoding if it exists
13771378
# and content_type is multipart or application/x-www-form-urlencoded
13781379
if cls._content_type_is_json(content_type):
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{{#if refInfo.refClass}}
2+
{{#with getDeepestRef}}
3+
{{#if types}}
4+
{{#eq types.size 1}}
5+
{{#if paramName}}{{paramName}}: {{#eq paramName "schema"}}typing_extensions.TypeAlias = {{/eq}}{{/if}}{{#if modulePrefix}}{{modulePrefix}}_{{/if}}{{../jsonPathPiece.snakeCase}}.{{../jsonPathPiece.camelCase}}[{{> components/schemas/_helper_schema_python_base_types }}]{{#unless paramName}},{{/unless}}
6+
{{else}}
7+
{{#if paramName}}{{paramName}}: {{#eq paramName "schema"}}typing_extensions.TypeAlias = {{/eq}}{{/if}}{{#if modulePrefix}}{{modulePrefix}}_{{/if}}{{../jsonPathPiece.snakeCase}}.{{../jsonPathPiece.camelCase}}[typing.Union[
8+
{{> components/schemas/_helper_schema_python_base_types_newline }}
9+
]]{{#unless paramName}},{{/unless}}
10+
{{/eq}}
11+
{{else}}
12+
{{#if paramName}}{{paramName}}: {{#eq paramName "schema"}}typing_extensions.TypeAlias = {{/eq}}{{/if}}{{#if modulePrefix}}{{modulePrefix}}_{{/if}}{{../jsonPathPiece.snakeCase}}.{{../jsonPathPiece.camelCase}}[typing.Union[
13+
{{> components/schemas/_helper_schema_python_base_types_newline }}
14+
]]{{#unless paramName}},{{/unless}}
15+
{{/if}}
16+
{{/with}}
17+
{{else}}
18+
{{#if types}}
19+
{{#eq types.size 1}}
20+
{{#if paramName}}{{paramName}}: {{#eq paramName "schema"}}typing_extensions.TypeAlias = {{/eq}}{{/if}}{{#if modulePrefix}}{{modulePrefix}}_{{/if}}{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}}[{{> components/schemas/_helper_schema_python_base_types }}]{{#unless paramName}},{{/unless}}
21+
{{else}}
22+
{{#if includeBody}}{{paramName}}: {{#eq paramName "schema"}}typing_extensions.TypeAlias = {{/eq}}{{/if}}{{#if modulePrefix}}{{modulePrefix}}_{{/if}}{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}}[typing.Union[
23+
{{> components/schemas/_helper_schema_python_base_types_newline }}
24+
]]{{#unless paramName}},{{/unless}}
25+
{{/eq}}
26+
{{else}}
27+
{{#if paramName}}{{paramName}}: {{#eq paramName "schema"}}typing_extensions.TypeAlias = {{/eq}}{{/if}}{{#if modulePrefix}}{{modulePrefix}}_{{/if}}{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}}[typing.Union[
28+
{{> components/schemas/_helper_schema_python_base_types_newline }}
29+
]]{{#unless paramName}},{{/unless}}
30+
{{/if}}
31+
{{/if}}

modules/openapi-json-schema-generator/src/main/resources/python/components/_helper_param_or_header_instance.hbs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,31 +27,31 @@ class {{jsonPathPiece.camelCase}}(api_client.{{#if noName}}Header{{/if}}{{#eq in
2727
{{/if}}
2828
{{#if schema}}
2929
{{#with schema}}
30-
schema = {{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}}
30+
{{> components/_helper_content_schema_type paramName="schema" modulePrefix=null }}
3131
{{/with}}
3232
{{/if}}
3333
{{#if content}}
3434
{{#each content}}
3535

3636

37-
class __{{@key.camelCase}}MediaType(api_client.MediaType):
37+
class {{@key.camelCase}}MediaType(api_client.MediaType):
3838
{{#with this}}
3939
{{#with schema}}
40-
schema: typing.Type[{{../@key.snakeCase}}_{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}}] = {{../@key.snakeCase}}_{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}}
40+
{{> components/_helper_content_schema_type paramName="schema" modulePrefix=../@key.snakeCase }}
4141
{{/with}}
4242
{{/with}}
4343
{{/each}}
44-
__Content = typing_extensions.TypedDict(
45-
'__Content',
44+
Content = typing_extensions.TypedDict(
45+
'Content',
4646
{
4747
{{#each content}}
48-
'{{{@key.original}}}': typing.Type[__{{@key.camelCase}}MediaType],
48+
'{{{@key.original}}}': typing.Type[{{@key.camelCase}}MediaType],
4949
{{/each}}
5050
}
5151
)
52-
content: __Content = {
52+
content: Content = {
5353
{{#each content}}
54-
'{{{@key.original}}}': __{{@key.camelCase}}MediaType,
54+
'{{{@key.original}}}': {{@key.camelCase}}MediaType,
5555
{{/each}}
5656
}
5757
{{/if}}

modules/openapi-json-schema-generator/src/main/resources/python/components/request_bodies/request_body.hbs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,24 @@ class {{jsonPathPiece.camelCase}}(api_client.RequestBody):
2424
{{#each content}}
2525

2626

27-
class __{{@key.camelCase}}MediaType(api_client.MediaType):
27+
class {{@key.camelCase}}MediaType(api_client.MediaType):
2828
{{#with this}}
2929
{{#with schema}}
3030
schema: typing.Type[{{../@key.snakeCase}}_{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}}] = {{../@key.snakeCase}}_{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}}
3131
{{/with}}
3232
{{/with}}
3333
{{/each}}
34-
__Content = typing_extensions.TypedDict(
35-
'__Content',
34+
Content = typing_extensions.TypedDict(
35+
'Content',
3636
{
3737
{{#each content}}
38-
'{{{@key.original}}}': typing.Type[__{{@key.camelCase}}MediaType],
38+
'{{{@key.original}}}': typing.Type[{{@key.camelCase}}MediaType],
3939
{{/each}}
4040
}
4141
)
42-
content: __Content = {
42+
content: Content = {
4343
{{#each content}}
44-
'{{{@key.original}}}': __{{@key.camelCase}}MediaType,
44+
'{{{@key.original}}}': {{@key.camelCase}}MediaType,
4545
{{/each}}
4646
}
4747
{{#if required}}

modules/openapi-json-schema-generator/src/main/resources/python/components/responses/_helper_header_schema_and_def.hbs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ class {{xParamsName}}:
2424
pass
2525

2626

27-
parameters = [
27+
parameters: typing.Dict[str, typing.Type[api_client.HeaderParameterWithoutName]] = {
2828
{{#each xParams}}
29-
{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}},
29+
'{{@key}}': {{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}},
3030
{{/each}}
31-
]
31+
}

modules/openapi-json-schema-generator/src/main/resources/python/components/responses/response.hbs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,23 @@ class Api{{jsonPathPiece.camelCase}}(api_client.ApiResponse):
4040
{{#each content}}
4141
{{#if this.schema}}
4242
{{#with this.schema}}
43-
{{../@key.snakeCase}}_{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}},
43+
{{> components/_helper_content_schema_type paramName=null modulePrefix=../@key.snakeCase }}
4444
{{/with}}
4545
{{else}}
4646
schemas.Unset,
4747
{{/if}}
4848
{{/each}}
4949
]
5050
{{else}}
51-
body: {{#each content}}{{#if this.schema}}{{#with this.schema}}{{../@key.snakeCase}}_{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}}{{/with}}{{else}}schemas.Unset{{/if}}{{/each}}
51+
{{#each content}}
52+
{{#if this.schema}}
53+
{{#with this.schema}}
54+
{{> components/_helper_content_schema_type paramName="body" modulePrefix=../@key.snakeCase }}
55+
{{/with}}
56+
{{else}}
57+
body: schemas.Unset
58+
{{/if}}
59+
{{/each}}
5260
{{/gt}}
5361
{{else}}
5462
body: schemas.Unset = schemas.unset
@@ -66,15 +74,23 @@ class Api{{jsonPathPiece.camelCase}}(api_client.ApiResponse):
6674
{{#each content}}
6775
{{#if this.schema}}
6876
{{#with this.schema}}
69-
{{../@key.snakeCase}}_{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}},
70-
{{/with}}
71-
{{else}}
77+
{{> components/_helper_content_schema_type paramName=null modulePrefix=../@key.snakeCase }}
78+
{{/with}}
79+
{{else}}
7280
schemas.Unset,
7381
{{/if}}
7482
{{/each}}
7583
]
7684
{{else}}
77-
body: {{#each content}}{{#if this.schema}}{{#with this.schema}}{{../@key.snakeCase}}_{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}}{{/with}}{{else}}schemas.Unset{{/if}}{{/each}}
85+
{{#each content}}
86+
{{#if this.schema}}
87+
{{#with this.schema}}
88+
{{> components/_helper_content_schema_type paramName="body" modulePrefix=../@key.snakeCase }}
89+
{{/with}}
90+
{{else}}
91+
body: schemas.Unset
92+
{{/if}}
93+
{{/each}}
7894
{{/gt}}
7995
{{else}}
8096
body: schemas.Unset = schemas.unset
@@ -96,27 +112,27 @@ class {{jsonPathPiece.camelCase}}(api_client.OpenApiResponse[Api{{jsonPathPiece.
96112
{{#each content}}
97113

98114

99-
class __{{@key.camelCase}}MediaType(api_client.MediaType):
115+
class {{@key.camelCase}}MediaType(api_client.MediaType):
100116
{{#with this}}
101117
{{#with schema}}
102-
schema: typing.Type[{{../@key.snakeCase}}_{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}}] = {{../@key.snakeCase}}_{{jsonPathPiece.snakeCase}}.{{jsonPathPiece.camelCase}}
118+
{{> components/_helper_content_schema_type paramName="schema" modulePrefix=../@key.snakeCase }}
103119
{{else}}
104120
pass
105121
{{/with}}
106122
{{/with}}
107123
{{/each}}
108124
{{#if content}}
109-
__Content = typing_extensions.TypedDict(
110-
'__Content',
125+
Content = typing_extensions.TypedDict(
126+
'Content',
111127
{
112128
{{#each content}}
113-
'{{{@key.original}}}': typing.Type[__{{@key.camelCase}}MediaType],
129+
'{{{@key.original}}}': typing.Type[{{@key.camelCase}}MediaType],
114130
{{/each}}
115131
}
116132
)
117-
content: __Content = {
133+
content: Content = {
118134
{{#each content}}
119-
'{{{@key.original}}}': __{{@key.camelCase}}MediaType,
135+
'{{{@key.original}}}': {{@key.camelCase}}MediaType,
120136
{{/each}}
121137
}
122138
{{/if}}

modules/openapi-json-schema-generator/src/main/resources/python/components/schemas/_helper_getitem.hbs

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{{#if types}}
2+
{{#eq types.size 1}}
3+
def __getitem__(self, name: {{#if literal}}typing_extensions.Literal["{{{key}}}"]{{else}}{{key}}{{/if}}) -> Schema_{{propertyClass}}.{{jsonPathPiece.camelCase}}[{{> components/schemas/_helper_schema_python_base_types }}]:{{#if overload}} ...{{/if}}
4+
{{else}}
5+
def __getitem__(self, name: {{#if literal}}typing_extensions.Literal["{{{key}}}"]{{else}}{{key}}{{/if}}) -> Schema_{{propertyClass}}.{{jsonPathPiece.camelCase}}[typing.Union[
6+
{{> components/schemas/_helper_schema_python_base_types_newline }}
7+
]]:{{#if overload}} ...{{/if}}
8+
{{/eq}}
9+
{{else}}
10+
def __getitem__(self, name: {{#if literal}}typing_extensions.Literal["{{{key}}}"]{{else}}{{key}}{{/if}}) -> Schema_{{propertyClass}}.{{jsonPathPiece.camelCase}}[typing.Union[
11+
{{> components/schemas/_helper_schema_python_base_types_newline }}
12+
]]:{{#if overload}} ...{{/if}}
13+
{{/if}}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{{#with getDeepestRef}}
2+
{{#if types}}
3+
{{#eq types.size 1}}
4+
def __getitem__(self, name: {{#if literal}}typing_extensions.Literal["{{{key}}}"]{{else}}{{key}}{{/if}}) -> {{#if ../refInfo.refModule}}{{../refInfo.refModule}}.{{/if}}{{../refInfo.refClass}}[{{> components/schemas/_helper_schema_python_base_types }}]:{{#if overload}} ...{{/if}}
5+
{{else}}
6+
def __getitem__(self, name: {{#if literal}}typing_extensions.Literal["{{{key}}}"]{{else}}{{key}}{{/if}}) -> {{#if ../refInfo.refModule}}{{../refInfo.refModule}}.{{/if}}{{../refInfo.refClass}}[typing.Union[
7+
{{> components/schemas/_helper_schema_python_base_types_newline }}
8+
]]:{{#if overload}} ...{{/if}}
9+
{{/eq}}
10+
{{else}}
11+
def __getitem__(self, name: {{#if literal}}typing_extensions.Literal["{{{key}}}"]{{else}}{{key}}{{/if}}) -> {{#if ../refInfo.refModule}}{{../refInfo.refModule}}.{{/if}}{{../refInfo.refClass}}[typing.Union[
12+
{{> components/schemas/_helper_schema_python_base_types_newline }}
13+
]]:{{#if overload}} ...{{/if}}
14+
{{/if}}
15+
{{/with}}

modules/openapi-json-schema-generator/src/main/resources/python/components/schemas/_helper_getitems.hbs

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,51 +4,94 @@
44

55
@typing.overload
66
{{#if refInfo.refClass}}
7-
def __getitem__(self, name: typing_extensions.Literal["{{{@key.original}}}"]) -> '{{> components/schemas/_helper_refclass_with_module }}': ...
7+
{{> components/schemas/_helper_getitem_refclass literal=true key=@key.original overload=true }}
88
{{else}}
99
{{#if jsonPathPiece}}
1010
{{#if schemaIsFromAdditionalProperties}}
11-
def __getitem__(self, name: typing_extensions.Literal["{{{@key.original}}}"]) -> Schema_.{{jsonPathPiece.camelCase}}: ...
11+
{{> components/schemas/_helper_getitem_property propertyClass="" literal=true key=@key.original overload=true }}
1212
{{else}}
13-
def __getitem__(self, name: typing_extensions.Literal["{{{@key.original}}}"]) -> Schema_.Properties.{{jsonPathPiece.camelCase}}: ...
13+
{{> components/schemas/_helper_getitem_property propertyClass=".Properties" literal=true key=@key.original overload=true }}
1414
{{/if}}
1515
{{else}}
16-
def __getitem__(self, name: typing_extensions.Literal["{{{@key.original}}}"]) -> schemas.AnyTypeSchema: ...
16+
{{! for when additionalProperties is unset, use schemas.AnyTypeSchema because val is not always schemas.UnsetAnyTypeSchema }}
17+
def __getitem__(self, name: typing_extensions.Literal["{{{@key.original}}}"]) -> schemas.AnyTypeSchema[typing.Union[
18+
{{> components/schemas/_helper_schema_python_base_types_newline }}
19+
]]: ...
1720
{{/if}}
1821
{{/if}}
1922
{{/with}}
2023
{{/each}}
2124
{{/if}}
2225
{{#if optionalProperties}}
23-
{{#each optionalProperties}}
26+
{{#each optionalProperties}}
2427

2528
@typing.overload
26-
{{#if refInfo.refClass}}
27-
def __getitem__(self, name: typing_extensions.Literal["{{{@key.original}}}"]) -> '{{> components/schemas/_helper_refclass_with_module }}': ...
28-
{{else}}
29-
def __getitem__(self, name: typing_extensions.Literal["{{{@key.original}}}"]) -> Schema_.Properties.{{jsonPathPiece.camelCase}}: ...
30-
{{/if}}
31-
{{/each}}
29+
{{#if refInfo.refClass}}
30+
{{> components/schemas/_helper_getitem_refclass literal=true key=@key.original overload=true }}
31+
{{else}}
32+
{{> components/schemas/_helper_getitem_property propertyClass=".Properties" literal=true key=@key.original overload=true }}
33+
{{/if}}
34+
{{/each}}
3235
{{/if}}
3336
{{#or properties requiredProperties}}
3437
{{#with additionalProperties}}
3538
{{#unless isBooleanSchemaFalse}}
3639

3740
@typing.overload
38-
def __getitem__(self, name: str) -> {{#if refInfo.refClass}}'{{> components/schemas/_helper_refclass_with_module }}'{{else}}Schema_.{{jsonPathPiece.camelCase}}{{/if}}: ...
41+
{{#if refInfo.refClass}}
42+
{{> components/schemas/_helper_getitem_refclass literal=false key="str" overload=true }}
43+
{{else}}
44+
{{> components/schemas/_helper_getitem_property propertyClass="" literal=false key="str" overload=true }}
45+
{{/if}}
3946
{{/unless}}
4047
{{else}}
48+
{{! for when additionalProperties is unset, use schemas.AnyTypeSchema because val is not always schemas.UnsetAnyTypeSchema }}
4149

4250
@typing.overload
43-
def __getitem__(self, name: str) -> schemas.UnsetAnyTypeSchema: ...
51+
def __getitem__(self, name: str) -> schemas.AnyTypeSchema[typing.Union[
52+
frozendict.frozendict,
53+
str,
54+
decimal.Decimal,
55+
schemas.BoolClass,
56+
schemas.NoneClass,
57+
tuple,
58+
bytes,
59+
schemas.FileIO
60+
]]: ...
4461
{{/with}}
4562

46-
{{> components/schemas/_helper_getitem methodName="__getitem__" }}
63+
def __getitem__(
64+
self,
65+
name: typing.Union[
66+
{{#each requiredProperties}}
67+
{{#if this}}
68+
typing_extensions.Literal["{{{@key.original}}}"],
69+
{{/if}}
70+
{{/each}}
71+
{{#each optionalProperties}}
72+
typing_extensions.Literal["{{{@key.original}}}"],
73+
{{/each}}
74+
{{#with additionalProperties}}
75+
{{#unless isBooleanSchemaFalse}}
76+
str
77+
{{/unless}}
78+
{{else}}
79+
str
80+
{{/with}}
81+
]
82+
):
83+
# dict_instance[name] accessor
84+
return super().__getitem__(name)
4785
{{else}}
86+
{{! no properties or requiredProperties }}
4887
{{#with additionalProperties}}
4988
{{#unless isBooleanSchemaFalse}}
5089

51-
def __getitem__(self, name: str) -> {{#if refInfo.refClass}}'{{> components/schemas/_helper_refclass_with_module }}'{{else}}Schema_.{{jsonPathPiece.camelCase}}{{/if}}:
90+
{{#if refInfo.refClass}}
91+
{{> components/schemas/_helper_getitem_refclass literal=false key="str" overload=false }}
92+
{{else}}
93+
{{> components/schemas/_helper_getitem_property propertyClass="" literal=false key="str" overload=false }}
94+
{{/if}}
5295
# dict_instance[name] accessor
5396
return super().__getitem__(name)
5497
{{/unless}}

0 commit comments

Comments
 (0)