Skip to content

BREAKING: Remove constructor callbacks in favor of event emitter pattern#33

Merged
eman merged 7 commits intomainfrom
remove-constructor-callbacks
Nov 2, 2025
Merged

BREAKING: Remove constructor callbacks in favor of event emitter pattern#33
eman merged 7 commits intomainfrom
remove-constructor-callbacks

Conversation

@eman
Copy link
Copy Markdown
Owner

@eman eman commented Nov 2, 2025

Summary

This PR removes the duplicate callback parameters from the NavienMqttClient constructor and standardizes on the event emitter pattern for all client events.

Breaking Changes

Removed constructor parameters:

  • on_connection_interrupted
  • on_connection_resumed

Migration:

# OLD (removed in v6.0.0)
mqtt_client = NavienMqttClient(
    auth_client,
    on_connection_interrupted=on_interrupted,
    on_connection_resumed=on_resumed,
)

# NEW (use event emitter pattern)
mqtt_client = NavienMqttClient(auth_client)
mqtt_client.on('connection_interrupted', on_interrupted)
mqtt_client.on('connection_resumed', on_resumed)

Benefits

  1. Multiple listeners per event - Not limited to one callback
  2. Consistent API - Same pattern as temperature_changed, mode_changed, etc.
  3. Dynamic management - Add/remove listeners at runtime with .on() and .off()
  4. Async support - Event handlers can be async functions
  5. Priority-based execution - Control order of handler execution
  6. Cleaner code - Separation of client creation and event registration

Changes

Code Changes

  • src/nwp500/mqtt_client.py (-25 lines)
    • Removed constructor callback parameters
    • Removed callback storage and invocation logic
    • Simplified constructor signature

Example Updates

  • examples/command_queue_demo.py - Updated to use event emitter
  • examples/reconnection_demo.py - Updated to use event emitter
  • examples/event_emitter_demo.py - Already using correct pattern ✓

Documentation Updates

  • docs/python_api/mqtt_client.rst - Updated API docs and examples
  • .github/copilot-instructions.md - Added backward compatibility policy
  • CHANGELOG.rst - Added v6.0.0 entry with migration guide

Validation

✅ Type checking: No errors
✅ Linting: All checks passed
✅ Syntax: All files compile successfully
✅ References: No remaining old pattern usage

Version Impact

This requires a major version bump (v5.0.2 → v6.0.0) due to breaking API changes.

Rationale

The library is young with no external clients. This change eliminates duplicate functionality and establishes a single, consistent pattern for event handling across the entire API.

eman added 6 commits November 2, 2025 10:50
- Remove on_connection_interrupted and on_connection_resumed parameters from NavienMqttClient
- Update examples to use event emitter pattern (mqtt_client.on('connection_interrupted', ...))
- Update documentation to reflect new pattern
- Add backward compatibility policy to Copilot instructions
- Update CHANGELOG.rst with migration guide

BREAKING CHANGE: Constructor callbacks removed. Use event emitter pattern instead:

  # Old (removed)
  mqtt_client = NavienMqttClient(auth, on_connection_interrupted=handler)

  # New
  mqtt_client = NavienMqttClient(auth)
  mqtt_client.on('connection_interrupted', handler)

Benefits:
- Multiple listeners per event
- Consistent API with other events
- Dynamic listener management
- Async handler support
These variables are not legacy or backward compatibility code - they are
essential connection state tracking used 33+ times throughout the codebase.

- _connected: Simpler to check than _connection_manager.is_connected
- _connection: Passed to MqttSubscriptionManager which needs raw connection
- Both: Handle the case before connect() when _connection_manager is None

The comment was misleading as it suggested these should be removed eventually,
when in fact they serve important architectural purposes.
Changed:
- 'Update legacy state for backward compatibility' → 'Update connection state'
- 'Update legacy state' → 'Clear connection state'

These variables are essential connection state tracking, not legacy code.
BREAKING CHANGE: Exception re-exports removed from api_client and auth modules.

Removed:
- APIError re-export from api_client module
- AuthenticationError, InvalidCredentialsError, TokenExpiredError,
  TokenRefreshError re-exports from auth module

Migration:
  # Old (removed)
  from nwp500.api_client import APIError
  from nwp500.auth import AuthenticationError

  # New (import from exceptions or package root)
  from nwp500.exceptions import APIError, AuthenticationError
  # OR
  from nwp500 import APIError, AuthenticationError

Updated all examples to import exceptions from correct module.

Rationale: Library is young with no external clients. Removing backward
compatibility prevents accumulation of legacy patterns and maintains clean
architecture.
- Fix line length in connection state comment (80 char limit)
- Import exceptions from exceptions module (not auth/api_client)
- Remove unused type: ignore comment

All CI checks now pass:
✅ Ruff linting
✅ Ruff formatting
✅ Mypy type checking
- Fix test_auth.py to import exceptions from exceptions module
- Update copilot instructions to make validation checks REQUIRED before
  completing any task
- All checks now passing:
  ✅ Tests: 123/123 passed
  ✅ Linting: All checks passed
  ✅ Type checking: No errors
@eman eman requested a review from Copilot November 2, 2025 19:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR removes duplicate callback parameters from the NavienMqttClient constructor, standardizing on the event emitter pattern for all connection events. This is a breaking change that simplifies the API by eliminating redundant functionality and establishing a consistent event-driven architecture.

Key Changes:

  • Removed on_connection_interrupted and on_connection_resumed constructor parameters
  • Standardized all examples to use the .on() event emitter pattern
  • Cleaned up backward compatibility exception re-exports from api_client and auth modules
  • Updated documentation to reflect the new event-only approach

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/nwp500/mqtt_client.py Removed constructor callback parameters and internal callback invocation logic
src/nwp500/auth.py Removed backward compatibility exception re-exports from __all__
src/nwp500/api_client.py Removed backward compatibility exception re-exports and simplified imports
tests/test_auth.py Updated imports to use exceptions module
examples/reconnection_demo.py Migrated from constructor callbacks to event emitter pattern
examples/command_queue_demo.py Migrated from constructor callbacks to event emitter pattern
examples/test_api_client.py Updated imports to use exceptions module
examples/device_status_callback_debug.py Updated imports to use exceptions module
examples/device_status_callback.py Updated imports to use exceptions module
examples/device_feature_callback.py Updated imports to use exceptions module
docs/python_api/mqtt_client.rst Updated API documentation and examples to show event emitter pattern
CHANGELOG.rst Added v6.0.0 entry with breaking changes documentation and migration guide
.github/copilot-instructions.md Added backward compatibility policy and enhanced validation requirements

Comment on lines +179 to +181
# Connection state tracking
# Note: Simpler to check than _connection_manager.is_connected
# (which can be None before connect())
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

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

[nitpick] The comment spans lines 179-181, but the actual implementation detail being explained is only on line 182. The comment should be condensed to a single line or reformatted to be more concise since it's explaining a simple state tracking variable.

Suggested change
# Connection state tracking
# Note: Simpler to check than _connection_manager.is_connected
# (which can be None before connect())
# Tracks the current MQTT connection (simpler to check than _connection_manager.is_connected, which can be None before connect())

Copilot uses AI. Check for mistakes.
Address PR feedback: comment was unnecessarily verbose for simple
state tracking variables. Reduced from 3 lines to 1 concise line.
@eman eman merged commit cf69c2c into main Nov 2, 2025
10 checks passed
@eman eman deleted the remove-constructor-callbacks branch November 2, 2025 19:58
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.

2 participants