Skip to content

test(core): stop output-format global leaking across tests - #93

Merged
GregHolmes merged 3 commits into
mainfrom
fix/output-format-test-isolation
Aug 17, 2026
Merged

test(core): stop output-format global leaking across tests#93
GregHolmes merged 3 commits into
mainfrom
fix/output-format-test-isolation

Conversation

@GregHolmes

@GregHolmes GregHolmes commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Problem

BaseCommand.output_result reads the output format from the process-global deepctl_core.output._output_config (via get_output_format()), not from config.get(). But five TestBaseCommand.test_output_result_* JSON tests only stubbed config.get.return_value = "json" — a value the code never reads.

As a result those tests depended on an earlier CLI-invoking test having left the global on "json" (the CLI entrypoint src/deepctl/main.py calls setup_output(), which mutates the global and nothing resets it). They pass in the full suite by collection-order luck and fail in isolation:

# on main
$ pytest packages/deepctl-core/tests/unit/test_base.py
5 failed, 83 passed

In isolation the format is its default "default", so output_result returns early and _output_json / print_json is never called → the assertions fail.

Fix (both halves)

  1. Tests set what the code reads. The 5 JSON tests now @patch("deepctl_core.output._output_config", {...}) — the same pattern the yaml/table/csv tests already use — instead of the no-op config.get stub. All 11 format patch sites now spread a shared _OUTPUT_CONFIG_DEFAULTS constant ({**_OUTPUT_CONFIG_DEFAULTS, "format": "json"}) that mirrors the real global's full key set, so the stand-in can't drift from _output_config (previously the dicts omitted agentic).
  2. Stop the leak. New autouse fixture in packages/deepctl-core/tests/conftest.py restores the pristine _output_config around every core test, so a format set by one test can no longer bleed into the next.

Half 1 makes the tests correct on their own; half 2 keeps the latent ordering bug from silently returning.

Verification

# in isolation (was 5 failed)
$ pytest packages/deepctl-core/tests/unit/test_base.py   → 88 passed
# whole core unit dir (was 5 failed)
$ pytest packages/deepctl-core/tests/unit                → 354 passed
# full suite
$ pytest                                                 → 976 passed

ruff / format clean (only test files touched). No src/ changes.

Note on the diff

Includes ~90 lines of ruff format reflow in TestConfirmPromptGating / TestIsGuided (the with patch(A), patch(B): blocks became parenthesized with ( … ): form, plus one line-wrap). All behavior-neutral formatter output, no logic change — called out here so it doesn't read as unexplained scope.

Scope

Pre-existing core test hygiene — independent of #92. Reset fixture is intentionally core-scoped to limit blast radius; a root-level version (covering cross-package leakage) can follow if wanted.

🤖 Generated with Claude Code

output_result reads the format from the process-global
deepctl_core.output._output_config (via get_output_format), not from
config.get(). But the five TestBaseCommand.test_output_result_* JSON tests
only stubbed config.get.return_value = "json" — a no-op the code never
reads — so they depended on an earlier CLI-invoking test having left the
global on "json". They passed in the full suite by collection-order luck and
failed in isolation (default format "default" → output_result returns early →
_output_json / print_json never called).

Fix both halves:
- Patch deepctl_core.output._output_config in each JSON test (matching the
  yaml/table/csv tests) so they set the format the code actually reads.
- Add an autouse fixture in packages/deepctl-core/tests/conftest.py that
  restores the pristine _output_config around every core test, so a format
  set by one test can no longer leak into the next.

test_base.py in isolation: 5 failed -> 88 passed. Full core suite: 354 passed.
…ests

The 11 format-test patch dicts stood in for the process-global
deepctl_core.output._output_config but carried only 4 of its 5 keys
(agentic was missing). Safe on today's path — output_result ->
get_output_format reads only ["format"] and _output_json prints directly —
but other output.py helpers read _output_config["agentic"], so a future
refactor routing output through one of them would KeyError every 4-key-dict
test at once.

Add a shared _OUTPUT_CONFIG_DEFAULTS constant mirroring the real global's
full key set and spread it at each site ({**_OUTPUT_CONFIG_DEFAULTS,
"format": "json"}), removing both the drift risk and the duplication.

