Skip to content

feat(python): add topic listing, update, delete and purge#3572

Open
mattp5657 wants to merge 6 commits into
apache:masterfrom
mattp5657:feat/python-sdk-topic-mgmt
Open

feat(python): add topic listing, update, delete and purge#3572
mattp5657 wants to merge 6 commits into
apache:masterfrom
mattp5657:feat/python-sdk-topic-mgmt

Conversation

@mattp5657

@mattp5657 mattp5657 commented Jun 26, 2026

Copy link
Copy Markdown

Which issue does this PR address?

Closes #3521

Rationale

Completes the Python SDK's topic management by adding the missing list, update, delete, and purge operations, which previously had no Python binding and forced callers to another SDK.

What changed?

The Python SDK exposed only create_topic and get_topic, so listing, updating, deleting, or purging topics required falling back to another SDK. TopicDetails also hid compression_algorithm and replication_factor, leaving the result of an update impossible to assert from Python.

get_topics, update_topic, delete_topic, and purge_topic now bind through to the Rust TopicClient, a new Topic type backs the list view, and TopicDetails exposes the two previously hidden fields. The new methods take stream_id to stay consistent with the Rust trait and the existing get_topic.

Local Execution

  • Passed
  • Pre-commit hooks ran

AI Usage

Claude was used to help generate and review this PR.

@mattp5657 mattp5657 force-pushed the feat/python-sdk-topic-mgmt branch from 2db95ac to 02a1008 Compare June 26, 2026 22:58
@mattp5657 mattp5657 force-pushed the feat/python-sdk-topic-mgmt branch from 02a1008 to ce94a0d Compare June 26, 2026 23:29
@mattp5657 mattp5657 marked this pull request as ready for review June 27, 2026 00:17
@github-actions github-actions Bot added the S-waiting-on-review PR is waiting on a reviewer label Jun 27, 2026

@slbotbm slbotbm 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.

Looks good at a first glance.

As an aside, please do not force push new code. Instead, address the review in well-formed commits. This helps me understand what changed since my last review.

You can write /ready on a new line in a comment to indicate that your PR is ready for review.

Comment thread foreign/python/src/client.rs Outdated
Comment on lines +246 to +247
/// Gets all topics in the given stream.
/// Returns a list of topics or a PyRuntimeError on failure.

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.

Let's change this to

 /// Get all topics in a stream.
///
/// Args:
///     stream_id: Stream identifier as `str | int`.
///
/// Returns:
///     An awaitable that resolves to `list[TopicDetails]`.
///
/// Raises:
///     PyRuntimeError: If the identifier is invalid or the request fails.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Wouldn't this break the pattern already established in client.rs. This also returns a list[Topic] similar to the Rust client. ex.

    /// Logs in the user with the given credentials.
    /// Returns `Ok(())` on success, or a PyRuntimeError on failure.

Comment thread foreign/python/src/client.rs Outdated
Comment on lines +266 to +267
/// Updates an existing topic with the given parameters.
/// Returns Ok(()) on successful topic update or a PyRuntimeError on failure.

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.

Change to

/// Update a topic in a stream.
///
/// Args:
///     stream_id: Stream identifier as `str | int`.
///     topic_id: Topic identifier as `str | int`.
///     name: Topic name as `str`.
///     compression_algorithm: Compression algorithm as `str | None`. Supported
///         values are `\"none\"` and `\"gzip\"`, case-insensitive.
///     replication_factor: Replication factor as `int | None`. Must be greater
///         than `0` when provided. If `None`, the server uses `1`.
///     message_expiry: Message retention period as `datetime.timedelta | None`.
///         If `None`, the server default is used, which currently means
///         messages do not expire.
///     max_topic_size: Maximum topic size in bytes as `int | None`. Use `0` to
///         request the server default, which is currently unlimited. If `None`,
///         the server default is also used.
///
/// Returns:
///     An awaitable that resolves to `None` when the topic is updated.
///
/// Raises:
///     PyRuntimeError: If an identifier or argument is invalid, or the update request fails.

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.

I'm already doing it for the rest of the functions right now. that's why i asked you to do it for your PR :)

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.

I'm already doing it for the rest of the functions right now. that's why i asked you to do it for your PR :)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Awesome, will do thank you for the clarification :)

Comment thread foreign/python/src/client.rs Outdated
Comment on lines +323 to +324
/// Deletes the topic with the given id from the given stream.
/// Returns Ok(()) on successful topic deletion or a PyRuntimeError on failure.

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.

Change to

