Complete the type annotations and turn on the CI gates - #24
Merged
Conversation
The package shipped `py.typed` while being only partly annotated, so consumers
got `Any` from anything unannotated -- worse than no marker, because it looks
checked. Every function now has a return annotation (116 of 116), `ruff` and
`ty` are clean, and both run as blocking CI jobs alongside `ruff format --check`.
The `ANN` rules were held back when ruff was first configured, because turning
them on against a partly annotated tree would have buried every other finding.
They are enabled now, except in `tests/`, where annotating each test function
adds noise without adding safety.
Modernisation across the package: `Dict`/`List`/`Tuple`/`Optional`/`Union` become
PEP 585/604 builtins and `X | None`; `Generator[X, None, None]` becomes
`Iterator[X]`; `class Encrypter(object)` loses its base. The `*TypeHint` aliases
are now `TypeAlias` declarations with comments explaining what they hold, and
`StatusCallbackTypeHint` refers to the `StatusCallback` Protocol rather than a
bare `Callable`.
Several fixes fell out of making the checker agree:
* `IOWrapper` classified its source into an `object`, which untyped every use
of it and needed four `type: ignore`s. It now has `_as_path`, `_as_bytes` and
`_as_stream` accessors that *validate* rather than assume, so a wrong-kind
access raises a LenticryptError instead of an AttributeError further along.
* `encode()` returned `bytearray` while its caller was annotated `bytes`; it
now returns `bytes`, which also lets it be yielded straight into the block
stream.
* `decode()` accepted `BinaryIO`, which the internal `IO` streams do not
nominally satisfy; widened to `IO`.
* `DictionaryEncrypter.__init__` was a `*args, **kwargs` pass-through that
typed all its parameters as `object`. It declares the real signature.
* `ProgressBar.__init__` likewise took `*args, **kwargs` and forwarded them.
Also replaces the 160-character block-header comment with a readable diagram,
and gives `is_power2` a real docstring.
`ty` has no `--strict` flag, so CI uses `--error-on-warning`, which is the
equivalent gate.
No `type: ignore` anywhere. Five `noqa`s remain, each with a written reason: the
deliberately-seeded RNG, two interface parameters that a particular override does
not need, `FrozenDict`'s dict-compatible constructor, and the CLI's error log
that intentionally omits a traceback.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01367hFob9sd4xpDmVT4uoFy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #23.
The package shipped
py.typedwhile being only partly annotated, so consumers gotAnyfrom anything unannotated — worse than no marker, because it looks checked. Every function now has a return annotation (116 of 116),ruffandtyare clean, and both run as blocking CI jobs alongsideruff format --check.The
ANNrules were held back when ruff was first configured, because turning them on against a partly annotated tree would have buried every other finding. They are enabled now, except intests/, where annotating each test function adds noise without adding safety.Modernisation
Dict/List/Tuple/Optional/Unionbecome PEP 585/604 builtins andX | None;Generator[X, None, None]becomesIterator[X];class Encrypter(object)loses its base. The*TypeHintaliases are nowTypeAliasdeclarations with comments explaining what they hold, andStatusCallbackTypeHintrefers to theStatusCallbackProtocol rather than a bareCallable.Fixes that fell out of making the checker agree
IOWrapperclassified its source into anobject, which untyped every use of it and needed fourtype: ignores. It now has_as_path,_as_bytes, and_as_streamaccessors that validate rather than assume, so a wrong-kind access raises aLenticryptErrorinstead of anAttributeErrorfurther along.encode()returnedbytearraywhile its caller was annotatedbytes; it now returnsbytes, which also lets it be yielded straight into the block stream.decode()acceptedBinaryIO, which the internalIOstreams do not nominally satisfy; widened toIO.DictionaryEncrypter.__init__was a*args, **kwargspass-through that typed all its parameters asobject. It declares the real signature.ProgressBar.__init__likewise took*args, **kwargsand forwarded them.Also replaces the 160-character block-header comment with a readable diagram, and gives
is_power2a real docstring.CI
tyhas no--strictflag, so CI uses--error-on-warning, which is the equivalent gate.Suppressions
No
type: ignoreanywhere. Fivenoqas remain, each with a written reason: the deliberately-seeded RNG, two interface parameters a particular override does not need,FrozenDict's dict-compatible constructor, and the CLI's error log that intentionally omits a traceback.256 passed.
🤖 Generated with Claude Code
https://claude.ai/code/session_01367hFob9sd4xpDmVT4uoFy