Skip to content

[python] add supportHttpxSync option for sync httpx methods (#23032)#24096

Open
AntoineDuComptoirDesPharmacies wants to merge 2 commits into
OpenAPITools:masterfrom
LeComptoirDesPharmacies:feature/23032
Open

[python] add supportHttpxSync option for sync httpx methods (#23032)#24096
AntoineDuComptoirDesPharmacies wants to merge 2 commits into
OpenAPITools:masterfrom
LeComptoirDesPharmacies:feature/23032

Conversation

@AntoineDuComptoirDesPharmacies

@AntoineDuComptoirDesPharmacies AntoineDuComptoirDesPharmacies commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

This Pull Request aims to help @soapun in implementation of httpx Sync in open api codegen.

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 #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

PR checklist

  • [ X ] Read the contribution guidelines.
  • [ X ] Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    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.
  • [ X ] If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

@cbornet (2017/09) @tomplus (2018/10) @krjakbrjak (2023/02) @fa0311 (2023/10) @multani (2023/10)


Summary by cubic

Add supportHttpxSync to the Python httpx generator to produce synchronous _sync method variants alongside existing async methods. The sync methods call their async counterparts via a reusable background event loop so the httpx.AsyncClient stays bound to one loop across calls.

  • New Features

    • New CLI option supportHttpxSync (for httpx only; ignored with a warning otherwise).
    • Generates _sync, _sync_with_http_info, and _sync_without_preload_content methods using sync_helper.run_sync.
    • Added httpx/sync_helper.mustache; updated api.mustache, api_doc.mustache, api_test.mustache; updated docs (docs/generators/python.md).
    • Added sample python-httpx-sync and config bin/configs/python-httpx-sync.yaml.
  • Bug Fixes

    • Corrected the generated .openapi-generator/FILES listing in the python-httpx-sync sample.

Written for commit 323754f. Summary will update on new commits.

Review in cubic

…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

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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>
Suggested change
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())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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>
Suggested change
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())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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>
Suggested change
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())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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>
Suggested change
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())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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>
Suggested change
print(Bathing.to_json())
print(bathing_instance.to_json())

@@ -0,0 +1,79 @@
# petstore_api.AnotherFakeApi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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>
Suggested change
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()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant