talk-python-cli 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/.claude/settings.local.json +4 -1
  2. talk_python_cli-0.2.0/CLAUDE.md +150 -0
  3. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/PKG-INFO +34 -18
  4. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/README.md +33 -17
  5. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/change-log.md +15 -0
  6. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/pyproject.toml +1 -1
  7. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/src/talk_python_cli/__init__.py +1 -1
  8. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/src/talk_python_cli/app.py +2 -2
  9. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/src/talk_python_cli/client.py +2 -2
  10. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/src/talk_python_cli/formatting.py +7 -0
  11. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/tests/test_client.py +29 -0
  12. talk_python_cli-0.2.0/tests/test_formatting.py +38 -0
  13. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/uv.lock +1 -1
  14. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/.gitignore +0 -0
  15. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/LICENSE +0 -0
  16. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/plans/001-talk-python-cli.plan.md +0 -0
  17. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/pyrefly.toml +0 -0
  18. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/ruff.toml +0 -0
  19. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/src/talk_python_cli/__main__.py +0 -0
  20. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/src/talk_python_cli/courses.py +0 -0
  21. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/src/talk_python_cli/episodes.py +0 -0
  22. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/src/talk_python_cli/guests.py +0 -0
  23. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/tests/__init__.py +0 -0
  24. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/tests/conftest.py +0 -0
  25. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/tests/test_courses.py +0 -0
  26. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/tests/test_episodes.py +0 -0
  27. {talk_python_cli-0.1.2 → talk_python_cli-0.2.0}/tests/test_guests.py +0 -0
@@ -5,7 +5,10 @@
5
5
  "Bash(./venv/bin/python -m talk_python_cli.app status:*)",
6
6
  "Bash(./venv/bin/talkpython status:*)",
7
7
  "Bash(./venv/bin/pip install:*)",
8
- "Bash(./venv/bin/talkpython:*)"
8
+ "Bash(./venv/bin/talkpython:*)",
9
+ "Bash(gh issue view:*)",
10
+ "Bash(pyrefly check:*)",
11
+ "Bash(uv lock:*)"
9
12
  ]
10
13
  }
11
14
  }
