Feature/23032 alternative#24104
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
…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, alongside the existing asynchronous methods. This addresses the review feedback on OpenAPITools#23044: instead of a separate `httpx-sync` library, both sync and async methods live in the same generated SDK. The `_sync` methods are genuinely synchronous (backed by httpx.Client) — no event loop or coroutine wrapping. - PythonClientCodegen: new `supportHttpxSync` CLI option, wired for the httpx library only (ignored with a warning otherwise) - httpx/rest.mustache: RESTClientObject also holds an httpx.Client and exposes request_sync()/close_sync(); RESTResponse gets read_sync() - api_client.mustache: add call_api_sync(), a sync context manager and close_sync() - 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
There was a problem hiding this comment.
24 issues found across 398 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/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, which will raise a `TypeError: missing 1 required positional argument: 'self'` at runtime.</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: Model usage example calls `to_json` on the class instead of the instance, producing broken copy-paste code.</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: Documentation example calls `to_json` on the class instead of the instance, producing broken sample code.</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: Documentation example calls `to_json()` on the class instead of the instance, which raises a `TypeError` at runtime.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/Client.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/Client.md:20">
P2: Documentation example calls `to_json` on the class instead of the created instance, producing invalid sample code.</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 calls `to_json` on the class (`Animal.to_json()`) instead of the instance (`animal_instance.to_json()`), which will cause a runtime TypeError since `to_json` is an instance method requiring `self`.</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 `Color.to_json()` as a class method instead of an instance method. The `to_json` method in `color.py` is an instance method (`def to_json(self) -> str`), so `print(Color.to_json())` would fail at runtime. It should be `print(color_instance.to_json())` to match the preceding instance creation.</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: Documentation example incorrectly calls `to_json()` on the class instead of the instance, producing a non-runnable usage example.</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">
P1: Documentation example incorrectly calls `to_json` on the class instead of the instance, which will fail at runtime because `to_json` is an instance method.</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">
P2: Model docs example calls `to_json()` on the class instead of the instance, which will cause a runtime error 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">
P2: Documentation example invokes `to_json` as a class method instead of on the instance, which will cause a TypeError when copied.</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">
P1: Model usage example calls `to_json` on the `Cat` class instead of the instance, producing failing sample code.</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 incorrectly calls `to_json` on the class instead of the model instance</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/AdditionalPropertiesWithDescriptionOnly.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/AdditionalPropertiesWithDescriptionOnly.md:20">
P2: Documentation example calls `to_json()` on the class instead of the instance, which causes a runtime `TypeError` if copied verbatim.</violation>
</file>
<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, which will raise a `TypeError` when users copy-paste the snippet. `to_json` is an instance method but is invoked as `CircularAllOfRef.to_json()` rather than `circular_all_of_ref_instance.to_json()`.</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">
P2: Documentation example calls class-level to_json() instead of instance-level, which will cause a TypeError at runtime.</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">
P2: Documentation example calls `to_json()` on the class instead of the instance, which will raise a `TypeError` at runtime since `to_json` is an instance method.</violation>
</file>
<file name="samples/openapi3/client/petstore/python-httpx-sync/docs/ClassModel.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/ClassModel.md:21">
P2: Documentation example 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/ArrayOfArrayOfNumberOnly.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/ArrayOfArrayOfNumberOnly.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/CreatureInfo.md">
<violation number="1" location="samples/openapi3/client/petstore/python-httpx-sync/docs/CreatureInfo.md:16">
P2: Default JSON example omits required `name` field, so documented `from_json` usage will fail during deserialization.</violation>
<violation number="2" location="samples/openapi3/client/petstore/python-httpx-sync/docs/CreatureInfo.md:20">
P1: Documentation example calls `to_json` on the class instead of the instance, causing a runtime TypeError when copied.</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: Model documentation example calls `to_json()` on the class instead of the created instance, which would cause a `TypeError` at runtime since `to_json(self)` is an instance method.</violation>
</file>
<file name="docs/generators/python.md">
<violation number="1" location="docs/generators/python.md:38">
P2: Documentation for `supportHttpxSync` incorrectly states that sync methods wrap async methods, while the implementation and PR description both indicate they use independent synchronous code paths (`call_api_sync`, `read_sync`).</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:36">
P1: Generated sync-client documentation example is non-runnable and mismatched: it uses top-level async/await syntax and invokes the async method instead of the sync variant.</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 ArrayOfArrayOfModel from a JSON string | ||
| array_of_array_of_model_instance = ArrayOfArrayOfModel.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(ArrayOfArrayOfModel.to_json()) |
There was a problem hiding this comment.
P1: Documentation example incorrectly calls to_json on the class instead of the instance, which will fail at runtime 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/ArrayOfArrayOfModel.md, line 20:
<comment>Documentation example incorrectly calls `to_json` on the class instead of the instance, which will fail at runtime because `to_json` is an instance method.</comment>
<file context>
@@ -0,0 +1,29 @@
+# create an instance of ArrayOfArrayOfModel from a JSON string
+array_of_array_of_model_instance = ArrayOfArrayOfModel.from_json(json)
+# print the JSON string representation of the object
+print(ArrayOfArrayOfModel.to_json())
+
+# convert the object into a dict
</file context>
| print(ArrayOfArrayOfModel.to_json()) | |
| print(array_of_array_of_model_instance.to_json()) |
| # create an instance of Cat from a JSON string | ||
| cat_instance = Cat.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(Cat.to_json()) |
There was a problem hiding this comment.
P1: Model usage example calls to_json on the Cat class instead of the instance, producing failing sample code.
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/Cat.md, line 20:
<comment>Model usage example calls `to_json` on the `Cat` class instead of the instance, producing failing sample code.</comment>
<file context>
@@ -0,0 +1,29 @@
+# create an instance of Cat from a JSON string
+cat_instance = Cat.from_json(json)
+# print the JSON string representation of the object
+print(Cat.to_json())
+
+# convert the object into a dict
</file context>
| print(Cat.to_json()) | |
| print(cat_instance.to_json()) |
| # 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, which will raise a TypeError when users copy-paste the snippet. to_json is an instance method but is invoked as CircularAllOfRef.to_json() rather than circular_all_of_ref_instance.to_json().
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, which will raise a `TypeError` when users copy-paste the snippet. `to_json` is an instance method but is invoked as `CircularAllOfRef.to_json()` rather than `circular_all_of_ref_instance.to_json()`.</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 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.
P1: Documentation example calls to_json on the class instead of the instance, causing a runtime TypeError when copied.
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>Documentation example calls `to_json` on the class instead of the instance, causing a runtime TypeError when copied.</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>
| print(CreatureInfo.to_json()) | |
| print(creature_info_instance.to_json()) |
|
|
||
|
|
||
| # Enter a context with an instance of the API client | ||
| async with petstore_api.ApiClient(configuration) as api_client: |
There was a problem hiding this comment.
P1: Generated sync-client documentation example is non-runnable and mismatched: it uses top-level async/await syntax and invokes the async method instead of the sync variant.
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 36:
<comment>Generated sync-client documentation example is non-runnable and mismatched: it uses top-level async/await syntax and invokes the async method instead of the sync variant.</comment>
<file context>
@@ -0,0 +1,79 @@
+
+
+# Enter a context with an instance of the API client
+async with petstore_api.ApiClient(configuration) as api_client:
+ # Create an instance of the API class
+ api_instance = petstore_api.AnotherFakeApi(api_client)
</file context>
| # create an instance of ClassModel from a JSON string | ||
| class_model_instance = ClassModel.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(ClassModel.to_json()) |
There was a problem hiding this comment.
P2: Documentation example calls to_json() on the class instead of the instance, which will raise a TypeError.
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/ClassModel.md, line 21:
<comment>Documentation example calls `to_json()` on the class instead of the instance, which will raise a TypeError.</comment>
<file context>
@@ -0,0 +1,30 @@
+# create an instance of ClassModel from a JSON string
+class_model_instance = ClassModel.from_json(json)
+# print the JSON string representation of the object
+print(ClassModel.to_json())
+
+# convert the object into a dict
</file context>
| print(ClassModel.to_json()) | |
| print(class_model_instance.to_json()) |
| # create an instance of ArrayOfArrayOfNumberOnly from a JSON string | ||
| array_of_array_of_number_only_instance = ArrayOfArrayOfNumberOnly.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(ArrayOfArrayOfNumberOnly.to_json()) |
There was a problem hiding this comment.
P2: Documentation example incorrectly 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/ArrayOfArrayOfNumberOnly.md, line 20:
<comment>Documentation example incorrectly calls `to_json()` on the class instead of the instance</comment>
<file context>
@@ -0,0 +1,29 @@
+# create an instance of ArrayOfArrayOfNumberOnly from a JSON string
+array_of_array_of_number_only_instance = ArrayOfArrayOfNumberOnly.from_json(json)
+# print the JSON string representation of the object
+print(ArrayOfArrayOfNumberOnly.to_json())
+
+# convert the object into a dict
</file context>
| print(ArrayOfArrayOfNumberOnly.to_json()) | |
| print(array_of_array_of_number_only_instance.to_json()) |
| from petstore_api.models.creature_info import CreatureInfo | ||
|
|
||
| # TODO update the JSON string below | ||
| json = "{}" |
There was a problem hiding this comment.
P2: Default JSON example omits required name field, so documented from_json usage will fail during deserialization.
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 16:
<comment>Default JSON example omits required `name` field, so documented `from_json` usage will fail during deserialization.</comment>
<file context>
@@ -0,0 +1,29 @@
+from petstore_api.models.creature_info import CreatureInfo
+
+# TODO update the JSON string below
+json = "{}"
+# create an instance of CreatureInfo from a JSON string
+creature_info_instance = CreatureInfo.from_json(json)
</file context>
| json = "{}" | |
| json = '{"name": "name_example"}' |
| # create an instance of AdditionalPropertiesClass from a JSON string | ||
| additional_properties_class_instance = AdditionalPropertiesClass.from_json(json) | ||
| # print the JSON string representation of the object | ||
| print(AdditionalPropertiesClass.to_json()) |
There was a problem hiding this comment.
P2: Model documentation example calls to_json() on the class instead of the created instance, which would cause a TypeError at runtime since to_json(self) 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/AdditionalPropertiesClass.md, line 22:
<comment>Model documentation example calls `to_json()` on the class instead of the created instance, which would cause a `TypeError` at runtime since `to_json(self)` is an instance method.</comment>
<file context>
@@ -0,0 +1,31 @@
+# create an instance of AdditionalPropertiesClass from a JSON string
+additional_properties_class_instance = AdditionalPropertiesClass.from_json(json)
+# print the JSON string representation of the object
+print(AdditionalPropertiesClass.to_json())
+
+# convert the object into a dict
</file context>
| print(AdditionalPropertiesClass.to_json()) | |
| print(additional_properties_class_instance.to_json()) |
| |projectName|python project name in setup.py (e.g. petstore-api).| |null| | ||
| |recursionLimit|Set the recursion limit. If not set, use the system default value.| |null| | ||
| |setEnsureAsciiToFalse|When set to true, add `ensure_ascii=False` in json.dumps when creating the HTTP request body.| |false| | ||
| |supportHttpxSync|Generate synchronous '_sync' variants of each API method (httpx library only). Each '_sync' method simply calls the corresponding async method and waits for its completion, so both synchronous and asynchronous methods are available from the same API class.| |false| |
There was a problem hiding this comment.
P2: Documentation for supportHttpxSync incorrectly states that sync methods wrap async methods, while the implementation and PR description both indicate they use independent synchronous code paths (call_api_sync, read_sync).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/generators/python.md, line 38:
<comment>Documentation for `supportHttpxSync` incorrectly states that sync methods wrap async methods, while the implementation and PR description both indicate they use independent synchronous code paths (`call_api_sync`, `read_sync`).</comment>
<file context>
@@ -35,6 +35,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|projectName|python project name in setup.py (e.g. petstore-api).| |null|
|recursionLimit|Set the recursion limit. If not set, use the system default value.| |null|
|setEnsureAsciiToFalse|When set to true, add `ensure_ascii=False` in json.dumps when creating the HTTP request body.| |false|
+|supportHttpxSync|Generate synchronous '_sync' variants of each API method (httpx library only). Each '_sync' method simply calls the corresponding async method and waits for its completion, so both synchronous and asynchronous methods are available from the same API class.| |false|
|useOneOfDiscriminatorLookup|Use the discriminator's mapping in oneOf to speed up the model lookup. IMPORTANT: Validation (e.g. one and only one match in oneOf's schemas) will be skipped.| |false|
</file context>
| |supportHttpxSync|Generate synchronous '_sync' variants of each API method (httpx library only). Each '_sync' method simply calls the corresponding async method and waits for its completion, so both synchronous and asynchronous methods are available from the same API class.| |false| | |
| +|supportHttpxSync|Generate synchronous '_sync' variants of each API method (httpx library only). Each '_sync' method uses a synchronous code path that shares common logic with the async method, so both synchronous and asynchronous methods are available from the same API class.| |false| |
| @@ -0,0 +1,17 @@ | |||
| generatorName: python | |||
| outputDir: samples/openapi3/client/petstore/python-httpx-sync | |||
There was a problem hiding this comment.
please add the new folder to the github workflow as well
Alternative solution to the #23032 where sync methods do not use coroutine but instead they share a common code with async methods.
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
Adds
supportHttpxSyncto the Pythonhttpxgenerator to create synchronous_syncvariants for each API method in the same class. This exposes both async and blocking methods without a separate library.New Features
supportHttpxSyncoption in Python generator (only forhttpx)._sync,_sync_with_http_info, and_sync_without_preload_contentalongside async methods.ApiClientaddscall_api_sync()and a sync context manager (__enter__/__exit__) withclose_sync().httpxREST layer adds a dedicatedhttpx.Client,request_sync(),close_sync(), andRESTResponse.read_sync().bin/configs/python-httpx-sync.yamlandsamples/.../python-httpx-sync).Migration
additionalProperties.supportHttpxSync=truewhen generating a Python client withlibrary: httpx.method_sync(...)for blocking calls.Written for commit 3974cc5. Summary will update on new commits.