Conversation
Add a public EventBus.remove(event_pattern, handler) method so callers can unsubscribe a handler registered with EventBus.on(). Returns True if the handler was found and removed, False otherwise. Extract event-key resolution from on() into _get_event_key() and reuse it in on() and remove(), and refactor expect() cleanup to use remove(). Co-Authored-By: Claude Code <noreply@anthropic.com>
There was a problem hiding this comment.
2 issues found across 2 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="bubus/service.py">
<violation number="1" location="bubus/service.py:456">
P3: After removing the last handler for an event key, the key remains in `self.handlers` as an empty list because the method never cleans up the entry. Since `handlers` is a `defaultdict(list)`, repeated remove()/expect() calls leave many empty keys, which accumulates over the bus lifetime and inflates `len(self.handlers)` shown in `__str__`. Delete the key when its list becomes empty.</violation>
<violation number="2" location="bubus/service.py:483">
P2: When a handler is typed for a concrete event, strict type checking rejects `remove(PingEvent, handler)` even though `on(PingEvent, handler)` accepts it. Add `remove()` overloads matching `on()` or otherwise preserve the handler's concrete event type.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
| return event_pattern.__name__ # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType] | ||
| return str(event_pattern) | ||
|
|
||
| def remove(self, event_pattern: EventPatternType, handler: ContravariantEventHandler['BaseEvent[Any]']) -> bool: |
There was a problem hiding this comment.
P2: When a handler is typed for a concrete event, strict type checking rejects remove(PingEvent, handler) even though on(PingEvent, handler) accepts it. Add remove() overloads matching on() or otherwise preserve the handler's concrete event type.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At bubus/service.py, line 483:
<comment>When a handler is typed for a concrete event, strict type checking rejects `remove(PingEvent, handler)` even though `on(PingEvent, handler)` accepts it. Add `remove()` overloads matching `on()` or otherwise preserve the handler's concrete event type.</comment>
<file context>
@@ -482,6 +472,38 @@ def on(
+ return event_pattern.__name__ # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
+ return str(event_pattern)
+
+ def remove(self, event_pattern: EventPatternType, handler: ContravariantEventHandler['BaseEvent[Any]']) -> bool:
+ """
+ Unsubscribe a previously registered handler from events matching a pattern.
</file context>
|
|
||
| # Ensure event_key is definitely a string at this point | ||
| assert isinstance(event_key, str) | ||
| event_key = self._get_event_key(event_pattern) |
There was a problem hiding this comment.
P3: After removing the last handler for an event key, the key remains in self.handlers as an empty list because the method never cleans up the entry. Since handlers is a defaultdict(list), repeated remove()/expect() calls leave many empty keys, which accumulates over the bus lifetime and inflates len(self.handlers) shown in __str__. Delete the key when its list becomes empty.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At bubus/service.py, line 456:
<comment>After removing the last handler for an event key, the key remains in `self.handlers` as an empty list because the method never cleans up the entry. Since `handlers` is a `defaultdict(list)`, repeated remove()/expect() calls leave many empty keys, which accumulates over the bus lifetime and inflates `len(self.handlers)` shown in `__str__`. Delete the key when its list becomes empty.</comment>
<file context>
@@ -453,17 +453,7 @@ def on(
-
- # Ensure event_key is definitely a string at this point
- assert isinstance(event_key, str)
+ event_key = self._get_event_key(event_pattern)
# Check for duplicate handler names
</file context>
What
Add a public
EventBus.remove(event_pattern, handler)method so callers can unsubscribe a handler registered withEventBus.on(). ReturnsTrueif the handler was found and removed,Falseotherwise.Also extract the event-key resolution from
on()into_get_event_key()and reuse it inon()andremove(), and refactorexpect()cleanup to useremove().Why
There is no way to unsubscribe after
EventBus.on()— the only cleanup path isexpect()'s internalself.handlers[...].remove(...). Closes #5.How tested
tests/test_remove_handler.py(4 cases: by class, by string name, scoped removal, wildcard*).🤖 Generated with Claude Code
Summary by cubic
Adds
EventBus.remove()to unsubscribe a handler registered withEventBus.on(). ReturnsTrueif the handler was found and removed,Falseotherwise. Closes #5.Changes
_get_event_key()and reuses it inon(),remove(), andexpect()cleanup.*wildcard.Written for commit 72b92d6. Summary will update on new commits.