@@ -0,0 +1,150 @@
1
+ # CLAUDE.md — Agent Instructions for talk-python-cli
2
+
3
+ ## Project Overview
4
+
5
+ CLI client for the Talk Python to Me podcast and Talk Python Training courses.
6
+ Wraps a remote MCP server (`https://talkpython.fm/api/mcp`) using JSON-RPC 2.0
7
+ over HTTP. The CLI is a **thin client** — all business logic lives on the server.
8
+ The CLI handles argument parsing, HTTP transport, and output formatting.
9
+
10
+ Published on PyPI as `talk-python-cli`. Entry point: `talkpython`.
11
+
12
+ ## Critical Rules
13
+
14
+ - **Use `uv pip install`, never `pip install`.**
15
+ - **Virtual environment is `./venv`, NOT `./.venv`.**
16
+ - **After every code edit, run: `ruff format && ruff check --fix`**
17
+ - **Use `pyrefly check` to validate type information after changes.**
18
+ - Do not add unnecessary abstractions, comments, or docstrings to unchanged code.
19
+ - **Update `change-log.md` after every major change** (new features, breaking changes, notable fixes). Follow the [Keep a Changelog](https://keepachangelog.com/) format already in use.
20
+
21
+ ## Build & Run
22
+
23
+ ```bash
24
+ # Activate venv
25
+ source venv/bin/activate
26
+
27
+ # Install in editable mode
28
+ uv pip install -e ".[dev]"
29
+
30
+ # Run CLI
31
+ talkpython --help
32
+ talkpython episodes search "fastapi"
33
+ talkpython status
34
+
35
+ # Run tests
36
+ pytest
37
+
38
+ # Lint & format (ALWAYS after edits)
39
+ ruff format && ruff check --fix
40
+
41
+ # Type check (ALWAYS after edits)
42
+ pyrefly check
43
+ ```
44
+
45
+ ## Project Structure
46
+
47
+ ```
48
+ src/talk_python_cli/
49
+ __init__.py # Version from importlib.metadata
50
+ __main__.py # python -m entry point
51
+ app.py # Root Cyclopts app, global options, meta-handler, status cmd
52
+ client.py # MCPClient: httpx-based JSON-RPC 2.0 client
53
+ formatting.py # Rich output: Markdown panels (text) or JSON
54
+ episodes.py # Episode commands (search, get, list, recent, transcript)
55
+ guests.py # Guest commands (search, get, list)
56
+ courses.py # Course commands (search, get, list)
57
+
58
+ tests/
59
+ conftest.py # Shared fixtures, JSON-RPC response builders
60
+ test_client.py # MCPClient tests
61
+ test_episodes.py # Episode command tests
62
+ test_guests.py # Guest command tests
63
+ test_courses.py # Course command tests
64
+ ```
65
+
66
+ ## Architecture & Key Patterns
67
+
68
+ ### CLI Framework: Cyclopts (not Click, not Typer)
69
+
70
+ - Root app in `app.py` with sub-apps for episodes, guests, courses.
71
+ - **Meta-app launcher** (`@app.meta.default`): intercepts all invocations to
72
+ process global options (`--format`, `--url`) before dispatching to subcommands.
73
+ - Parameters use `Annotated[type, cyclopts.Parameter(...)]` for docs/defaults.
74
+ - Cyclopts auto-converts snake_case commands to kebab-case (e.g. `transcript_vtt` → `transcript-vtt`).
75
+
76
+ ### Client Pattern
77
+
78
+ - `MCPClient` in `client.py` wraps httpx for JSON-RPC 2.0 over HTTP.
79
+ - Lazy initialization: `_ensure_initialized()` runs MCP handshake on first call.
80
+ - Session ID tracked via `Mcp-Session-Id` response header.
81
+ - `call_tool(tool_name, arguments)` is the only public API for MCP tool calls.
82
+ - Output format sent as URL query param: `?format=json` when JSON mode.
83
+ - No authentication required (public API).
84
+
85
+ ### Lazy Client Access (avoids circular imports)
86
+
87
+ Each command module retrieves the client via a local helper:
88
+ ```python
89
+ def _client():
90
+ from talk_python_cli.app import get_client
91
+ return get_client()
92
+ ```
93
+ This deferred import avoids circular dependency since `app.py` imports the command modules.
94
+
95
+ ### Output Formatting
96
+
97
+ - `display(content, format)` in `formatting.py` routes to markdown or JSON renderer.
98
+ - Text mode: Rich Markdown panel with "Talk Python" theme (cyan border, monokai code).
99
+ - JSON mode on TTY: pretty-printed with syntax highlighting.
100
+ - JSON mode piped: compact single-line JSON for scripting.
101
+
102
+ ### Adding a New Command
103
+
104
+ 1. Add function in the appropriate module (`episodes.py`, `guests.py`, `courses.py`).
105
+ 2. Decorate with `@sub_app.default` or just define as a regular function in the sub-app.
106
+ 3. Call `_client().call_tool('tool_name', {'arg': value})` to invoke the MCP tool.
107
+ 4. Pass result to `display(result, _client().output_format)`.
108
+ 5. Add tests in the corresponding test file using `pytest-httpx` mocks.
109
+
110
+ ### Adding a New Command Group
111
+
112
+ 1. Create `src/talk_python_cli/newgroup.py` with a `cyclopts.App(name='newgroup')`.
113
+ 2. Register in `app.py`: `app.command(newgroup.sub_app)`.
114
+ 3. Create `tests/test_newgroup.py`.
115
+
116
+ ## Testing
117
+
118
+ - Framework: **pytest** with **pytest-httpx** for HTTP mocking.
119
+ - `conftest.py` provides helpers: `jsonrpc_result()`, `tool_result()`, `add_init_responses()`.
120
+ - Every test must call `add_init_responses(httpx_mock)` before making MCP client calls.
121
+ - Tests verify JSON-RPC request structure, argument passing, and response handling.
122
+
123
+ ## Dependencies
124
+
125
+ | Package | Purpose |
126
+ |-------------|--------------------------------|
127
+ | cyclopts | CLI framework (commands, args) |
128
+ | httpx | HTTP client for MCP calls |
129
+ | rich | Terminal output formatting |
130
+ | pytest | Testing (dev) |
131
+ | pytest-httpx| HTTP mocking in tests (dev) |
132
+
133
+ Build system: **hatchling**. Package manager: **uv**.
134
+
135
+ ## Config Files
136
+
137
+ - `pyproject.toml` — Package metadata, dependencies, entry points, build config
138
+ - `ruff.toml` — Line length 120, single quotes, target Python 3.14
139
+ - `pyrefly.toml` — Type checker config, search path includes `src/`
140
+ - `uv.lock` — Locked dependencies (committed)
141
+
142
+ ## Style Conventions
143
+
144
+ - Line length: 120
145
+ - Quotes: single quotes
146
+ - Modern Python type syntax: `dict | None` not `Optional[dict]`
147
+ - `from __future__ import annotations` in all modules
148
+ - Private helpers prefixed with `_`
149
+ - Minimal docstrings: only on public functions/classes
150
+ - Python target: 3.12+ (currently targeting 3.14 in tooling)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: talk-python-cli
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: CLI for the Talk Python to Me podcast and courses
5
5
  Project-URL: Homepage, https://github.com/talkpython/talk-python-cli
6
6
  Project-URL: Source, https://github.com/talkpython/talk-python-cli
@@ -44,12 +44,12 @@ Unlock 500+ episodes of [Talk Python to Me](https://talkpython.fm), full transcr
44
44
  Requires Python 3.12+.
45
45
 
46
46
  ```bash
47
- # Try it instantly with uvx (no install needed)
48
- uvx --from talk-python-cli talkpython episodes recent
49
-
50
- # Or install it permanently with uv
47
+ # Install it permanently with uv
51
48
  uv tool install talk-python-cli
52
49
 
50
+ # Or try it instantly with uvx (no install needed)
51
+ uvx --from talk-python-cli talkpython episodes recent
52
+
53
53
  # Or with pip
54
54
  pip install talk-python-cli
55
55
  ```
@@ -58,6 +58,8 @@ This installs the `talkpython` command.
58
58
 
59
59
  ## Quick start
60
60
 
61
+ Copy this whole block and paste it into your terminal to see what you get.
62
+
61
63
  ```bash
62
64
  # Search for episodes about FastAPI
63
65
  talkpython episodes search "FastAPI"
@@ -109,41 +111,55 @@ talkpython courses list
109
111
 
110
112
  ## Output formats
111
113
 
112
- The CLI auto-detects the best output format:
114
+ The CLI supports three output formats via `--format`:
113
115
 
114
- - **Interactive terminal** — Rich-formatted Markdown with styled panels and color.
115
- - **Piped / redirected** Compact JSON, ready for processing.
116
-
117
- Override the default with `--format`:
116
+ - **`text`** (default) — Rich-formatted Markdown with styled panels and color for human reading.
117
+ - **`json`**Structured JSON, pretty-printed on a TTY or compact when piped.
118
+ - **`markdown`** — Raw Markdown output with no Rich formatting. Ideal for piping into AI agents, LLMs, and automation tools that consume Markdown natively.
118
119
 
119
120
  ```bash
120
121
  # Force JSON output in the terminal
121
122
  talkpython --format json episodes search "async"
122
123
 
124
+ # Raw Markdown for AI agents and LLM pipelines
125
+ talkpython --format markdown episodes get 535
126
+
123
127
  # Force rich text output even when piping
124
128
  talkpython --format text episodes recent | less -R
125
129
  ```
126
130
 
131
+ ## Agentic AI and LLM integration
132
+
133
+ Use `--format markdown` when feeding output to AI agents, LLMs, or RAG pipelines. This gives you clean, raw Markdown without terminal styling — exactly what language models expect:
134
+
135
+ ```bash
136
+ # Feed an episode summary to an LLM
137
+ talkpython --format markdown episodes get 535 | llm "Summarize this podcast episode"
138
+
139
+ # Grab a transcript for RAG ingestion
140
+ talkpython --format markdown episodes transcript 535 | your-rag-pipeline ingest
141
+
142
+ # Pipe course details into an AI agent
143
+ talkpython --format markdown courses get 57 | your-agent process
144
+ ```
145
+
127
146
  ## Piping JSON to other tools
128
147
 
129
- Because the CLI outputs JSON automatically when piped, it integrates naturally with tools like `jq`, `llm`, or your own scripts:
148
+ The `--format json` output integrates naturally with tools like `jq` or your own scripts:
130
149
 
131
150
  ```bash
132
151
  # Extract episode titles with jq
133
- talkpython episodes search "testing" | jq '.title'
152
+ talkpython --format json episodes search "testing" | jq '.title'
134
153
 
135
- # Feed episode data into an LLM
136
- talkpython episodes get 535 | llm "Summarize this podcast episode"
137
-
138
- # Grab a transcript for RAG ingestion
139
- talkpython episodes transcript 535 | your-rag-pipeline ingest
154
+ # Process structured data in a script
155
+ talkpython --format json episodes recent | python process_episodes.py
140
156
  ```
141
157
 
142
158
  ## Global options
143
159
 
144
160
  | Option | Description |
145
161
  |--------|-------------|
146
- | `--format text\|json` | Force output format (auto-detected by default) |
162
+ | `--format text\|json\|markdown` | Output format: `text` (rich), `json`, or `markdown` (raw) |
147
163
  | `--url <mcp-url>` | Override the MCP server URL (default: `https://talkpython.fm/api/mcp`) |
148
164
  | `--version`, `-V` | Show version |
149
165
 
@@ -17,12 +17,12 @@ Unlock 500+ episodes of [Talk Python to Me](https://talkpython.fm), full transcr
17
17
  Requires Python 3.12+.
18
18
 
19
19
  ```bash
20
- # Try it instantly with uvx (no install needed)
21
- uvx --from talk-python-cli talkpython episodes recent
22
-
23
- # Or install it permanently with uv
20
+ # Install it permanently with uv
24
21
  uv tool install talk-python-cli
25
22
 
23
+ # Or try it instantly with uvx (no install needed)
24
+ uvx --from talk-python-cli talkpython episodes recent
25
+
26
26
  # Or with pip
27
27
  pip install talk-python-cli
28
28
  ```
@@ -31,6 +31,8 @@ This installs the `talkpython` command.
31
31
 
32
32
  ## Quick start
33
33
 
34
+ Copy this whole block and paste it into your terminal to see what you get.
35
+
34
36
  ```bash
35
37
  # Search for episodes about FastAPI
36
38
  talkpython episodes search "FastAPI"
@@ -82,41 +84,55 @@ talkpython courses list
82
84
 
83
85
  ## Output formats
84
86
 
85
- The CLI auto-detects the best output format:
87
+ The CLI supports three output formats via `--format`:
86
88
 
87
- - **Interactive terminal** — Rich-formatted Markdown with styled panels and color.
88
- - **Piped / redirected** Compact JSON, ready for processing.
89
-
90
- Override the default with `--format`:
89
+ - **`text`** (default) — Rich-formatted Markdown with styled panels and color for human reading.
90
+ - **`json`**Structured JSON, pretty-printed on a TTY or compact when piped.
91
+ - **`markdown`** — Raw Markdown output with no Rich formatting. Ideal for piping into AI agents, LLMs, and automation tools that consume Markdown natively.
91
92
 
92
93
  ```bash
93
94
  # Force JSON output in the terminal
94
95
  talkpython --format json episodes search "async"
95
96
 
97
+ # Raw Markdown for AI agents and LLM pipelines
98
+ talkpython --format markdown episodes get 535
99
+
96
100
  # Force rich text output even when piping
97
101
  talkpython --format text episodes recent | less -R
98
102
  ```
99
103
 
104
+ ## Agentic AI and LLM integration
105
+
106
+ Use `--format markdown` when feeding output to AI agents, LLMs, or RAG pipelines. This gives you clean, raw Markdown without terminal styling — exactly what language models expect:
107
+
108
+ ```bash
109
+ # Feed an episode summary to an LLM
110
+ talkpython --format markdown episodes get 535 | llm "Summarize this podcast episode"
111
+
112
+ # Grab a transcript for RAG ingestion
113
+ talkpython --format markdown episodes transcript 535 | your-rag-pipeline ingest
114
+
115
+ # Pipe course details into an AI agent
116
+ talkpython --format markdown courses get 57 | your-agent process
117
+ ```
118
+
100
119
  ## Piping JSON to other tools
101
120
 
102
- Because the CLI outputs JSON automatically when piped, it integrates naturally with tools like `jq`, `llm`, or your own scripts:
121
+ The `--format json` output integrates naturally with tools like `jq` or your own scripts:
103
122
 
104
123
  ```bash
105
124
  # Extract episode titles with jq
106
- talkpython episodes search "testing" | jq '.title'
125
+ talkpython --format json episodes search "testing" | jq '.title'
107
126
 
108
- # Feed episode data into an LLM
109
- talkpython episodes get 535 | llm "Summarize this podcast episode"
110
-
111
- # Grab a transcript for RAG ingestion
112
- talkpython episodes transcript 535 | your-rag-pipeline ingest
127
+ # Process structured data in a script
128
+ talkpython --format json episodes recent | python process_episodes.py
113
129
  ```
114
130
 
115
131
  ## Global options
116
132
 
117
133
  | Option | Description |
118
134
  |--------|-------------|
119
- | `--format text\|json` | Force output format (auto-detected by default) |
135
+ | `--format text\|json\|markdown` | Output format: `text` (rich), `json`, or `markdown` (raw) |
120
136
  | `--url <mcp-url>` | Override the MCP server URL (default: `https://talkpython.fm/api/mcp`) |
121
137
  | `--version`, `-V` | Show version |
122
138
 
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.0] - 2026-02-07
9
+
10
+ ### Added
11
+ - `--format markdown` output mode for raw Markdown without Rich formatting, ideal for AI agents, LLMs, and RAG pipelines
12
+ - New "Agentic AI and LLM integration" section in README
13
+ - `display_markdown_raw()` in `formatting.py` for plain stdout output
14
+ - Tests for markdown format: query param propagation, raw output, and display routing
15
+
16
+ ### Changed
17
+ - `--format` flag now accepts `text`, `json`, or `markdown` (was `text` or `json`)
18
+ - MCP client sends `?format=markdown` query param to server when markdown format is selected
19
+ - README "Output formats" and "Piping JSON to other tools" sections updated for the new format
20
+
21
+ ---
22
+
8
23
  ## [0.1.2] - 2026-02-07
9
24
 
10
25
  ### Added
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "talk-python-cli"
3
- version = "0.1.2"
3
+ version = "0.2.0"
4
4
  description = "CLI for the Talk Python to Me podcast and courses"
5
5
  requires-python = ">=3.12"
6
6
  license = "MIT"
@@ -2,4 +2,4 @@
2
2
 
3
3
  from importlib.metadata import version
4
4
 
5
- __version__ = version("talk-python-cli")
5
+ __version__ = version('talk-python-cli')
@@ -82,10 +82,10 @@ def status() -> None:
82
82
  def launcher(
83
83
  *tokens: Annotated[str, cyclopts.Parameter(show=False, allow_leading_hyphen=True)],
84
84
  format: Annotated[
85
- Literal['text', 'json'],
85
+ Literal['text', 'json', 'markdown'],
86
86
  cyclopts.Parameter(
87
87
  name='--format',
88
- help="Output format: 'text' (rich Markdown) or 'json'.",
88
+ help="Output format: 'text' (rich Markdown), 'json', or 'markdown' (raw).",
89
89
  ),
90
90
  ] = 'text',
91
91
  url: Annotated[
@@ -46,8 +46,8 @@ class MCPClient:
46
46
  return self._msg_id
47
47
 
48
48
  def _url(self) -> str:
49
- if self.output_format == 'json':
50
- return f'{self.base_url}?format=json'
49
+ if self.output_format in ('json', 'markdown'):
50
+ return f'{self.base_url}?format={self.output_format}'
51
51
  return self.base_url
52
52
 
53
53
  def _post(self, payload: dict) -> httpx.Response:
@@ -39,10 +39,17 @@ def display(content: str, output_format: str) -> None:
39
39
  """Route content to the appropriate renderer."""
40
40
  if output_format == 'json':
41
41
  display_json(content)
42
+ elif output_format == 'markdown':
43
+ display_markdown_raw(content)
42
44
  else:
43
45
  display_markdown(content)
44
46
 
45
47
 
48
+ def display_markdown_raw(content: str) -> None:
49
+ """Print raw Markdown content to stdout without any Rich formatting."""
50
+ print(content)
51
+
52
+
46
53
  def display_markdown(content: str) -> None:
47
54
  """Render Markdown content with Rich, wrapped in a styled panel."""
48
55
  md = Markdown(content, code_theme='monokai')
@@ -197,6 +197,35 @@ class TestOutputFormat:
197
197
  assert 'format=json' in str(req.url)
198
198
  client.close()
199
199
 
200
+ def test_markdown_format_adds_query_param(self, httpx_mock: HTTPXMock) -> None:
201
+ md_url = f'{DEFAULT_URL}?format=markdown'
202
+ client = MCPClient(base_url=DEFAULT_URL, output_format='markdown')
203
+
204
+ httpx_mock.add_response(
205
+ method='POST',
206
+ url=md_url,
207
+ json=jsonrpc_result(
208
+ 1,
209
+ {
210
+ 'protocolVersion': '2025-03-26',
211
+ 'capabilities': {'tools': {}},
212
+ 'serverInfo': {'name': 'test', 'version': '0.1'},
213
+ },
214
+ ),
215
+ headers={'mcp-session-id': 's1'},
216
+ )
217
+ httpx_mock.add_response(method='POST', url=md_url, status_code=202, headers={'mcp-session-id': 's1'})
218
+ httpx_mock.add_response(
219
+ method='POST',
220
+ url=md_url,
221
+ json=tool_result(3, '# Episode 535\n\nSome markdown content'),
222
+ )
223
+
224
+ client.call_tool('get_episodes')
225
+ for req in httpx_mock.get_requests():
226
+ assert 'format=markdown' in str(req.url)
227
+ client.close()
228
+
200
229
 
201
230
  class TestContextManager:
202
231
  """Verify MCPClient works as a context manager."""
@@ -0,0 +1,38 @@
1
+ """Tests for output formatting."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from talk_python_cli.formatting import display, display_markdown_raw
6
+
7
+
8
+ class TestDisplayMarkdownRaw:
9
+ def test_prints_raw_content(self, capsys) -> None:
10
+ display_markdown_raw('# Hello\n\nSome **bold** text')
11
+
12
+ captured = capsys.readouterr()
13
+ assert captured.out == '# Hello\n\nSome **bold** text\n'
14
+
15
+ def test_no_rich_markup_in_output(self, capsys) -> None:
16
+ display_markdown_raw('## Heading\n- item 1\n- item 2')
17
+
18
+ captured = capsys.readouterr()
19
+ # Raw markdown should appear verbatim — no Rich panel borders or styling
20
+ assert '## Heading' in captured.out
21
+ assert '- item 1' in captured.out
22
+ assert '╭' not in captured.out # no Rich panel border
23
+
24
+
25
+ class TestDisplayRouting:
26
+ def test_markdown_format_routes_to_raw(self, capsys) -> None:
27
+ display('# Raw markdown', 'markdown')
28
+
29
+ captured = capsys.readouterr()
30
+ assert captured.out == '# Raw markdown\n'
31
+
32
+ def test_text_format_does_not_print_raw(self, capsys) -> None:
33
+ display('# Rendered', 'text')
34
+
35
+ captured = capsys.readouterr()
36
+ # Text mode uses Rich console, so raw '# Rendered' should NOT appear verbatim
37
+ # (Rich renders it as a heading without the # prefix)
38
+ assert '# Rendered' not in captured.out
@@ -235,7 +235,7 @@ wheels = [
235
235
 
236
236
  [[package]]
237
237
  name = "talk-python-cli"
238
- version = "0.1.1"
238
+ version = "0.2.0"
239
239
  source = { editable = "." }
240
240
  dependencies = [
241
241
  { name = "cyclopts" },
File without changes