No behavior change: test_base.py 88 passed in isolation, full suite 976.

@dg-coreylweathers dg-coreylweathers 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.

Approved — verified end-to-end, both rounds.

Re-ran the whole story locally rather than trusting the PR body:

  • Reproduced the bug on main: test_base.py in isolation → 5 failed / 83 passed, exactly the five output_result JSON tests, failing on the "default" early-return. Confirmed in source that output_result reads get_output_format()_output_config["format"], so the old config.get stubs were no-ops as described.
  • On this branch: isolation 88 passed, core unit dir 354 passed, ruff format --check clean, no new ruff check findings vs main.
  • The autouse reset fixture is correct: pristine snapshot taken at collection time before any test runs, in-place clear()/update() composes cleanly with the tests' @patch swaps, no overlap with the root conftest.
  • f1469c1's _OUTPUT_CONFIG_DEFAULTS spread resolves the missing-agentic-key shape drift across all 12 format tests, and the PR body now accounts for the ruff-format reflow.

Two non-gating notes for the record:

  1. Full suite here is 975 passed + 1 pre-existing unrelated failure: test_file_info_modified_timestamp (deepctl-shared-utils) uses local-time fromtimestamp() and fails on any machine west of UTC — that's the 975-vs-976 gap between our machines. Deserves its own issue (fromtimestamp(ts, tz=timezone.utc)).
  2. Core-scoped reset fixture accepted as-is; root-level version can follow if cross-package leakage ever shows up.

@GregHolmes
GregHolmes merged commit 77ac580 into main Aug 17, 2026
39 checks passed
@GregHolmes
GregHolmes deleted the fix/output-format-test-isolation branch August 17, 2026 11:23
@GregHolmes GregHolmes mentioned this pull request Aug 17, 2026
GregHolmes pushed a commit that referenced this pull request Aug 17, 2026
🤖 I have created a release *beep* *boop*
---

## 📦 deepctl 0.2.27 — what's in this release

Ships the Deepgram Python SDK **7.7.0** upgrade, makes **Flux** the
default text-to-speech model, expands redaction/formatting controls for
speech-to-text, and hardens the MCP proxy against host disconnects. All
feature areas were exercised end-to-end against the live API before
cutting this release.

### ✨ Features

