Commit 3539973
authored
test: add pytest suite + fix the CI gates that were failing on main (#4)
* chore: format sweep + Python 3.8-3.11 f-string compat fix
Two separate hygiene fixes bundled because they both block the new
test suite from running green in CI:
1. **black + isort sweep across 17 source files.** The repo was
never run through `black` after the formatter became a CI gate
in `.github/workflows/test.yml`. Pure whitespace / import-order
changes; no logic touched.
2. **`tools/data_tools._generate_create_table_sql` syntax fix.**
Line 188 used `{',\n '.join(column_definitions)}` inside an
f-string. Backslashes in f-string expression parts are a
SyntaxError on Python 3.8 - 3.11 (only legal from 3.12 onward),
and `pyproject.toml` declares `requires-python = ">=3.8"` plus
the CI matrix runs 3.8-3.12. The module is unimportable on every
pre-3.12 Python; CI never caught it because nothing imported the
module. Fixed by binding the separator to a name (`sep = ",\n "`)
so the f-string expression is backslash-free. Behaviour
identical.
After this commit, `black --check`, `isort --check-only`, and
`flake8 . --select=E9,F63,F7,F82` all pass cleanly. The next commit
adds the test suite that surfaced both gaps.
* test: add pytest suite for config, data_tools, and CLI
Bootstraps clickr's first real test suite. The CI workflow at
`.github/workflows/test.yml` already invokes `pytest tests/`, but
the directory did not exist - so every "passing" green check on
main was a no-op. This commit makes the green meaningful: 52 tests
across three files, all running in <1s on Python 3.9.
`tests/conftest.py` - shared fixtures. The autouse `_isolate_env`
fixture strips `CLICKHOUSE_*` and `OPENROUTER_*` from `os.environ`
and points `$HOME` at a `tmp_path` so the loader's probe for
`~/.config/proto/proto-config.json` never finds the developer's
real config. Without this, tests pass locally but fail in CI (or
vice versa) depending on whose machine they run on.
`tests/test_settings.py` (28 tests) - covers `ClickHouseConfig`
defaults and validation, plus every input source `load_config`
merges (file, env vars, CLI args, the legacy `clickhouse_*` key
mapping from the onboarding flow), and the precedence between
them (CLI > env > file). Also covers the silent
`provider != "local"` coercion (so an old config doesn't break
boot) and the `create_sample_config` round-trip.
`tests/test_data_tools.py` (15 tests) - exercises every dtype
branch of `_generate_create_table_sql` (UInt64 / Int64 /
Float64 / Bool / DateTime / String fallback for mixed-object
columns) and the structural invariants (IF NOT EXISTS, MergeTree
engine, ORDER BY tuple(), backtick quoting for reserved-word
columns, multi-column composition, empty-DataFrame degenerate
case). The function does not touch `self.client`, so the fixture
passes `None`.
`tests/test_cli.py` (9 tests) - Typer `CliRunner` smoke tests:
top-level `--help`, that documented subcommands appear in help
(catches silent renames), every subcommand has a working `--help`,
`version` returns 0, and unknown commands return non-zero. Does
not exercise the LLM provider or ClickHouse client - those need
real services.
Methodology choices worth flagging:
- No mocks for ClickHouse or the LLM. Mocked tests for an HTTP
client tend to lock in the mock's view of reality and rot when
the real service moves. The pure-data-validation tests cover
what is actually testable without a server.
- Tests use the public API (`load_config`, `ClickHouseConfig`,
`_generate_create_table_sql`) rather than asserting against
internal helpers. A refactor of internals should not need to
touch this file.
- Each test class groups behaviour, not function-under-test, so a
reader can scan the test names for the contract instead of
reading the code.
* fix(packaging): use legacy license-table syntax so install works on Python 3.8
`license = "MIT"` is the new PEP 639 SPDX-string form, only understood
by setuptools >= 77 (released Feb 2025). The CI matrix includes
Python 3.8, whose bundled setuptools predates that — so
`pip install -e ".[dev]"` fails on the ubuntu-latest 3.8 job with:
ValueError: invalid pyproject.toml config: `project.license`.
configuration error: `project.license` must be valid exactly by
one definition (2 matches found):
- keys: 'file': {type: string}
- keys: 'text': {type: string}
`license = { text = "MIT" }` is the pre-PEP-639 table form, understood
by every setuptools version that supports pyproject.toml, so it works
across the full 3.8 - 3.12 matrix without forcing a setuptools-upgrade
step into the CI install. Same metadata reaches PyPI either way
(`License: MIT` classifier).
* chore: drop Python 3.8 (EOL Oct 2024) from CI matrix and metadata
The latest `clickhouse-connect` (a transitive dep) uses PEP 585
generic-subscript syntax (`list[IPv6Address]`) without bumping its
own `requires-python` past 3.8 — so on Python 3.8 pip resolves to a
version of clickhouse-connect that fails to import with
`TypeError: 'type' object is not subscriptable`. The Python 3.8
test job was failing before this PR for that reason; the matrix
ran for years on luck (no test ever imported clickhouse-connect).
Python 3.8 reached end-of-life on 2024-10-07. Dropping it across:
- `.github/workflows/test.yml` matrix: 3.8 → 3.9 floor
- `pyproject.toml`: `requires-python`, classifier, mypy
`python_version`, black `target-version`
- `setup.py`: `python_requires`, classifier
Cuts the matrix from 15 jobs to 12 and matches the practical reality
of the dep tree. Anyone genuinely on 3.8 can still install older
clickr versions from PyPI; new 3.9+ becomes the supported floor.
* fix(packaging): read README.md with explicit utf-8 encoding for Windows
`Path.read_text()` without `encoding=` falls back to
`locale.getpreferredencoding()` — UTF-8 on macOS/Linux, but cp1252
on Windows. README.md contains the ERP•AI brand mark (`•`) and
em-dashes, which fail to decode as cp1252 and crash the install:
UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d in
position 480: character maps to <undefined>
Pinning `encoding="utf-8"` makes the install reliable across the
matrix. The same bug pattern bites every Python project that does
`open("README.md").read()` without encoding; would not surface
until someone runs CI (or installs) on Windows.
* test(conftest): point USERPROFILE + HOMEDRIVE/HOMEPATH at tmp_path for Windows
`Path.home()` reads HOME on POSIX but USERPROFILE on Windows (with
HOMEDRIVE + HOMEPATH as a fallback). The autouse fixture only set
HOME, so on Windows runners the loader's `~/.config/proto/...`
probe escaped the sandbox and resolved to the real runner's home —
where there is no proto-config.json — and
test_default_config_in_xdg_home_is_picked_up failed with
`assert 'localhost' == 'xdg.example.com'`.
Setting all three env vars (HOME, USERPROFILE, HOMEDRIVE+HOMEPATH)
makes the fixture portable across the full ubuntu/macos/windows
matrix without forking the test or skipping on Windows.1 parent 73e1980 commit 3539973
25 files changed
Lines changed: 2149 additions & 1186 deletions
File tree
- .github/workflows
- agent
- config
- providers
- tests
- tools
- ui
- utils
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | | - | |
13 | | - | |
| 13 | + | |
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | | - | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
26 | 27 | | |
27 | 28 | | |
28 | 29 | | |
29 | | - | |
| 30 | + | |
30 | 31 | | |
31 | | - | |
32 | | - | |
33 | | - | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
34 | 39 | | |
35 | 40 | | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
40 | 51 | | |
41 | | - | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
42 | 55 | | |
43 | 56 | | |
44 | 57 | | |
| 58 | + | |
45 | 59 | | |
46 | 60 | | |
47 | 61 | | |
48 | 62 | | |
49 | 63 | | |
50 | 64 | | |
51 | | - | |
| 65 | + | |
52 | 66 | | |
53 | 67 | | |
54 | | - | |
| 68 | + | |
55 | 69 | | |
56 | 70 | | |
57 | | - | |
| 71 | + | |
58 | 72 | | |
59 | | - | |
| 73 | + | |
60 | 74 | | |
61 | 75 | | |
62 | 76 | | |
| |||
71 | 85 | | |
72 | 86 | | |
73 | 87 | | |
| 88 | + | |
74 | 89 | | |
75 | 90 | | |
76 | 91 | | |
| |||
86 | 101 | | |
87 | 102 | | |
88 | 103 | | |
89 | | - | |
| 104 | + | |
90 | 105 | | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
97 | 114 | | |
98 | 115 | | |
99 | 116 | | |
100 | | - | |
| 117 | + | |
101 | 118 | | |
102 | 119 | | |
103 | | - | |
| 120 | + | |
104 | 121 | | |
105 | 122 | | |
106 | | - | |
| 123 | + | |
107 | 124 | | |
108 | | - | |
109 | | - | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
110 | 129 | | |
111 | 130 | | |
112 | 131 | | |
| |||
118 | 137 | | |
119 | 138 | | |
120 | 139 | | |
121 | | - | |
| 140 | + | |
122 | 141 | | |
123 | | - | |
| 142 | + | |
124 | 143 | | |
125 | 144 | | |
126 | 145 | | |
127 | 146 | | |
128 | 147 | | |
129 | | - | |
| 148 | + | |
130 | 149 | | |
131 | 150 | | |
| 151 | + | |
132 | 152 | | |
133 | 153 | | |
134 | 154 | | |
135 | | - | |
| 155 | + | |
136 | 156 | | |
137 | 157 | | |
138 | 158 | | |
| |||
147 | 167 | | |
148 | 168 | | |
149 | 169 | | |
150 | | - | |
| 170 | + | |
151 | 171 | | |
152 | 172 | | |
153 | | - | |
| 173 | + | |
154 | 174 | | |
155 | 175 | | |
| 176 | + | |
156 | 177 | | |
157 | 178 | | |
158 | 179 | | |
| |||
168 | 189 | | |
169 | 190 | | |
170 | 191 | | |
171 | | - | |
| 192 | + | |
172 | 193 | | |
173 | | - | |
| 194 | + | |
174 | 195 | | |
175 | | - | |
| 196 | + | |
176 | 197 | | |
| 198 | + | |
177 | 199 | | |
178 | 200 | | |
179 | | - | |
180 | | - | |
| 201 | + | |
| 202 | + | |
0 commit comments