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

Commit 5f9910d

Browse files
authored
[python-experimental] reduces python version (#13481)
* Removes classmethod property combinations * Changes python version to 3.8 * Changes python version to 3.7 * Tests fixed * Samples updated * Adds getAddSuffixToDuplicateOperationNickname and uses it in python-exp, samples regenerated * test_paths regenerated * Fixes bug * Adds typing_extensions requirement
1 parent fa51d8b commit 5f9910d

File tree

954 files changed

+3800
-3009
lines changed

Some content is hidden

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

954 files changed

+3800
-3009
lines changed

docs/generators/python-experimental.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ title: Documentation for the python-experimental Generator
1010
| generator stability | EXPERIMENTAL | |
1111
| generator type | CLIENT | |
1212
| generator language | Python | |
13-
| generator language version | >=3.9 | |
13+
| generator language version | >=3.7 | |
1414
| generator default templating engine | handlebars | |
1515
| helpTxt | Generates a Python client library<br /><br />Features in this generator:<br />- type hints on endpoints and model creation<br />- model parameter names use the spec defined keys and cases<br />- robust composition (oneOf/anyOf/allOf/not) where payload data is stored in one instance only<br />- endpoint parameter names use the spec defined keys and cases<br />- inline schemas are supported at any location including composition<br />- multiple content types supported in request body and response bodies<br />- run time type checking<br />- Sending/receiving decimals as strings supported with type:string format: number -> DecimalSchema<br />- Sending/receiving uuids as strings supported with type:string format: uuid -> UUIDSchema<br />- quicker load time for python modules (a single endpoint can be imported and used without loading others)<br />- all instances of schemas dynamically inherit from all matching schemas so one can use isinstance to check if validation passed<br />- composed schemas with type constraints supported (type:object + oneOf/anyOf/allOf)<br />- schemas are not coerced/cast. For example string + date are both stored as string, and there is a date accessor<br /> - Exceptions: int/float is stored as Decimal, When receiving data from headers it will start as str and may need to be cast for example to int | |
1616

modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,4 +328,6 @@ public interface CodegenConfig {
328328
List<VendorExtension> getSupportedVendorExtensions();
329329

330330
boolean getUseInlineModelResolver();
331+
332+
boolean getAddSuffixToDuplicateOperationNicknames();
331333
}

modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,12 @@ apiTemplateFiles are for API outputs only (controllers/handlers).
297297
// from deeper schema defined locations
298298
protected boolean addSchemaImportsFromV3SpecLocations = false;
299299

300+
protected boolean addSuffixToDuplicateOperationNicknames = true;
301+
302+
public boolean getAddSuffixToDuplicateOperationNicknames() {
303+
return addSuffixToDuplicateOperationNicknames;
304+
}
305+
300306
@Override
301307
public List<CliOption> cliOptions() {
302308
return cliOptions;

modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,16 +1200,18 @@ private OperationsMap processOperations(CodegenConfig config, String tag, List<C
12001200
objs.setClassname(config.toApiName(tag));
12011201
objs.setPathPrefix(config.toApiVarName(tag));
12021202

1203-
// check for operationId uniqueness
1204-
Set<String> opIds = new HashSet<>();
1205-
int counter = 0;
1206-
for (CodegenOperation op : ops) {
1207-
String opId = op.nickname;
1208-
if (opIds.contains(opId)) {
1209-
counter++;
1210-
op.nickname += "_" + counter;
1203+
// check for nickname uniqueness
1204+
if (config.getAddSuffixToDuplicateOperationNicknames()) {
1205+
Set<String> opIds = new HashSet<>();
1206+
int counter = 0;
1207+
for (CodegenOperation op : ops) {
1208+
String opId = op.nickname;
1209+
if (opIds.contains(opId)) {
1210+
counter++;
1211+
op.nickname += "_" + counter;
1212+
}
1213+
opIds.add(opId);
12111214
}
1212-
opIds.add(opId);
12131215
}
12141216
objs.setOperation(ops);
12151217

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonExperimentalClientCodegen.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import com.github.curiousoddman.rgxgen.config.RgxGenOption;
2121
import com.github.curiousoddman.rgxgen.config.RgxGenProperties;
2222
import com.google.common.base.CaseFormat;
23-
import io.swagger.v3.oas.annotations.tags.Tags;
2423
import io.swagger.v3.oas.models.OpenAPI;
2524
import io.swagger.v3.oas.models.Operation;
2625
import io.swagger.v3.oas.models.PathItem;
@@ -112,6 +111,7 @@ public PythonExperimentalClientCodegen() {
112111
addSchemaImportsFromV3SpecLocations = true;
113112
sortModelPropertiesByRequiredFlag = Boolean.TRUE;
114113
sortParamsByRequiredFlag = Boolean.TRUE;
114+
addSuffixToDuplicateOperationNicknames = false;
115115

116116
modifyFeatureSet(features -> features
117117
.includeSchemaSupportFeatures(
@@ -2638,7 +2638,7 @@ public String defaultTemplatingEngine() {
26382638
}
26392639

26402640
@Override
2641-
public String generatorLanguageVersion() { return ">=3.9"; };
2641+
public String generatorLanguageVersion() { return ">=3.7"; };
26422642

26432643
@Override
26442644
public void preprocessOpenAPI(OpenAPI openAPI) {

modules/openapi-generator/src/main/resources/python-experimental/README.handlebars

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
1818
## Requirements.
1919

2020
Python {{generatorLanguageVersion}}
21-
v3.9 is needed so one can combine classmethod and property decorators to define
22-
object schema properties as classes
2321

2422
## Migration from other generators like python and python-legacy
2523

@@ -60,6 +58,16 @@ object schema properties as classes
6058
- A type hint is also generated for additionalProperties accessed using this method
6159
- So you will need to update you code to use some_instance['optionalProp'] to access optional property
6260
and additionalProperty values
61+
8. The location of the api classes has changed
62+
- Api classes are located in your_package.apis.tags.some_api
63+
- This change was made to eliminate redundant code generation
64+
- Legacy generators generated the same endpoint twice if it had > 1 tag on it
65+
- This generator defines an endpoint in one class, then inherits that class to generate
66+
apis by tags and by paths
67+
- This change reduces code and allows quicker run time if you use the path apis
68+
- path apis are at your_package.apis.paths.some_path
69+
- Those apis will only load their needed models, which is less to load than all of the resources needed in a tag api
70+
- So you will need to update your import paths to the api classes
6371

6472
### Why are Oapg and _oapg used in class and method names?
6573
Classes can have arbitrarily named properties set on them

modules/openapi-generator/src/main/resources/python-experimental/__init__test_paths.handlebars

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class ApiTestMixin:
4141
)
4242

4343
@staticmethod
44-
def headers_for_content_type(content_type: str) -> dict[str, str]:
44+
def headers_for_content_type(content_type: str) -> typing.Dict[str, str]:
4545
return {'content-type': content_type}
4646

4747
@classmethod
@@ -50,7 +50,7 @@ class ApiTestMixin:
5050
body: typing.Union[str, bytes],
5151
status: int = 200,
5252
content_type: str = json_content_type,
53-
headers: typing.Optional[dict[str, str]] = None,
53+
headers: typing.Optional[typing.Dict[str, str]] = None,
5454
preload_content: bool = True
5555
) -> urllib3.HTTPResponse:
5656
if headers is None:

modules/openapi-generator/src/main/resources/python-experimental/api_client.handlebars

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ from multiprocessing.pool import ThreadPool
1313
import re
1414
import tempfile
1515
import typing
16+
import typing_extensions
1617
import urllib3
1718
from urllib3._collections import HTTPHeaderDict
1819
from urllib.parse import urlparse, quote
@@ -704,7 +705,7 @@ class HeaderParameter(ParameterBase, StyleSimpleSerializer):
704705
)
705706

706707
@staticmethod
707-
def __to_headers(in_data: typing.Tuple[typing.Tuple[str, str], ...]) -> HTTPHeaderDict[str, str]:
708+
def __to_headers(in_data: typing.Tuple[typing.Tuple[str, str], ...]) -> HTTPHeaderDict:
708709
data = tuple(t for t in in_data if t)
709710
headers = HTTPHeaderDict()
710711
if not data:
@@ -716,7 +717,7 @@ class HeaderParameter(ParameterBase, StyleSimpleSerializer):
716717
self,
717718
in_data: typing.Union[
718719
Schema, Decimal, int, float, str, date, datetime, None, bool, list, tuple, dict, frozendict.frozendict]
719-
) -> HTTPHeaderDict[str, str]:
720+
) -> HTTPHeaderDict:
720721
if self.schema:
721722
cast_in_data = self.schema(in_data)
722723
cast_in_data = self._json_encoder.default(cast_in_data)
@@ -1270,7 +1271,7 @@ class Api:
12701271
self.api_client = api_client
12711272

12721273
@staticmethod
1273-
def _verify_typed_dict_inputs_oapg(cls: typing.Type[typing.TypedDict], data: typing.Dict[str, typing.Any]):
1274+
def _verify_typed_dict_inputs_oapg(cls: typing.Type[typing_extensions.TypedDict], data: typing.Dict[str, typing.Any]):
12741275
"""
12751276
Ensures that:
12761277
- required keys are present
@@ -1342,9 +1343,9 @@ class Api:
13421343
return host
13431344

13441345

1345-
class SerializedRequestBody(typing.TypedDict, total=False):
1346+
class SerializedRequestBody(typing_extensions.TypedDict, total=False):
13461347
body: typing.Union[str, bytes]
1347-
fields: typing.Tuple[typing.Union[RequestField, tuple[str, str]], ...]
1348+
fields: typing.Tuple[typing.Union[RequestField, typing.Tuple[str, str]], ...]
13481349

13491350

13501351
class RequestBody(StyleFormSerializer, JSONDetector):

modules/openapi-generator/src/main/resources/python-experimental/apis_path_to_api.handlebars

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import typing
1+
import typing_extensions
22

33
from {{packageName}}.paths import PathValues
44
{{#each pathModuleToApiClassname}}
55
from {{packageName}}.apis.paths.{{@key}} import {{this}}
66
{{/each}}
77

8-
PathToApi = typing.TypedDict(
8+
PathToApi = typing_extensions.TypedDict(
99
'PathToApi',
1010
{
1111
{{#each pathEnumToApiClassname}}

modules/openapi-generator/src/main/resources/python-experimental/apis_tag_to_api.handlebars

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import typing
1+
import typing_extensions
22

33
from {{packageName}}.apis.tags import TagValues
44
{{#each tagModuleNameToApiClassname}}
55
from {{packageName}}.apis.tags.{{@key}} import {{this}}
66
{{/each}}
77

8-
TagToApi = typing.TypedDict(
8+
TagToApi = typing_extensions.TypedDict(
99
'TagToApi',
1010
{
1111
{{#each tagEnumToApiClassname}}

0 commit comments

Comments
 (0)