Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .github/workflows/samples-python-petstore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
- "3.13"
sample:
- samples/openapi3/client/petstore/python-aiohttp
- samples/openapi3/client/petstore/python-httpx
- samples/openapi3/client/petstore/python
- samples/openapi3/client/petstore/python-lazyImports
services:
Expand Down
15 changes: 15 additions & 0 deletions bin/configs/python-httpx.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
generatorName: python
outputDir: samples/openapi3/client/petstore/python-httpx
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inputSpec: modules/openapi-generator/src/test/resources/3_0/python/petstore-with-fake-endpoints-models-for-testing.yaml
templateDir: modules/openapi-generator/src/main/resources/python
library: httpx
additionalProperties:
packageName: petstore_api
mapNumberTo: float
poetry1: true
nameMappings:
_type: underscore_type
type_: type_with_underscore
modelNameMappings:
# The OpenAPI spec ApiResponse conflicts with the internal ApiResponse
ApiResponse: ModelApiResponse
2 changes: 1 addition & 1 deletion docs/generators/python.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|generateSourceCodeOnly|Specifies that only a library source code is to be generated.| |false|
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
|lazyImports|Enable lazy imports.| |false|
|library|library template (sub-template) to use: asyncio, tornado (deprecated), urllib3| |urllib3|
|library|library template (sub-template) to use: asyncio, tornado (deprecated), urllib3, httpx| |urllib3|
|mapNumberTo|Map number to Union[StrictFloat, StrictInt], StrictStr or float.| |Union[StrictFloat, StrictInt]|
|packageName|python package name (convention: snake_case).| |openapi_client|
|packageUrl|python package URL.| |null|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ public PythonClientCodegen() {
supportedLibraries.put("urllib3", "urllib3-based client");
supportedLibraries.put("asyncio", "asyncio-based client");
supportedLibraries.put("tornado", "tornado-based client (deprecated)");
CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use: asyncio, tornado (deprecated), urllib3");
supportedLibraries.put("httpx", "httpx-based client");
CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use: asyncio, tornado (deprecated), urllib3, httpx");
libraryOption.setDefault(DEFAULT_LIBRARY);
cliOptions.add(libraryOption);
setLibrary(DEFAULT_LIBRARY);
Expand Down Expand Up @@ -330,10 +331,15 @@ public void processOpts() {

if ("asyncio".equals(getLibrary())) {
supportingFiles.add(new SupportingFile("asyncio/rest.mustache", packagePath(), "rest.py"));
additionalProperties.put("async", "true");
additionalProperties.put("asyncio", "true");
} else if ("tornado".equals(getLibrary())) {
supportingFiles.add(new SupportingFile("tornado/rest.mustache", packagePath(), "rest.py"));
additionalProperties.put("tornado", "true");
} else if ("httpx".equals(getLibrary())) {
supportingFiles.add(new SupportingFile("httpx/rest.mustache", packagePath(), "rest.py"));
additionalProperties.put("async", "true");
additionalProperties.put("httpx", "true");
} else {
supportingFiles.add(new SupportingFile("rest.mustache", packagePath(), "rest.py"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ To be able to use it, you will need these dependencies in your own package that

* urllib3 >= 2.1.0, < 3.0.0
* python-dateutil >= 2.8.2
{{#asyncio}}
{{#async}}
* aiohttp >= 3.8.4
* aiohttp-retry >= 2.8.3
{{/asyncio}}
{{/async}}
{{#tornado}}
* tornado >= 4.2, < 5
{{/tornado}}
Expand Down
16 changes: 8 additions & 8 deletions modules/openapi-generator/src/main/resources/python/api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -32,40 +32,40 @@ class {{classname}}:


@validate_call
{{#asyncio}}async {{/asyncio}}def {{operationId}}{{>partial_api_args}} -> {{{returnType}}}{{^returnType}}None{{/returnType}}:
{{#async}}async {{/async}}def {{operationId}}{{>partial_api_args}} -> {{{returnType}}}{{^returnType}}None{{/returnType}}:
{{>partial_api}}

response_data = {{#asyncio}}await {{/asyncio}}self.api_client.call_api(
response_data = {{#async}}await {{/async}}self.api_client.call_api(
*_param,
_request_timeout=_request_timeout
)
{{#asyncio}}await {{/asyncio}}response_data.read()
{{#async}}await {{/async}}response_data.read()
return self.api_client.response_deserialize(
response_data=response_data,
response_types_map=_response_types_map,
).data


@validate_call
{{#asyncio}}async {{/asyncio}}def {{operationId}}_with_http_info{{>partial_api_args}} -> ApiResponse[{{{returnType}}}{{^returnType}}None{{/returnType}}]:
{{#async}}async {{/async}}def {{operationId}}_with_http_info{{>partial_api_args}} -> ApiResponse[{{{returnType}}}{{^returnType}}None{{/returnType}}]:
{{>partial_api}}

response_data = {{#asyncio}}await {{/asyncio}}self.api_client.call_api(
response_data = {{#async}}await {{/async}}self.api_client.call_api(
*_param,
_request_timeout=_request_timeout
)
{{#asyncio}}await {{/asyncio}}response_data.read()
{{#async}}await {{/async}}response_data.read()
return self.api_client.response_deserialize(
response_data=response_data,
response_types_map=_response_types_map,
)


@validate_call
{{#asyncio}}async {{/asyncio}}def {{operationId}}_without_preload_content{{>partial_api_args}} -> RESTResponseType:
{{#async}}async {{/async}}def {{operationId}}_without_preload_content{{>partial_api_args}} -> RESTResponseType:
{{>partial_api}}

response_data = {{#asyncio}}await {{/asyncio}}self.api_client.call_api(
response_data = {{#async}}await {{/async}}self.api_client.call_api(
*_param,
_request_timeout=_request_timeout
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class ApiClient:
self.user_agent = '{{{httpUserAgent}}}{{^httpUserAgent}}OpenAPI-Generator/{{{packageVersion}}}/python{{/httpUserAgent}}'
self.client_side_validation = configuration.client_side_validation

{{#asyncio}}
{{#async}}
async def __aenter__(self):
return self

Expand All @@ -97,14 +97,14 @@ class ApiClient:

async def close(self):
await self.rest_client.close()
{{/asyncio}}
{{^asyncio}}
{{/async}}
{{^async}}
def __enter__(self):
return self

def __exit__(self, exc_type, exc_value, traceback):
pass
{{/asyncio}}
{{/async}}

@property
def user_agent(self):
Expand Down Expand Up @@ -257,7 +257,7 @@ class ApiClient:
{{#tornado}}
@tornado.gen.coroutine
{{/tornado}}
{{#asyncio}}async {{/asyncio}}def call_api(
{{#async}}async {{/async}}def call_api(
self,
method,
url,
Expand All @@ -280,7 +280,7 @@ class ApiClient:

try:
# perform request and return response
response_data = {{#asyncio}}await {{/asyncio}}{{#tornado}}yield {{/tornado}}self.rest_client.request(
response_data = {{#async}}await {{/async}}{{#tornado}}yield {{/tornado}}self.rest_client.request(
method, url,
headers=header_params,
body=body, post_params=post_params,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ from pprint import pprint
{{> python_doc_auth_partial}}

# Enter a context with an instance of the API client
{{#asyncio}}async {{/asyncio}}with {{{packageName}}}.ApiClient(configuration) as api_client:
{{#async}}async {{/async}}with {{{packageName}}}.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = {{{packageName}}}.{{{classname}}}(api_client)
{{#allParams}}
Expand All @@ -21,7 +21,7 @@ from pprint import pprint
{{#summary}}
# {{{.}}}
{{/summary}}
{{#returnType}}api_response = {{/returnType}}{{#asyncio}}await {{/asyncio}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}})
{{#returnType}}api_response = {{/returnType}}{{#async}}await {{/async}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}})
{{#returnType}}
print("The response of {{classname}}->{{operationId}}:\n")
pprint(api_response)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,31 @@ import unittest
from {{apiPackage}}.{{classFilename}} import {{classname}}


class {{#operations}}Test{{classname}}(unittest.{{#asyncio}}IsolatedAsyncio{{/asyncio}}TestCase):
class {{#operations}}Test{{classname}}(unittest.{{#async}}IsolatedAsyncio{{/async}}TestCase):
"""{{classname}} unit test stubs"""

{{#asyncio}}
{{#async}}
async def asyncSetUp(self) -> None:
self.api = {{classname}}()

async def asyncTearDown(self) -> None:
await self.api.api_client.close()
{{/asyncio}}
{{^asyncio}}
{{/async}}
{{^async}}
def setUp(self) -> None:
self.api = {{classname}}()

def tearDown(self) -> None:
pass
{{/asyncio}}
{{/async}}

{{#operation}}
{{#asyncio}}
{{#async}}
async def test_{{operationId}}(self) -> None:
{{/asyncio}}
{{^asyncio}}
{{/async}}
{{^async}}
def test_{{operationId}}(self) -> None:
{{/asyncio}}
{{/async}}
"""Test case for {{{operationId}}}

{{#summary}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ from pprint import pprint


# Enter a context with an instance of the API client
{{#asyncio}}async {{/asyncio}}with {{{packageName}}}.ApiClient(configuration) as api_client:
{{#async}}async {{/async}}with {{{packageName}}}.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = {{{packageName}}}.{{{classname}}}(api_client)
{{#allParams}}
Expand All @@ -19,7 +19,7 @@ from pprint import pprint
{{#summary}}
# {{{.}}}
{{/summary}}
{{#returnType}}api_response = {{/returnType}}{{#asyncio}}await {{/asyncio}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}})
{{#returnType}}api_response = {{/returnType}}{{#async}}await {{/async}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}})
{{#returnType}}
print("The response of {{classname}}->{{operationId}}:\n")
pprint(api_response)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import copy
import http.client as httplib
import logging
from logging import FileHandler
{{^asyncio}}
{{^async}}
import multiprocessing
{{/asyncio}}
{{/async}}
import sys
from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union
from typing_extensions import NotRequired, Self
Expand Down Expand Up @@ -395,21 +395,21 @@ conf = {{{packageName}}}.Configuration(
Set this to the SNI value expected by the server.
"""

{{#asyncio}}
{{#async}}
self.connection_pool_maxsize = 100
"""This value is passed to the aiohttp to limit simultaneous connections.
Default values is 100, None means no-limit.
"""
{{/asyncio}}
{{^asyncio}}
{{/async}}
{{^async}}
self.connection_pool_maxsize = multiprocessing.cpu_count() * 5
"""urllib3 connection pool's maximum number of connections saved
per pool. urllib3 uses 1 connection as default value, but this is
not the best value when you are making a lot of possibly parallel
requests to the same host, which is often the case here.
cpu_count * 5 is used as default value to increase performance.
"""
{{/asyncio}}
{{/async}}

self.proxy: Optional[str] = None
"""Proxy URL
Expand Down
Loading
Loading