Skip to content

fix(deps): make toon_format an optional extra, and reject --output toon before the command runs - #331

Merged
tomaz-lc merged 2 commits into
masterfrom
fix-toon-optional-extra
Jul 30, 2026
Merged

fix(deps): make toon_format an optional extra, and reject --output toon before the command runs#331
tomaz-lc merged 2 commits into
masterfrom
fix-toon-optional-extra

Conversation

@tomaz-lc

@tomaz-lc tomaz-lc commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Credit

The diagnosis and the fix in this PR are @Nynir's work, contributed in #325 and reported in #324. Thank you. This was a genuinely hard bug to see from our side: uv reported success on every install, just for a release three months of features behind, and nothing in our CI or on PyPI looked wrong. It took someone noticing that uv tool upgrade limacharlie kept saying "Nothing to upgrade" and then chasing it all the way down to a transitive pre-release rule in the resolver.

Their commit is preserved here with its authorship intact, and everything this PR adds on top is a separate commit. The CHANGELOG credits them under a ### Thanks entry.

Details

This carries #325 by @Nynir, rebased onto current master, with follow-up fixes. Closes #324.

The CHANGELOG entries are filed under 5.6.1, dated July 30, 2026, on the assumption that this branch is tagged 5.6.1 on merge. If the merge slips past today, that date needs adjusting before tagging. There is no version constant to bump: the package version is derived from the git tag by setuptools-scm.

toon_format moves out of [project.dependencies] into an optional toon extra. The only toon_format release in our supported range is a pre-release (0.9.0b1), and uv before 0.12 refuses pre-releases reached through another package's metadata. Rather than reporting a conflict it backtracks to the newest release that does not need one, which is 5.3.0, silently: uv tool install limacharlie, uvx limacharlie, and uv pip install limacharlie have all been landing on a release that predates the dependency, with uv tool upgrade limacharlie reporting "Nothing to upgrade". Making the dependency optional lets those uv versions install the current release. Behavior change: a default install no longer supports --output toon; pip install 'limacharlie[toon]' restores it. The other five output formats are unaffected, and toon stays in the --output choice list so it still validates and tab-completes.