- **`dg speak` now defaults to Flux TTS (`flux-alexis-en`).**
Text-to-speech streams via Flux (Speak v2 WebSocket) by default instead
of Aura 2, with new Flux-only controls: `--speed` (0.85–1.15) and
`--expressivity` (−2…2, beta). Aura voices remain available via `-m
aura-2-*` (REST batch). (#89, #92)
- **`dg listen` redaction & numerals on files *and* live streams.** New
`--redact` and `--numerals`. Flux STT (v2) accepts `--redact numbers` /
`aggressive_numbers`; v1 models also accept `pci`, `ssn`, etc. and are
repeatable. (#92)
- **Flux STT streaming guardrail.** Flux STT is streaming-only — a file
or URL source now fails fast with guidance to use `--mic`, stdin (`-`),
or a v1 model (e.g. `nova-3`) for pre-recorded audio, instead of
erroring opaquely. (#92)
- **Deepgram SDK bumped to 7.7.0.** (#92)

### 🐛 Bug Fixes

- **MCP pipe-safety.** `dg mcp` now swallows broken/closed-pipe errors
during startup notifications and on the error path, so a host disconnect
exits cleanly with no Python traceback. (#88)

### 🔧 Internal

- Test isolation: the output-format global no longer leaks across the
test suite. (#93)

### ⚠️ Upgrade note

`dg speak` output now comes from Flux (`flux-alexis-en`) by default
rather than Aura 2 — expect a different default voice and raw `linear16`
(auto-wrapped to WAV) instead of Aura's MP3 default. To keep the
previous behavior, pass `-m aura-2-asteria-en` (add `--encoding mp3` for
MP3 output).

---

<sub>The machine-generated release manifest below is required by Release
Please and is left unchanged.</sub>


<details><summary>0.2.27</summary>

## [0.2.27](v0.2.26...v0.2.27)
(2026-08-17)


### Features

* SDK 7.7.0 — Flux TTS controls, Flux STT fix, listen redact/numerals
([#92](#92))
([50d96cf](50d96cf))
* **speak:** default to Flux TTS (flux-alexis-en) instead of Aura 2
([#89](#89))
([5a0b698](5a0b698))


### Bug Fixes

* **mcp:** swallow broken/closed-pipe on dg mcp startup notifications
and error path ([#88](#88))
([b24396e](b24396e))
</details>

<details><summary>deepctl-core: 0.2.15</summary>

##
[0.2.15](deepctl-core-v0.2.14...deepctl-core-v0.2.15)
(2026-08-17)


### Features

* SDK 7.7.0 — Flux TTS controls, Flux STT fix, listen redact/numerals
([#92](#92))
([50d96cf](50d96cf))
</details>

<details><summary>deepctl-telemetry: 0.0.6</summary>

##
[0.0.6](deepctl-telemetry-v0.0.5...deepctl-telemetry-v0.0.6)
(2026-08-17)


### Bug Fixes

* **mcp:** swallow broken/closed-pipe on dg mcp startup notifications
and error path ([#88](#88))
([b24396e](b24396e))
</details>

<details><summary>deepctl-cmd-login: 0.1.17</summary>

##
[0.1.17](deepctl-cmd-login-v0.1.16...deepctl-cmd-login-v0.1.17)
(2026-08-17)


### Features

* SDK 7.7.0 — Flux TTS controls, Flux STT fix, listen redact/numerals
([#92](#92))
([50d96cf](50d96cf))
</details>

<details><summary>deepctl-cmd-projects: 0.1.13</summary>

##
[0.1.13](deepctl-cmd-projects-v0.1.12...deepctl-cmd-projects-v0.1.13)
(2026-08-17)


### Features

* SDK 7.7.0 — Flux TTS controls, Flux STT fix, listen redact/numerals
([#92](#92))
([50d96cf](50d96cf))
</details>

<details><summary>deepctl-cmd-usage: 0.1.13</summary>

##
[0.1.13](deepctl-cmd-usage-v0.1.12...deepctl-cmd-usage-v0.1.13)
(2026-08-17)


### Features

* SDK 7.7.0 — Flux TTS controls, Flux STT fix, listen redact/numerals
([#92](#92))
([50d96cf](50d96cf))
</details>

<details><summary>deepctl-cmd-update: 0.2.6</summary>

##
[0.2.6](deepctl-cmd-update-v0.2.5...deepctl-cmd-update-v0.2.6)
(2026-08-17)


### Bug Fixes

* **mcp:** swallow broken/closed-pipe on dg mcp startup notifications
and error path ([#88](#88))
([b24396e](b24396e))
</details>

<details><summary>deepctl-cmd-skills: 0.0.7</summary>

##
[0.0.7](deepctl-cmd-skills-v0.0.6...deepctl-cmd-skills-v0.0.7)
(2026-08-17)


### Bug Fixes

* **mcp:** swallow broken/closed-pipe on dg mcp startup notifications
and error path ([#88](#88))
([b24396e](b24396e))
</details>

<details><summary>deepctl-cmd-speak: 0.0.4</summary>

##
[0.0.4](deepctl-cmd-speak-v0.0.3...deepctl-cmd-speak-v0.0.4)
(2026-08-17)


### Features

* SDK 7.7.0 — Flux TTS controls, Flux STT fix, listen redact/numerals
([#92](#92))
([50d96cf](50d96cf))
* **speak:** default to Flux TTS (flux-alexis-en) instead of Aura 2
([#89](#89))
([5a0b698](5a0b698))
</details>

<details><summary>deepctl-cmd-listen: 0.0.14</summary>

##
[0.0.14](deepctl-cmd-listen-v0.0.13...deepctl-cmd-listen-v0.0.14)
(2026-08-17)


### Features

* SDK 7.7.0 — Flux TTS controls, Flux STT fix, listen redact/numerals
([#92](#92))
([50d96cf](50d96cf))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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