Skip to content

Type-check the full tconnectsync package - #158

Merged
jwoglom merged 2 commits into
devfrom
claude/full-type-checking-iua99e
Jul 21, 2026
Merged

Type-check the full tconnectsync package#158
jwoglom merged 2 commits into
devfrom
claude/full-type-checking-iua99e

Conversation

@jwoglom

@jwoglom jwoglom commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Remove the single-file opt-in in setup.cfg ([mypy] files) so mypy checks the entire tconnectsync package, and fix everything that surfaced.

Config:

  • setup.cfg: mypy files now points at the whole tconnectsync package.

Event processors (were typed as BaseEvent, which lacks the per-event fields like seqNum and the event-specific attributes):

  • Type each *_to_nsentry / helper with the concrete event type(s) it handles (or a Union of them), matching the existing process_alarm.py pattern.
  • process_basal_suspension, process_basal_resume, process_cgm_start_join_stop: filter out None before appending to ns_entries, matching process_basal / process_cgm_alert. Previously a None from a non-matching event would have been appended and passed to upload_entry().
  • Add explicit return None fall-throughs where a helper annotated to return a value could implicitly return None.
  • process_cgm_reading: give each sensor's GlucosevaluestatusEnum its own local variable so the enum types don't clash.

process.py:

  • Add an EventProcessor Protocol and annotate event_classes with it, so the instantiated handlers are typed instead of object.
  • Rename the updater-loop variable so it no longer collides with the processor-loop variable's type.

Other:

  • api/tandemsource.py: narrow the JWKS key to RSAPublicKey before jwt.decode, and use arrow.get() (not time.time()) when forcing token expiry so the attribute type stays consistent.
  • api/common.py: split_days_range returns Arrow tuples, not str tuples.
  • parser/nightscout.py: sort profile segments by the typed startTime rather than an untyped dict value (same resulting order).
  • domain/tandemsource/pump_settings.py: PumpSettings inherits DataClassJsonMixin so from_dict is visible to the type checker.
  • domain/tandemsource/event_class.py: ignore the set/Enum hash clash.
  • nightscout.py: explicit return None when a ConnectionError is swallowed.

No runtime behavior change; full test suite (461 passed, 1 skipped) still green.

claude added 2 commits July 21, 2026 03:59
Remove the single-file opt-in in setup.cfg ([mypy] files) so mypy checks
the entire tconnectsync package, and fix everything that surfaced.

Config:
- setup.cfg: mypy `files` now points at the whole `tconnectsync` package.

Event processors (were typed as BaseEvent, which lacks the per-event fields
like seqNum and the event-specific attributes):
- Type each *_to_nsentry / helper with the concrete event type(s) it handles
  (or a Union of them), matching the existing process_alarm.py pattern.
- process_basal_suspension, process_basal_resume, process_cgm_start_join_stop:
  filter out None before appending to ns_entries, matching process_basal /
  process_cgm_alert. Previously a None from a non-matching event would have
  been appended and passed to upload_entry().
- Add explicit `return None` fall-throughs where a helper annotated to return
  a value could implicitly return None.
- process_cgm_reading: give each sensor's GlucosevaluestatusEnum its own local
  variable so the enum types don't clash.

process.py:
- Add an EventProcessor Protocol and annotate event_classes with it, so the
  instantiated handlers are typed instead of `object`.
- Rename the updater-loop variable so it no longer collides with the
  processor-loop variable's type.

Other:
- api/tandemsource.py: narrow the JWKS key to RSAPublicKey before jwt.decode,
  and use arrow.get() (not time.time()) when forcing token expiry so the
  attribute type stays consistent.
- api/common.py: split_days_range returns Arrow tuples, not str tuples.
- parser/nightscout.py: sort profile segments by the typed startTime rather
  than an untyped dict value (same resulting order).
- domain/tandemsource/pump_settings.py: PumpSettings inherits DataClassJsonMixin
  so from_dict is visible to the type checker.
- domain/tandemsource/event_class.py: ignore the set/Enum __hash__ clash.
- nightscout.py: explicit return None when a ConnectionError is swallowed.

No runtime behavior change; full test suite (461 passed, 1 skipped) still green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UaQXTakxAKEfeeys5cv3en
The Python 3.8 CI job installs an older mypy that behaves differently from
newer releases, surfacing two things the newer local mypy did not:

- requests (and other stub-less deps) raise `import-untyped`, which older
  mypy does not silence via ignore_missing_imports. Add
  `disable_error_code = import-untyped` so stub-less third-party libs are
  treated as untyped rather than failing the run.
- TandemSourceApi.__init__: older mypy infers secret.TCONNECT_REGION as
  Optional[str], so region.upper() tripped union-attr. Guard against an
  unset region (also avoids an AttributeError at runtime) which narrows it
  to str.

Verified with both mypy 1.19.1 and 2.3.0; tests still green (461 passed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UaQXTakxAKEfeeys5cv3en
@jwoglom
jwoglom merged commit 74576bb into dev Jul 21, 2026
4 checks passed
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