Two things are worth flagging for the merge decision. First, uv 0.12.0 fixed the underlying resolver behavior on 2026-07-28 (astral-sh/uv#19993) by switching the default pre-release mode to if-necessary, so current uv resolves transitive pre-releases the way pip does and installs the newest release either way. The extra is still what unblocks anyone pinned to uv 0.11 or older, but it is no longer fixing a problem that every uv user has, and it is worth deciding explicitly whether the behavior change is worth it on that basis. Second, the obvious lighter alternative does not work: widening the range so a stable release qualifies fails because toon_format 0.1.0 is a stub whose encode() raises NotImplementedError. Moving it to an extra is the only fix that does not require a new toon_format release upstream.

The second commit adds an up-front check. Refusing TOON only at render time means the command has already done its work: a search runs to completion, bills the organization, and buffers every page before discovering it has no encoder. That path was unreachable while toon_format was a hard dependency and becomes a normal one once it moves to an extra, so ensure_format_available() now guards the format as the CLI selects it. It shares a single message constant with the render-time guard in format_toon() so the two cannot drift apart, and format_toon() keeps its own guard because it is public SDK API that callers reach directly. The check exempts help and completion: the root group callback runs before a subcommand parses its own --help, so without that exemption limacharlie --output toon sensor --help would fail on a default install.

The rest of the second commit is correctness cleanup on the original: the CHANGELOG, README, CLI docs, pyproject.toml comment, and the error message all asserted the uv breakage in the present tense and are now scoped to uv older than 0.12; the dev extra self-references limacharlie[toon] instead of repeating the version range, leaving one place to bump when toon_format ships a stable release; test_cli_reports_the_extra_without_a_traceback asserted no traceback while main() prints one when LC_DEBUG is set, so it failed for anyone with that variable exported; and doc/getting-started.md still advertised a bare pip install limacharlie with no mention that TOON became opt-in.

Verification

Resolver behavior was checked against a wheel built from this branch, and the failure it fixes was reproduced against real PyPI first. Every uv from 0.5.31 through 0.11.33 installs limacharlie==5.3.0 when asked for limacharlie today; uv 0.12.0 installs 5.5.5 with toon-format 0.9.0b1. With this branch's wheel, uv 0.11.33 installs it with no flags and pulls no toon-format, <wheel>[toon] restores the encoder, and uv 0.12.0 and pip both resolve it normally.

Full suite passes both ways, and CI's install path is unchanged because [dev] still pulls the encoder:

pip install ".[dev]"     3859 passed,  5 skipped
without the toon extra   3845 passed, 19 skipped

Live CLI on a default install with no encoder: --output toon exits 1 with a one-line hint and no traceback, --help / sensor --help / completion bash / --output json all still work, and reinstalling the extra restores real TOON output. Both pip install ".[dev]" and pip install -e ".[dev]" were confirmed to still pull the encoder through the new self-reference.

Blast radius / isolation

Packaging metadata plus the CLI's output-format selection. The only runtime code touched is limacharlie/output.py (one new function, one message constant) and the root group callback in limacharlie/cli.py.

Not affected: every other --output format, all SDK APIs other than format_toon(), authentication, transport, and every command's own logic. No command module changes. Existing installs do not lose TOON on upgrade, because pip install -U limacharlie does not uninstall a toon_format that is already present; only fresh installs are affected. CI is unaffected on both GitHub Actions and Cloud Build, which install .[dev]; the Cloud Build wheel-smoke steps only run limacharlie --version.

Performance characteristics

No measurable change. ensure_format_available() is one string comparison and one identity check against a module global, run once per invocation inside the callback that already imports limacharlie.output. The help exemption scans sys.argv, which is a handful of elements. No new imports on any startup path, so the lazy-import work that keeps --help and --version fast is preserved. A default install now resolves one fewer package.

Notable contracts / APIs

  • limacharlie.output.ensure_format_available(fmt) is new and public. It raises ImportError for a format whose encoder ships in an extra and is a no-op otherwise, including for None.
  • format_toon() keeps raising ImportError with the same message when the encoder is missing. The message text changed (it now names the extra and the uv form); nothing should be matching on it, but it is a user-visible string.
  • Installation contract changes: limacharlie no longer requires toon_format, and a new toon extra provides it. This is the backward-incompatible part, and it is why the CHANGELOG entry is marked as a behavior change.
  • No wire format, API, or data schema changes.

Rollback

Revert the pyproject.toml hunk to put toon_format back in [project.dependencies]; the up-front check degrades to a no-op on its own, since the encoder is then always importable. Reverting the whole branch is also safe, since nothing here is persisted or versioned outside package metadata.

Related PRs

  • python-limacharlie#325 - the original contribution this rebases and builds on. Supersede or close it if this lands.
  • python-limacharlie#324 - the issue reporting the silent uv fallback to 5.3.0.
  • lc-ai#112 - works around the same resolution failure in the plugin CLI auto-installer with --prerelease=allow and a version floor. That workaround can be dropped for future releases once this lands, along with its noted trade-off that --prerelease=allow could also admit a pre-release of limacharlie itself.
  • astral-sh/uv#19993 - the upstream uv change that fixes the root cause in 0.12.0.

🤖 Generated with Claude Code

…nt releases

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@tomaz-lc
tomaz-lc force-pushed the fix-toon-optional-extra branch from 65c4525 to 78e36db Compare July 30, 2026 11:26
@tomaz-lc
tomaz-lc marked this pull request as ready for review July 30, 2026 11:33
…o <0.12

Follow-up to making toon_format an optional extra. Filed under 5.6.1, which is
the tag these entries ship in.

Refusing TOON only at render time means the command has already done its
work: a search runs to completion, bills the organization, and buffers every
page before discovering it has no encoder. That was unreachable while
toon_format was a hard dependency and became a normal path once it moved to
an extra. ensure_format_available() now guards the format as the CLI selects
it, sharing one message with the render-time guard in format_toon() so the two
cannot drift. The root group callback runs before a subcommand parses its own
--help, so the check exempts help and completion; without that exemption
`--output toon <command> --help` would fail on a default install.

uv 0.12.0 changed its default pre-release mode to resolve transitive
pre-releases the way pip does, which fixes the resolution failure that
motivated the extra. The extra still matters for uv 0.11 and older, but every
present-tense claim that uv "cannot install" us is now wrong for current uv,
so the CHANGELOG, README, CLI docs, pyproject comment, and the error message
itself are scoped to uv older than 0.12.

Also:

- The dev extra self-references limacharlie[toon] instead of repeating the
  version range, leaving one place to bump when toon_format ships a stable
  release. Verified that both `pip install .[dev]` and `pip install -e .[dev]`
  still pull the encoder.
- test_cli_reports_the_extra_without_a_traceback asserted no traceback while
  main() prints one when LC_DEBUG is set, so it failed for anyone with that
  exported. It now clears the variable.
- getting-started.md said `pip install limacharlie` with no mention that TOON
  became opt-in, and the README ran the pip and uv forms together in one block
  as though both were needed.
- The CHANGELOG credits @Nynir for finding and fixing the uv fallback, and
  references the originating issue and PRs.

Verified against a wheel built from this branch: uv 0.11.33 installs it with
no flags and pulls no toon-format, uv 0.12.0 and pip both resolve it, and the
wheel plus [toon] restores TOON output. Full suite passes both with the extra
(3859 passed, 5 skipped) and without it (3845 passed, 19 skipped).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tomaz-lc
tomaz-lc force-pushed the fix-toon-optional-extra branch from 78e36db to 0a97613 Compare July 30, 2026 11:37
@tomaz-lc
tomaz-lc enabled auto-merge (squash) July 30, 2026 11:38
@tomaz-lc
tomaz-lc requested a review from maximelb July 30, 2026 12:27
@tomaz-lc
tomaz-lc merged commit ea6730d into master Jul 30, 2026
6 checks passed
@tomaz-lc
tomaz-lc deleted the fix-toon-optional-extra branch July 30, 2026 14:11
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.

uv installs silently resolve to 5.3.0 because newer releases depend on pre-release-only toon_format

3 participants