fix(cli): repair the doctor connectivity check - #72
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
nl2sql doctor— the command a user runs when something is already wrong — crashed instead of diagnosing:verify_connectivity()carried two phantom imports against an API that does not exist:from nl2sql.datasources import load_profiles—nl2sql.datasourcesexportsDatasourceRegistry,discover_adapters, the models and the adapter protocol. There is noload_profiles.from nl2sql.diagnostics import check_connectivity as core_check— there is nonl2sql.diagnosticsmodule at all.Both imports sat at lines 19-21, outside the
try:that begins at line 23. That is why theImportErrorescaped the function's own error handling and surfaced as an unhandled-exception traceback rather than a failed check.nl2sql setupwas affected too: the wizard's connectivity step (cli/commands/setup.py:405) calls the same function, so it died the same way — the second caller alongsidecli/commands/doctor.py:48.The fix
verify_connectivity()is rewritten against the real API, following the construction order already used bynl2sql/context.pyandcli/demo/manager.py:ConfigManager()→load_secrets()/SecretManager.configure()→load_datasources()→DatasourceRegistry(secret_manager)→register_datasource()per config →adapter.test_connection().Datasources are registered one at a time rather than through
register_datasources(), which raises on the first bad entry and would abort the whole check. Every datasource now gets its own row.doctormust never crash, so each failure mode is reported instead of raised:Connectivity check failed: ...message, returnsFalsemssqlwithoutpyodbc)Failedrow with the driver errorFailedrow${env:...}secretFailedrowtest_connection()returnsFalseFailedrowtest_connection()raisesFailedrow with the exception textNo datasources configured.message, returnsTruetest_connection()onBaseSQLAlchemyAdapterreturnsFalseon failure, but the protocol only declares-> booland a third-party adapter may raise, so both are handled.The return contract is unchanged —
Trueonly when every datasource connected — becausesetup.pybranches on it.Imports moved to module level
The three imports (
ConfigManager,DatasourceRegistry,SecretManager) are now at module level. There is no circular-import reason to keep them local:nl2sql.cli.checksis imported only fromcli/commands/, and none ofnl2sql.configs,nl2sql.datasourcesornl2sql.secretsimport anything undernl2sql.cli. A phantom import would now fail at import time, loudly, instead of at the moment a user needs the command.Rich markup
Datasource ids and driver error text are wrapped in
Text(...)before they reach the table, and the config-error message is printed asTextrather than a markup string — a driver error containing a bracket sequence such as[/{style}]must not raiseMarkupErroror be silently swallowed. This is the disciplinetest_cli_error_markup.pyexists to protect.Tests
New:
packages/nl2sql/tests/cli/test_doctor_connectivity.py(10 tests). The absence of any coverage here is why this shipped.verify_connectivityreturnsTruewhen all adapters connect,Falsewhen one fails, and does not raise in either casetest_connection()is caught and reported — with markup-shaped text in the exception messageFalseis reported${env:...}secret is reportednl2sql doctorexits 0 and prints the connectivity table — the CLI smoke test that would have caught the original bug. Againstmainit fails withassert 1 == 0and theImportErrortraceback in the captured output.All 10 fail on
main; all 10 pass here. SQLite and stubs only — no live database, no network, no API key.Suites, run twice each (
pytest-randomlyactive):pytest -m "not integration"—241 passed, 1 skipped, 47 deselected(baseline 231 + 10 new)pytest -m "integration and not llm"—28 passed, 261 deselected