/// Delete a topic from a stream.
///
/// Args:
///     stream_id: Stream identifier as `str | int`.
///     topic_id: Topic identifier as `str | int`.
///
/// Returns:
///     An awaitable that resolves to `None` when the topic is deleted.
///
/// Raises:
///     PyRuntimeError: If an identifier is invalid or the delete request fails.

Comment thread foreign/python/src/client.rs Outdated
Comment on lines +344 to +346

/// Purges all messages from the topic with the given id in the given stream.
/// Returns Ok(()) on successful topic purge or a PyRuntimeError on failure.

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.

change to

/// Purge all messages from a topic in a stream.
///
/// Args:
///     stream_id: Stream identifier as `str | int`.
///     topic_id: Topic identifier as `str | int`.
///
/// Returns:
///     An awaitable that resolves to `None` when the topic is purged.
///
/// Raises:
///     PyRuntimeError: If an identifier is invalid or the purge request fails.

Comment thread foreign/python/src/topic.rs Outdated
Comment on lines 18 to 19
use iggy::prelude::Topic as RustTopic;
use iggy::prelude::TopicDetails as RustTopicDetails;

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.

These can be merged together

Comment on lines +37 to +57
impl Topic {
#[getter]
pub fn id(&self) -> u32 {
self.inner.id
}

#[getter]
pub fn name(&self) -> String {
self.inner.name.to_string()
}

#[getter]
pub fn messages_count(&self) -> u64 {
self.inner.messages_count
}

#[getter]
pub fn partitions_count(&self) -> u32 {
self.inner.partitions_count
}
}

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.

Lets add getters for the following as well:

  • created_at
  • size
  • message_expiry
  • compression_algorithm
  • max_topic_size
  • replication_factor

Please also add docs to Topic and its getters in the style as shown in the review previously.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I added getters for compression_algorithm and replication_factor since those are simple scalars. The rest wrap richer types. message_expiry and max_topic_size are tri-state enums (IggyExpiry, MaxTopicSize) that the Rust client returns without losing information, so they need a proper Python representation rather than a one-line getter. I'd like to keep this PR scoped to the topic operations and handle message_expiry, max_topic_size, size, and created_at in a follow-up. I'll open an issue to track it and link it here.

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.

sure, please go ahead and open an issue

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.

sure, please go ahead and open an issue

Comment on lines +95 to +104

#[getter]
pub fn compression_algorithm(&self) -> String {
self.inner.compression_algorithm.to_string()
}

#[getter]
pub fn replication_factor(&self) -> u8 {
self.inner.replication_factor
}

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.

Let's add getters for the rest of the fields as well:

  • created_at
  • size
  • message_expiry
  • max_topic_size
  • partitions

With docs.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Same situation as the Topic getters. created_at, size, message_expiry, and max_topic_size wrap richer types (timestamp, byte size, and the IggyExpiry / MaxTopicSize tri-state enums), so they need a proper Python representation rather than one-line getters. partitions is a Vec, so exposing it also means adding a Partition class with its own getters. I'd like to handle all of these in the same follow-up to keep this PR scoped to the topic operations, and I'll cover them in the tracking issue.

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.

sure

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.

sure

@slbotbm slbotbm Jun 27, 2026

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.

The tests look good. I would like you to add some more tests though:

  • for all 4 functions, test what happens when you call the function repeatedly.
  • merge the tests calling the function before connect, and before login into one. No need for two tests.
  • purge_topic on non-existent stream
  • purge_topic on existing stream with non-existing topic
  • update_topic on non-existent stream
  • testing naming collision by trying to update a topic's name to one that another topic already possesses.
  • happy path tests for message_expiry and max_topic_size args in update_topic

Some additions is the current tests that can be made:

  • after purging the topic, check that all fields except message count remain the same.
  • for get_topics, check all fields you supply, or those that are deterministically set by the server. Do not check fields that are set randomly by the server.

I also liked your way of creating a class per function. Could you do that for the rest of the tests in this file? ie. create TestCreateTopic and TestGetTopic classes and split and move the existing tests under TestTopicOperations into these?

@slbotbm

slbotbm commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

/author

@github-actions github-actions Bot added S-waiting-on-author PR is waiting on author response and removed S-waiting-on-review PR is waiting on a reviewer labels Jun 27, 2026
@mattp5657

Copy link
Copy Markdown
Author

Appreciate the comments and have addressed most of them. The remaining Topic/TopicDetails getters are tracked in #3577 as a follow-up I'll take on after this merges.

@mattp5657

Copy link
Copy Markdown
Author

/ready

@github-actions github-actions Bot added S-waiting-on-review PR is waiting on a reviewer and removed S-waiting-on-author PR is waiting on author response labels Jun 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review PR is waiting on a reviewer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[python sdk] Add functions related to topic management

2 participants