Skip to content

refactor!: trim public API, remove dead code, deduplicate conversions#95

Merged
eman merged 3 commits into
mainfrom
refactor/architecture-cleanup
Jul 5, 2026
Merged

refactor!: trim public API, remove dead code, deduplicate conversions#95
eman merged 3 commits into
mainfrom
refactor/architecture-cleanup

Conversation

@eman

@eman eman commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Sixth batch from the comprehensive repo evaluation: architecture cleanup. Based on #94 (fix/protocol-correctness) because both touch temperature.py/control.py — merge #94 first, then retarget/merge this one.

Contains breaking changes — requires a major version bump.

Removed (breaking)

  • Deprecated .control property on NavienMqttClient: the @warnings.deprecated shim slated for v9.0.0 contradicts the project's documented no-backward-compat policy (remove immediately, don't deprecate). Use the delegated methods directly (client.set_power(...)).
  • Never-raised exception classes: TokenExpiredError, MqttSubscriptionError, DeviceNotFoundError, DeviceOfflineError, DeviceOperationError had zero raise sites in the library, so no working error handling can break. Catch AuthenticationError/MqttError/DeviceError instead. Hierarchy docs updated.
  • Internal plumbing un-exported from the top-level namespace (__all__ 103 → 87): requires_capability, MqttDeviceInfoCache, MqttDeviceCapabilityChecker, log_performance, and the eight bit-encoding helpers. All remain importable from their owning modules (nwp500.encoding, etc.); docs and examples updated to match.
  • Dead code: nwp500/cli/commands.py (never imported anywhere; its command metadata had drifted from the real click commands), converters.str_enum_validator, unused module-level temperature.half_celsius_to_fahrenheit/deci_celsius_to_fahrenheit wrappers, the no-op NavienMqttClient._on_message_received placeholder (real dispatch lives in the subscription manager), duplicated-then-unused _line_width calculations in the CLI formatters, and identical-branch isinstance conditionals in div_10/mul_10.

Deduplicated (behavior unchanged)

  • Temperature classes: HalfCelsius/DeciCelsius/RawCelsius/DeciCelsiusDelta were four near-identical copies differing only in a scale constant. Conversions are now implemented once on Temperature with a per-class _scale: ClassVar; only RawCelsius (formula-specific rounding) and DeciCelsiusDelta (no ±32 offset) override. Doctests all pass.
  • field_factory: the 6-line json_schema_extra merge block was pasted 4×; extracted into one private _metadata_field() helper.
  • Device booleans: mqtt/control.py now uses converters.device_bool_from_python() instead of inline 2 if enabled else 1 literals.
  • Version import: auth.py resolves the version from distribution metadata instead of from . import __version__ (an order-dependent near-circular import with __init__.py).

Net: −575 lines.

Deferred follow-ups (tracked from the evaluation, too large for one PR)

  • Slimming mqtt/client.py (~1500 lines) into a thin façade over its helper modules
  • Merging the doubled CLI formatting stacks (output_formatters.py + rich_output.py, ~2100 lines) behind a presentation-neutral layer
  • Wrapping awscrt types (QoS/Connection/AwsCrtError) out of public signatures
  • Unifying the two event systems (events.py string emitter vs typed mqtt_events.py)
  • Removing model computed_field dependence on the global unit-system state

Tests

New tests/test_public_api.py: every __all__ name resolves, internal plumbing absent, removed exceptions gone, encoding helpers importable from nwp500.encoding. Removed the 7 tests that only exercised the deleted exception classes.

Validation

  • pytest: 522 passed
  • ruff check / ruff format --check: clean
  • pyright src/nwp500: 0 errors
  • mypy src/nwp500: no issues

emmanuel added 2 commits July 5, 2026 08:23
- Send flat raw protocol payloads for weekly reservation and
  recirculation schedules; the model dump double-nested the request
  and leaked computed display fields (incl. unit-converted temperature)
  into device commands. Add NavienBaseModel.to_protocol_dict()
- Preserve command queue order on failed flush (deque with re-insert
  at front instead of tail)
- Discard queued commands older than max_queued_command_age (default
  300s) instead of replaying stale control commands after long outages
- Use truncated remainder (firmware semantics) instead of Python's
  floored modulo in the ASYMMETRIC Fahrenheit formula; fixes
  off-by-one conversions for sub-zero temperatures
- Correct freeze protection default limits to raw half-Celsius 12/20
  (43F/50F documented fixed range) instead of 43/65
- Emit error_detected when the error code changes between two
  non-zero codes
- Round TOU prices half-up via Decimal (round() banker's rounding
  under-encoded exact halves); encode bool prices instead of passing
  them through as pre-encoded ints
