Skip to content

Conversation

@ttypic
Copy link
Contributor

@ttypic ttypic commented Nov 11, 2025

Resolves #638

Getting rid of outdated and unmaintained methoddispatch dependency

Summary by CodeRabbit

  • Refactor
    • Publish methods are now asynchronous, requiring updates to calling code to use async/await patterns.
    • Removed unnecessary internal dependencies, reducing the dependency footprint.

@ttypic ttypic requested a review from VeskeR November 11, 2025 13:18
@coderabbitai
Copy link

coderabbitai bot commented Nov 11, 2025

Walkthrough

The pull request removes the methoddispatch library dependency by eliminating Channel class inheritance from SingleDispatch and replacing the singledispatch-based _publish method with an async dispatcher that uses explicit type checking. Related public methods (publish_message, publish_messages, publish_name_data) are converted to async methods. The dependency is also removed from pyproject.toml.

Changes

Cohort / File(s) Summary
Channel class refactoring
ably/rest/channel.py
Removed SingleDispatch inheritance; refactored _publish from singledispatch to async method with inline type branching (isinstance checks for Message, list, str); converted publish_message, publish_messages, and publish_name_data to async methods; removed all @_publish.register decorators.
Dependency removal
pyproject.toml
Removed methoddispatch from [tool.poetry.dependencies].

Sequence Diagram

sequenceDiagram
    participant Caller
    participant Channel
    participant _publish
    participant Handler

    Caller->>Channel: publish_message(message)
    Channel->>_publish: await _publish(message)
    _publish->>_publish: isinstance(arg, Message)?
    _publish->>Handler: Call publish_message logic
    Handler-->>Caller: Return result

    Caller->>Channel: publish_messages(messages)
    Channel->>_publish: await _publish(messages)
    _publish->>_publish: isinstance(arg, list)?
    _publish->>Handler: Call publish_messages logic
    Handler-->>Caller: Return result

    Caller->>Channel: publish_name_data(name, data)
    Channel->>_publish: await _publish(name, data)
    _publish->>_publish: isinstance(arg, str)?
    _publish->>Handler: Call publish_name_data logic
    Handler-->>Caller: Return result
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Straightforward refactoring from singledispatch to explicit type checking with minimal logic changes
  • Dependency removal is trivial
  • Verify that async conversion maintains intended behavior and doesn't break call sites
  • Check that all type branches in _publish are correctly handled and that exception handling for unrecognized types remains intact

Poem

🐰 One dispatch falls away, no more external sway,
Async branches bloom where singledispatch held sway,
Type checks now explicit, our code runs direct,
Simpler dependencies—just what we'd expect! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the primary changes: removing methoddispatch dependency and simplifying _publish implementation, matching the core objectives of the PR.
Linked Issues check ✅ Passed The PR successfully addresses issue #638 by removing methoddispatch entirely and implementing a simplified _publish dispatcher with isinstance checks instead of singledispatch.
Out of Scope Changes check ✅ Passed All changes are directly related to removing methoddispatch and refactoring _publish; no extraneous modifications detected in the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ECO-5638/get-rid-of-methoddispatch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot temporarily deployed to staging/pull/639/features November 11, 2025 13:18 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ably/rest/channel.py (1)

104-106: Add params parameter to publish_name_data method.

Line 104: The publish_name_data method is missing the params parameter that exists in publish_message and publish_messages. The public publish() dispatcher (line 126) passes **kwargs to publish_name_data, which means users calling .publish(name='x', data='y', params={...}) will hit a TypeError at runtime since the method doesn't accept the params kwarg.

Update line 104 from:

async def publish_name_data(self, name, data, timeout=None):

To:

async def publish_name_data(self, name, data, params=None, timeout=None):

And update line 106 to pass params along with timeout:

return await self.publish_messages(messages, params=params, timeout=timeout)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d0d15ad and ede01a3.

⛔ Files ignored due to path filters (1)
  • poetry.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • ably/rest/channel.py (2 hunks)
  • pyproject.toml (0 hunks)
💤 Files with no reviewable changes (1)
  • pyproject.toml
🧰 Additional context used
🧬 Code graph analysis (1)
ably/rest/channel.py (1)
ably/types/message.py (1)
  • Message (24-231)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: check (3.11)
  • GitHub Check: check (3.13)
  • GitHub Check: check (3.10)
  • GitHub Check: check (3.12)
  • GitHub Check: check (3.8)
  • GitHub Check: check (3.9)
  • GitHub Check: check (3.7)
🔇 Additional comments (2)
ably/rest/channel.py (2)

21-21: LGTM: Dependency removed successfully.

The removal of SingleDispatch inheritance successfully eliminates the methoddispatch dependency while maintaining the same public API.


108-134: LGTM: Backwards compatibility preserved.

The publish method correctly maintains backwards compatibility for various calling patterns (kwargs with name/data, kwargs with messages, positional args) and properly delegates to the refactored _publish dispatcher.

Comment on lines +78 to +86
async def _publish(self, arg, *args, **kwargs):
if isinstance(arg, Message):
return await self.publish_message(arg, *args, **kwargs)
elif isinstance(arg, list):
return await self.publish_messages(arg, *args, **kwargs)
elif isinstance(arg, str):
return await self.publish_name_data(arg, *args, **kwargs)
else:
raise TypeError('Unexpected type %s' % type(arg))
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate list contents to prevent runtime errors.

The isinstance(arg, list) check accepts any list, not specifically lists of Message objects. Passing a list of non-Message objects (e.g., strings, dicts) will cause runtime errors downstream in __publish_request_body when attempting to call Message methods.

Consider adding validation:

 async def _publish(self, arg, *args, **kwargs):
     if isinstance(arg, Message):
         return await self.publish_message(arg, *args, **kwargs)
     elif isinstance(arg, list):
+        if arg and not all(isinstance(item, Message) for item in arg):
+            raise TypeError('All list items must be Message objects')
         return await self.publish_messages(arg, *args, **kwargs)
     elif isinstance(arg, str):
         return await self.publish_name_data(arg, *args, **kwargs)
     else:
-        raise TypeError('Unexpected type %s' % type(arg))
+        raise TypeError(
+            f'Expected Message, list of Messages, or str for name, got {type(arg).__name__}'
+        )

Additionally, consider adding type hints to prevent misuse:

async def _publish(
    self, 
    arg: Message | list[Message] | str, 
    *args, 
    **kwargs
) -> None:
🤖 Prompt for AI Agents
In ably/rest/channel.py around lines 78 to 86, the branch that accepts lists
doesn't validate that list elements are Message instances which can cause
runtime errors later; update the function signature to include type hints (e.g.,
arg: Message | list[Message] | str) and add explicit validation when arg is a
list: iterate the list, verify each item is an instance of Message, and raise a
TypeError with a clear message if any item is not; keep existing behavior for
Message and str branches and ensure the error message includes the offending
item's type/index for easier debugging.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Could we not rely on methoddispatch as a depency? (at least until it gets some TLC)

2 participants