[python] add supportHttpxSync option for sync httpx methods (#23032)#24096
[python] add supportHttpxSync option for sync httpx methods (#23032)#24096AntoineDuComptoirDesPharmacies wants to merge 2 commits into
Conversation
…ools#23032) Add a new `supportHttpxSync` option to the Python generator (httpx library only) that generates synchronous `_sync` variants of each API method inside the same API class, instead of a separate `httpx-sync` library. Following the maintainer's review feedback on OpenAPITools#23044, each generated `_sync` method simply calls its asynchronous counterpart and waits for completion, so both synchronous and asynchronous methods are available from the same SDK (matching the sync/async layout already used by other generators). - PythonClientCodegen: new `supportHttpxSync` CLI option, wired for the httpx library only (ignored with a warning otherwise) - httpx/sync_helper.mustache: `run_sync()` helper running coroutines to completion on a dedicated, reused background event loop so the httpx AsyncClient stays bound to a single loop across calls - api.mustache: generate `_sync`, `_sync_with_http_info` and `_sync_without_preload_content` variants under `{{#supportHttpxSync}}` - api_doc / api_test: document and stub the sync variants - new sample petstore python-httpx-sync (bin/configs/python-httpx-sync.yaml) - docs/generators/python.md regenerated
Fix FILES
There was a problem hiding this comment.
25 issues found across 397 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/CircularAllOfRef.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/CircularAllOfRef.md:21">
P1: Documentation example calls `to_json()` on the class instead of the instance.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/Color.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/Color.md:20">
P2: Documentation example calls `to_json()` on the class (`Color.to_json()`) instead of the instance (`color_instance.to_json()`). Since `to_json` is an instance method requiring `self`, copying this snippet will raise a TypeError.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/AdditionalPropertiesClass.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/AdditionalPropertiesClass.md:22">
P2: Documentation example calls `to_json()` on the class instead of the instance, which will cause a runtime TypeError since `to_json()` is an instance method.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/ArrayOfArrayOfModel.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/ArrayOfArrayOfModel.md:20">
P2: Documentation example incorrectly calls `to_json()` on the class instead of the instance. The example creates `array_of_array_of_model_instance` but then calls `ArrayOfArrayOfModel.to_json()`, which will fail at runtime since `to_json(self)` is an instance method. Should call `array_of_array_of_model_instance.to_json()` instead.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/AdditionalPropertiesObject.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/AdditionalPropertiesObject.md:20">
P1: Documentation example calls `to_json()` on the class instead of the instance, which will fail at runtime since `to_json` is an instance method.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/ArrayOfNumberOnly.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/ArrayOfNumberOnly.md:20">
P1: Documentation example calls `to_json()` on the model class instead of the instance, causing a runtime `TypeError` for users who copy the snippet.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/AllOfWithSingleRef.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/AllOfWithSingleRef.md:21">
P2: Documentation example incorrectly calls `to_json()` on the class instead of the instance.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/BaseDiscriminator.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/BaseDiscriminator.md:20">
P1: Documentation example calls `to_json()` on the class instead of the instance, which will raise a TypeError because `to_json` is an instance method.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/Cat.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/Cat.md:20">
P2: Documentation example uses incorrect method invocation: `Cat.to_json()` should be `cat_instance.to_json()`. The `to_json` method is an instance method requiring `self`, so calling it on the class would raise a `TypeError` when users copy-paste the example.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/CircularReferenceModel.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/CircularReferenceModel.md:21">
P2: Documentation example calls `to_json` on the class instead of the instance, causing a runtime error for users following the snippet.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/Animal.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/Animal.md:21">
P2: Documentation example incorrectly calls `to_json()` on the class instead of the instance, which would raise a `TypeError` since `to_json` is an instance method.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/ArrayTest.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/ArrayTest.md:23">
P2: Documentation example calls `to_json` on the class instead of the instance, producing broken copy-paste usage that will raise a `TypeError` at runtime.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/Category.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/Category.md:21">
P2: Generated docs example incorrectly calls `to_json()` on the class instead of the instance, which will raise a TypeError.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/Capitalization.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/Capitalization.md:25">
P2: Documentation example calls `to_json()` on the class instead of the instance</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/AnyOfColor.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/AnyOfColor.md:20">
P2: Documentation example calls `to_json()` on the class instead of the parsed instance.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/DanishPig.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/DanishPig.md:21">
P1: Documentation example incorrectly calls `to_json()` as a class method instead of on the instance.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/AdditionalPropertiesAnyType.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/AdditionalPropertiesAnyType.md:20">
P1: Documentation example calls `to_json()` on the class instead of the instance, which will raise a TypeError at runtime because `to_json` is an instance method.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/ArrayOfMapModel.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/ArrayOfMapModel.md:20">
P2: Documentation example incorrectly calls `to_json()` on the class instead of the instance</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/Creature.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/Creature.md:21">
P2: Documentation example calls `to_json()` on the class instead of the instance</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/AllOfSuperModel.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/AllOfSuperModel.md:20">
P2: Model docs example calls `to_json()` on the class instead of the instance, which would raise a TypeError if copied by users.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/Bathing.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/Bathing.md:22">
P2: Documentation example incorrectly calls `to_json()` as a class method instead of on the instance `bathing_instance`, which would cause a TypeError since `to_json` is an instance method.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/AnotherFakeApi.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/AnotherFakeApi.md:13">
P2: sync-enabled sample docs advertise `_sync` methods but provide only async code examples</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/CreatureInfo.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/CreatureInfo.md:20">
P2: Model doc example calls `to_json()` as a class method instead of on the instance</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/BasquePig.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/BasquePig.md:21">
P2: Model example docs call `to_json()` on the class (`BasquePig.to_json()`) instead of the instance, which will raise a `TypeError` at runtime because `to_json` is defined as an instance method (`def to_json(self)`).</violation>
</file>
<file name="modules/openapi-generator/src/main/resources/python/httpx/sync_helper.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/python/httpx/sync_helper.mustache:48">
P2: `run_sync` lacks runtime protection against being called from within an active event loop, risking event-loop freeze or deadlock</violation>
</file>
Note: This PR contains a large number of files. cubic only reviews up to 100 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review.
On a pro plan you can use ultrareview for larger PRs.
Re-trigger cubic
| # create an instance of CircularAllOfRef from a JSON string | ||
| circular_all_of_ref_instance = CircularAllOfRef.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(CircularAllOfRef.to_json()) |
There was a problem hiding this comment.
P1: Documentation example calls to_json() on the class instead of the instance.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/python-httpx-sync/docs/CircularAllOfRef.md, line 21:
<comment>Documentation example calls `to_json()` on the class instead of the instance.</comment>
<file context>
@@ -0,0 +1,30 @@
+# create an instance of CircularAllOfRef from a JSON string
+circular_all_of_ref_instance = CircularAllOfRef.from_json(json)
+# print the JSON string representation of the object
+print(CircularAllOfRef.to_json())
+
+# convert the object into a dict
</file context>
| print(CircularAllOfRef.to_json()) | |
| print(circular_all_of_ref_instance.to_json()) |
| # create an instance of AdditionalPropertiesObject from a JSON string | ||
| additional_properties_object_instance = AdditionalPropertiesObject.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(AdditionalPropertiesObject.to_json()) |
There was a problem hiding this comment.
P1: Documentation example calls to_json() on the class instead of the instance, which will fail at runtime since to_json is an instance method.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/python-httpx-sync/docs/AdditionalPropertiesObject.md, line 20:
<comment>Documentation example calls `to_json()` on the class instead of the instance, which will fail at runtime since `to_json` is an instance method.</comment>
<file context>
@@ -0,0 +1,29 @@
+# create an instance of AdditionalPropertiesObject from a JSON string
+additional_properties_object_instance = AdditionalPropertiesObject.from_json(json)
+# print the JSON string representation of the object
+print(AdditionalPropertiesObject.to_json())
+
+# convert the object into a dict
</file context>
| print(AdditionalPropertiesObject.to_json()) | |
| print(additional_properties_object_instance.to_json()) |
| # create an instance of ArrayOfNumberOnly from a JSON string | ||
| array_of_number_only_instance = ArrayOfNumberOnly.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(ArrayOfNumberOnly.to_json()) |
There was a problem hiding this comment.
P1: Documentation example calls to_json() on the model class instead of the instance, causing a runtime TypeError for users who copy the snippet.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/python-httpx-sync/docs/ArrayOfNumberOnly.md, line 20:
<comment>Documentation example calls `to_json()` on the model class instead of the instance, causing a runtime `TypeError` for users who copy the snippet.</comment>
<file context>
@@ -0,0 +1,29 @@
+# create an instance of ArrayOfNumberOnly from a JSON string
+array_of_number_only_instance = ArrayOfNumberOnly.from_json(json)
+# print the JSON string representation of the object
+print(ArrayOfNumberOnly.to_json())
+
+# convert the object into a dict
</file context>
| print(ArrayOfNumberOnly.to_json()) | |
| print(array_of_number_only_instance.to_json()) |
| # create an instance of BaseDiscriminator from a JSON string | ||
| base_discriminator_instance = BaseDiscriminator.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(BaseDiscriminator.to_json()) |
There was a problem hiding this comment.
P1: Documentation example calls to_json() on the class instead of the instance, which will raise a TypeError because to_json is an instance method.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/python-httpx-sync/docs/BaseDiscriminator.md, line 20:
<comment>Documentation example calls `to_json()` on the class instead of the instance, which will raise a TypeError because `to_json` is an instance method.</comment>
<file context>
@@ -0,0 +1,29 @@
+# create an instance of BaseDiscriminator from a JSON string
+base_discriminator_instance = BaseDiscriminator.from_json(json)
+# print the JSON string representation of the object
+print(BaseDiscriminator.to_json())
+
+# convert the object into a dict
</file context>
| # create an instance of DanishPig from a JSON string | ||
| danish_pig_instance = DanishPig.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(DanishPig.to_json()) |
There was a problem hiding this comment.
P1: Documentation example incorrectly calls to_json() as a class method instead of on the instance.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/python-httpx-sync/docs/DanishPig.md, line 21:
<comment>Documentation example incorrectly calls `to_json()` as a class method instead of on the instance.</comment>
<file context>
@@ -0,0 +1,30 @@
+# create an instance of DanishPig from a JSON string
+danish_pig_instance = DanishPig.from_json(json)
+# print the JSON string representation of the object
+print(DanishPig.to_json())
+
+# convert the object into a dict
</file context>
| print(DanishPig.to_json()) | |
| print(danish_pig_instance.to_json()) |
| # create an instance of Bathing from a JSON string | ||
| bathing_instance = Bathing.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(Bathing.to_json()) |
There was a problem hiding this comment.
P2: Documentation example incorrectly calls to_json() as a class method instead of on the instance bathing_instance, which would cause a TypeError since to_json is an instance method.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/python-httpx-sync/docs/Bathing.md, line 22:
<comment>Documentation example incorrectly calls `to_json()` as a class method instead of on the instance `bathing_instance`, which would cause a TypeError since `to_json` is an instance method.</comment>
<file context>
@@ -0,0 +1,31 @@
+# create an instance of Bathing from a JSON string
+bathing_instance = Bathing.from_json(json)
+# print the JSON string representation of the object
+print(Bathing.to_json())
+
+# convert the object into a dict
</file context>
| print(Bathing.to_json()) | |
| print(bathing_instance.to_json()) |
| @@ -0,0 +1,79 @@ | |||
| # petstore_api.AnotherFakeApi | |||
There was a problem hiding this comment.
P2: sync-enabled sample docs advertise _sync methods but provide only async code examples
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/python-httpx-sync/docs/AnotherFakeApi.md, line 13:
<comment>sync-enabled sample docs advertise `_sync` methods but provide only async code examples</comment>
<file context>
@@ -0,0 +1,79 @@
+# **call_123_test_special_tags**
+> Client call_123_test_special_tags(client)
+
+**Synchronous variant:** `call_123_test_special_tags_sync(...)` — same parameters and return type, but blocks until completion instead of requiring `await`.
+
+To test special tags
</file context>
| # create an instance of CreatureInfo from a JSON string | ||
| creature_info_instance = CreatureInfo.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(CreatureInfo.to_json()) |
There was a problem hiding this comment.
P2: Model doc example calls to_json() as a class method instead of on the instance
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/python-httpx-sync/docs/CreatureInfo.md, line 20:
<comment>Model doc example calls `to_json()` as a class method instead of on the instance</comment>
<file context>
@@ -0,0 +1,29 @@
+# create an instance of CreatureInfo from a JSON string
+creature_info_instance = CreatureInfo.from_json(json)
+# print the JSON string representation of the object
+print(CreatureInfo.to_json())
+
+# convert the object into a dict
</file context>
| # create an instance of BasquePig from a JSON string | ||
| basque_pig_instance = BasquePig.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(BasquePig.to_json()) |
There was a problem hiding this comment.
P2: Model example docs call to_json() on the class (BasquePig.to_json()) instead of the instance, which will raise a TypeError at runtime because to_json is defined as an instance method (def to_json(self)).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/python-httpx-sync/docs/BasquePig.md, line 21:
<comment>Model example docs call `to_json()` on the class (`BasquePig.to_json()`) instead of the instance, which will raise a `TypeError` at runtime because `to_json` is defined as an instance method (`def to_json(self)`).</comment>
<file context>
@@ -0,0 +1,30 @@
+# create an instance of BasquePig from a JSON string
+basque_pig_instance = BasquePig.from_json(json)
+# print the JSON string representation of the object
+print(BasquePig.to_json())
+
+# convert the object into a dict
</file context>
| print(BasquePig.to_json()) | |
| print(basque_pig_instance.to_json()) |
| ``async`` code) as it would block that loop; use the ``await``-able async | ||
| methods directly in that case. | ||
| """ | ||
| return asyncio.run_coroutine_threadsafe(coro, _get_sync_loop()).result() |
There was a problem hiding this comment.
P2: run_sync lacks runtime protection against being called from within an active event loop, risking event-loop freeze or deadlock
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/python/httpx/sync_helper.mustache, line 48:
<comment>`run_sync` lacks runtime protection against being called from within an active event loop, risking event-loop freeze or deadlock</comment>
<file context>
@@ -0,0 +1,48 @@
+ ``async`` code) as it would block that loop; use the ``await``-able async
+ methods directly in that case.
+ """
+ return asyncio.run_coroutine_threadsafe(coro, _get_sync_loop()).result()
</file context>
This Pull Request aims to help @soapun in implementation of httpx Sync in open api codegen.
Add a new
supportHttpxSyncoption to the Python generator (httpx library only) that generates synchronous_syncvariants of each API method inside the same API class, instead of a separatehttpx-synclibrary.Following the maintainer's review feedback on #23044, each generated
_syncmethod simply calls its asynchronous counterpart and waits for completion, so both synchronous and asynchronous methods are available from the same SDK (matching the sync/async layout already used by other generators).supportHttpxSyncCLI option, wired for the httpx library only (ignored with a warning otherwise)run_sync()helper running coroutines to completion on a dedicated, reused background event loop so the httpx AsyncClient stays bound to a single loop across calls_sync,_sync_with_http_infoand_sync_without_preload_contentvariants under{{#supportHttpxSync}}PR checklist
Commit all changed files.
This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
These must match the expectations made by your contribution.
You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example
./bin/generate-samples.sh bin/configs/java*.IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
@cbornet (2017/09) @tomplus (2018/10) @krjakbrjak (2023/02) @fa0311 (2023/10) @multani (2023/10)
Summary by cubic
Add
supportHttpxSyncto the Pythonhttpxgenerator to produce synchronous_syncmethod variants alongside existing async methods. The sync methods call their async counterparts via a reusable background event loop so thehttpx.AsyncClientstays bound to one loop across calls.New Features
supportHttpxSync(forhttpxonly; ignored with a warning otherwise)._sync,_sync_with_http_info, and_sync_without_preload_contentmethods usingsync_helper.run_sync.httpx/sync_helper.mustache; updatedapi.mustache,api_doc.mustache,api_test.mustache; updated docs (docs/generators/python.md).python-httpx-syncand configbin/configs/python-httpx-sync.yaml.Bug Fixes
.openapi-generator/FILESlisting in thepython-httpx-syncsample.Written for commit 323754f. Summary will update on new commits.