- Fix inverted enable-flag doc, wrong week-bitfield example (158->84),
  and int/float doctest values
BREAKING CHANGES (major version bump required):

- Remove deprecated NavienMqttClient.control property; use the
  delegated methods on the client directly
- Remove never-raised exception classes: TokenExpiredError,
  MqttSubscriptionError, DeviceNotFoundError, DeviceOfflineError,
  DeviceOperationError (catch the parent classes instead)
- Stop re-exporting internal plumbing from the top-level namespace:
  requires_capability, MqttDeviceInfoCache,
  MqttDeviceCapabilityChecker, log_performance, and the eight
  bit-encoding helpers (import from nwp500.encoding et al.)

Cleanup:

- Delete dead nwp500.cli.commands module (never imported, drifted
  from the real click commands)
- Delete unused converters.str_enum_validator and module-level
  temperature conversion wrappers; simplify div_10/mul_10
- Delete no-op NavienMqttClient._on_message_received placeholder and
  unused CLI width calculations
- Deduplicate the four Temperature classes via a _scale ClassVar on
  the base (behavior unchanged, ~200 lines removed); doctests pass
- Deduplicate field_factory metadata-merge boilerplate
- Use converters.device_bool_from_python in mqtt/control.py instead
  of inline 2/1 literals
- Resolve auth.py version from distribution metadata, removing the
  order-dependent 'from . import __version__' near-circular import
- Update docs and examples to import encoding helpers from
  nwp500.encoding; add public-API surface tests
@eman
eman changed the base branch from fix/protocol-correctness to main July 5, 2026 16:43
…-cleanup

# Conflicts:
#	CHANGELOG.rst
#	src/nwp500/encoding.py
#	src/nwp500/mqtt/client.py
#	src/nwp500/temperature.py
#	tests/test_protocol_correctness.py
@eman
eman requested a review from Copilot July 5, 2026 16:51
@eman
eman merged commit 195ba74 into main Jul 5, 2026
8 checks passed

Copilot AI 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.

Pull request overview

This PR performs an architecture cleanup/refactor of nwp500, trimming the top-level public API, removing dead code and never-raised exceptions, and deduplicating a few repeated conversion/field-construction implementations. It aligns the library with the documented “no backward compatibility” policy by removing a deprecated shim rather than carrying it forward.

Changes:

  • Remove deprecated/unused public API elements (e.g., NavienMqttClient.control, never-raised exception classes, and several internal helpers previously re-exported via nwp500.__all__).
  • Deduplicate core implementations (temperature conversions via per-class scaling; shared Field(..., json_schema_extra=...) construction; centralized device-bool encoding).
  • Update tests, docs, examples, and changelog to reflect the trimmed public surface and new import paths.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/test_public_api.py Adds coverage asserting __all__ names resolve and that removed/internal names are not exported.
tests/test_exceptions.py Removes tests for exception classes deleted from the library.
tests/test_auth.py Removes tests that referenced the deleted TokenExpiredError.
src/nwp500/temperature.py Deduplicates temperature conversions via a shared Temperature implementation with per-class _scale.
src/nwp500/mqtt/control.py Uses device_bool_from_python() to centralize protocol boolean encoding.
src/nwp500/mqtt/client.py Removes a no-op message callback placeholder and drops the deprecated .control property.
src/nwp500/field_factory.py Extracts repeated json_schema_extra merge logic into _metadata_field().
src/nwp500/exceptions.py Removes never-raised exception classes and updates the documented hierarchy.
src/nwp500/converters.py Removes dead str_enum_validator() and simplifies div_10() / mul_10() by removing redundant branches.
src/nwp500/cli/output_formatters.py Removes unused line-width calculations in CLI formatting.
src/nwp500/cli/commands.py Deletes an unused/never-imported CLI command registry module.
src/nwp500/auth.py Resolves __version__ via distribution metadata to avoid near-circular import with __init__.py.
src/nwp500/init.py Trims __all__ exports by removing re-exports of internal plumbing and deleted exception types.
examples/advanced/tou_openei.py Updates imports to pull encoding helpers from nwp500.encoding instead of the top-level package.
docs/reference/python_api/mqtt_client.rst Updates docs examples to import encoding helpers from nwp500.encoding.
docs/reference/python_api/exceptions.rst Removes docs for deleted exceptions and updates hierarchy presentation.
docs/reference/python_api/auth_client.rst Removes TokenExpiredError mentions from auth error-handling docs.
docs/how-to/schedule-operation.rst Updates how-to guide imports for build_reservation_entry to use nwp500.encoding.
docs/how-to/optimize-tou.rst Updates how-to guide imports for encoding helpers to use nwp500.encoding.
CHANGELOG.rst Documents breaking removals and the refactor/deduplication work under “Unreleased”.

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