Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 10 additions & 23 deletions src/codex32/_cli_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,36 +410,24 @@ def _correction_plan(
byte_length: int | Literal["?"] | None,
count: int,
target: int | None,
) -> tuple[tuple[int, ...], frozenset[int], frozenset[int], bool]:
) -> tuple[int, ...]:
if target is not None:
return (
(target,),
frozenset((target,)),
frozenset(),
True,
)
return (target,)
normalized_hrp = hrp.value if isinstance(hrp, Profile) else hrp.lower()
if normalized_hrp == Profile.CL.value:
return (74,), frozenset((74,)), frozenset(), True
return (74,)
if isinstance(byte_length, int):
return (
((length := _text_length(byte_length)),),
frozenset((length,)),
frozenset(),
True,
)
return (_text_length(byte_length),)
if byte_length == "?":
return TEXT_LENGTHS, frozenset(TEXT_LENGTHS), frozenset(), True
return TEXT_LENGTHS
if normalized_hrp == Profile.MS.value:
nearest = min(_PRIMARY_MS, key=lambda length: abs(count - length))
targets = (nearest, *(length for length in TEXT_LENGTHS if length != nearest))
return targets, frozenset(targets), frozenset(), True
return targets
rules = _optional_profile_rules(normalized_hrp)
if rules is not None and hasattr(rules, "text_length"):
targets = (rules.text_length,)
return targets, frozenset(targets), frozenset(), True
targets = tuple(sorted({count + delta for delta in (*range(-4, 5), -8, 8)}))
return targets, frozenset(targets), frozenset(), True
return (rules.text_length,)
return tuple(sorted({count + delta for delta in (*range(-4, 5), -8, 8)}))


def _correction_candidates(
Expand All @@ -459,16 +447,15 @@ def _correction_candidates(
optional_only: bool = False,
) -> tuple[tuple[CorrectionCandidate, ...], bool, float]:
count = len(value.replace(" ", ""))
targets, primary, reduced, _timed = _correction_plan(profile, byte_length, count, target)
targets = _correction_plan(profile, byte_length, count, target)
deadline = monotonic() + 10 if deadline is None else deadline
contexts = tuple(CorrectionContext(profile, length, immutable, excluded) for length in targets)
from codex32.indel import _search_many

candidates, complete = _search_many(
contexts,
value,
primary=primary,
reduced=reduced,
primary=frozenset(targets),
deadline=deadline,
competitors=True,
allowed=allowed,
Expand Down
2 changes: 1 addition & 1 deletion src/codex32/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def _secret(artifacts: list[Artifact]) -> Secret:
if not all(isinstance(artifact, Share) for artifact in artifacts):
raise _UsageError("Recovery accepts ordinary shares or one complete secret.")
try:
return recover_secret([artifact for artifact in artifacts if isinstance(artifact, Share)])
return recover_secret(cast(list[Share], artifacts))
except CodexError as error:
raise _UsageError(str(error)) from error

Expand Down
1 change: 0 additions & 1 deletion src/codex32/indel.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,6 @@ def _search_many(
damaged_text: str,
*,
primary: frozenset[int],
reduced: frozenset[int] = frozenset(),
deadline: float | None = None,
max_character_depth: int = 4,
competitors: bool = False,
Expand Down
3 changes: 1 addition & 2 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1835,14 +1835,13 @@ def test_correction_options_control_lengths_deadline_and_search_envelope(
assert observed == damaged
assert tuple(context.expected_length for context in contexts) == lengths
assert (search.call_args.kwargs["deadline"] is not None) is bounded
assert search.call_args.kwargs["reduced"] == frozenset()


def test_automatic_target_selection_covers_midpoints_and_supported_lengths() -> None:
from codex32._cli_input import _correction_plan

for observed in range(40, 136):
targets = _correction_plan(Profile.MS, None, observed, None)[0]
targets = _correction_plan(Profile.MS, None, observed, None)
expected = 48 if observed <= 61 else 74 if observed <= 100 else 127

assert targets[0] == expected
Expand Down
3 changes: 1 addition & 2 deletions tests/test_correction_indel.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def test_automatic_secondary_search_recovers_two_group_indels(
damaged = _group_damage(source, inserted, omitted)
contexts = tuple(
CorrectionContext(Profile.MS, target, "ms1")
for target in _correction_plan(Profile.MS, None, len(damaged), None)[0]
for target in _correction_plan(Profile.MS, None, len(damaged), None)
)

candidates, complete = _search_many(
Expand Down Expand Up @@ -507,7 +507,6 @@ def search(state, _frontier, results, _deadline): # type: ignore[no-untyped-def
contexts,
damaged,
primary=frozenset((48, 74, 127)),
reduced=frozenset((54, 61, 67)),
)
return calls

Expand Down
1 change: 0 additions & 1 deletion tools/correction_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ def benchmark_cross_length(observed_length: int, *, unknown: bool = False) -> di
contexts,
damaged,
primary=frozenset((48, 74, 127)),
reduced=frozenset() if unknown else frozenset((54, 61, 67)),
)
seconds = perf_counter() - started
if not complete or candidates:
Expand Down
Loading