Bug description
Several Python SDK methods are declared as collections.abc.Awaitable[None], but their successful futures return Rust unit (()). With the pinned PyO3 0.29.2 and pyo3-async-runtimes 0.29.0, that path resolves to an empty Python tuple rather than None.
This affects callers that check result is None and makes the runtime contract inconsistent with the generated type declarations.
Affected area / component
Python SDK
Versions
Audited checkout: e0c2423a, based on upstream 3a00b5ba1ebcca9ccfaab532b406c9591a862dcb. PyO3 0.29.2 and pyo3-async-runtimes 0.29.0.
Evidence and validation limits
Source inspection at e0c2423a2961ed6728c0cc92bf377c8a06dc251e identified 24 IggyClient methods and 3 IggyConsumer methods. This audit did not run runtime tests for those 27 methods. The standalone ping reproduction below is prepared but has not yet been run: the available Windows environment lacks the build tools and a usable local Linux/server environment.
The same conversion was observed in the initial delete_segments implementation: two real-server tests failed with assert () is None in this CI run. That new method was separately corrected for #4328. Its successful rerun does not establish runtime coverage for the other methods listed here.
Minimal reproduction to run
Build/install the Python SDK from the audited checkout and start an Iggy server from the same checkout, then run:
import asyncio
from apache_iggy import IggyClient
async def main():
client = IggyClient("127.0.0.1:8090")
await client.connect()
try:
result = await client.ping()
print(repr(result), type(result).__name__)
assert result is None
finally:
await client.shutdown()
asyncio.run(main())
Expected: None. Source-predicted result before a fix: () (tuple). The reproduction only opens a connection and pings the server; it does not create or delete resources.
Affected methods from source inspection
IggyClient: ping, login_user, update_user, delete_user, update_permissions, change_password, logout_user, connect, disconnect, shutdown, create_stream, update_stream, delete_stream, purge_stream, create_topic, update_topic, delete_topic, purge_topic, create_partitions, delete_partitions, create_consumer_group, delete_consumer_group, join_consumer_group, leave_consumer_group
IggyConsumer: store_offset, delete_offset, consume_messages
IggyClient.delete_segments and IggyProducer.shutdown explicitly return Python None and are excluded.
Conversion path
Source references: client bindings, consumer bindings, and type declarations.
- The wrappers declare
Awaitable[None] using a stub override, which does not change runtime conversion.
pyo3-async-runtimes 0.29.0 converts the future's successful value with val.into_py_any(py) (src/generic.rs:655).
- PyO3 0.29.2 implements
IntoPyObject for () using PyTuple::empty(py) (src/conversion.rs:561-572).
Related work and scope
#4166 proposes returning resource details from create_stream, create_topic, and create_consumer_group. #4167 proposes returning identity details from login_user. Those four methods should be coordinated with that work rather than assigned a new final return contract here.
For methods intended to retain a None contract, an explicit Python None conversion and a return-value regression test would align runtime behavior with the type declaration. The approach should be agreed before a broad fix. This report is separate from #4328.
Bug description
Several Python SDK methods are declared as
collections.abc.Awaitable[None], but their successful futures return Rust unit (()). With the pinned PyO3 0.29.2 and pyo3-async-runtimes 0.29.0, that path resolves to an empty Python tuple rather thanNone.This affects callers that check
result is Noneand makes the runtime contract inconsistent with the generated type declarations.Affected area / component
Python SDK
Versions
Audited checkout: e0c2423a, based on upstream
3a00b5ba1ebcca9ccfaab532b406c9591a862dcb. PyO3 0.29.2 and pyo3-async-runtimes 0.29.0.Evidence and validation limits
Source inspection at
e0c2423a2961ed6728c0cc92bf377c8a06dc251eidentified 24IggyClientmethods and 3IggyConsumermethods. This audit did not run runtime tests for those 27 methods. The standalonepingreproduction below is prepared but has not yet been run: the available Windows environment lacks the build tools and a usable local Linux/server environment.The same conversion was observed in the initial
delete_segmentsimplementation: two real-server tests failed withassert () is Nonein this CI run. That new method was separately corrected for #4328. Its successful rerun does not establish runtime coverage for the other methods listed here.Minimal reproduction to run
Build/install the Python SDK from the audited checkout and start an Iggy server from the same checkout, then run:
Expected:
None. Source-predicted result before a fix:()(tuple). The reproduction only opens a connection and pings the server; it does not create or delete resources.Affected methods from source inspection
IggyClient:ping,login_user,update_user,delete_user,update_permissions,change_password,logout_user,connect,disconnect,shutdown,create_stream,update_stream,delete_stream,purge_stream,create_topic,update_topic,delete_topic,purge_topic,create_partitions,delete_partitions,create_consumer_group,delete_consumer_group,join_consumer_group,leave_consumer_groupIggyConsumer:store_offset,delete_offset,consume_messagesIggyClient.delete_segmentsandIggyProducer.shutdownexplicitly return PythonNoneand are excluded.Conversion path
Source references: client bindings, consumer bindings, and type declarations.
Awaitable[None]using a stub override, which does not change runtime conversion.pyo3-async-runtimes0.29.0 converts the future's successful value withval.into_py_any(py)(src/generic.rs:655).IntoPyObject for ()usingPyTuple::empty(py)(src/conversion.rs:561-572).Related work and scope
#4166 proposes returning resource details from
create_stream,create_topic, andcreate_consumer_group. #4167 proposes returning identity details fromlogin_user. Those four methods should be coordinated with that work rather than assigned a new final return contract here.For methods intended to retain a
Nonecontract, an explicit PythonNoneconversion and a return-value regression test would align runtime behavior with the type declaration. The approach should be agreed before a broad fix. This report is separate from #4328.