fix(cli): repair the doctor connectivity check - #72

Merged
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check
Aug 28, 2026
Merged

fix(cli): repair the doctor connectivity check#72
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The bug

nl2sql doctor — the command a user runs when something is already wrong — crashed instead of diagnosing:

$ nl2sql doctor
File "packages/nl2sql/src/nl2sql/cli/checks.py", line 20, in verify_connectivity
from nl2sql.datasources import load_profiles
ImportError: cannot import name 'load_profiles' from 'nl2sql.datasources'
Please report this bug to the nl2sql team.

verify_connectivity() carried two phantom imports against an API that does not exist:

  • from nl2sql.datasources import load_profilesnl2sql.datasources exports DatasourceRegistry, discover_adapters, the models and the adapter protocol. There is no load_profiles.
  • from nl2sql.diagnostics import check_connectivity as core_check — there is no nl2sql.diagnostics module at all.

Both imports sat at lines 19-21, outside the try: that begins at line 23. That is why the ImportError escaped the function's own error handling and surfaced as an unhandled-exception traceback rather than a failed check.

nl2sql setup was 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 alongside cli/commands/doctor.py:48.

The fix

verify_connectivity() is rewritten against the real API, following the construction order already used by nl2sql/context.py and cli/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.

doctor must never crash, so each failure mode is reported instead of raised:

FailureBehaviour
Config file missing or unparseableConnectivity check failed: ... message, returns False
Adapter driver not installed (mssql without pyodbc)Failed row with the driver error
Unknown engine typeFailed row
Unresolvable ${env:...} secretFailed row
test_connection() returns FalseFailed row
test_connection() raisesFailed row with the exception text
Zero datasources configuredNo datasources configured. message, returns True

test_connection() on BaseSQLAlchemyAdapter returns False on failure, but the protocol only declares -> bool and a third-party adapter may raise, so both are handled.

The return contract is unchanged — True only when every datasource connected — because setup.py branches 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.checks is imported only from cli/commands/, and none of nl2sql.configs, nl2sql.datasources or nl2sql.secrets import anything under nl2sql.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 as Text rather than a markup string — a driver error containing a bracket sequence such as [/{style}] must not raise MarkupError or be silently swallowed. This is the discipline test_cli_error_markup.py exists 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_connectivity returns True when all adapters connect, False when one fails, and does not raise in either case
  • a missing config, and an unparseable config, are reported rather than raised
  • an adapter raising inside test_connection() is caught and reported — with markup-shaped text in the exception message
  • an adapter returning False is reported
  • an unresolvable ${env:...} secret is reported
  • zero datasources is reported
  • nl2sql doctor exits 0 and prints the connectivity table — the CLI smoke test that would have caught the original bug. Against main it fails with assert 1 == 0 and the ImportError traceback 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-randomly active):

  • pytest -m "not integration"241 passed, 1 skipped, 47 deselected (baseline 231 + 10 new)
  • pytest -m "integration and not llm"28 passed, 261 deselected

@nadeem4
nadeem4 merged commit 2abb600 into mainAug 28, 2026
8 checks passed
@nadeem4
nadeem4 deleted the fix/doctor-connectivity-check branch August 28, 2026 18:48
Sign up for freeto 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.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(cli): repair the doctor connectivity check - #72

Merged
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check
Aug 28, 2026
Merged

fix(cli): repair the doctor connectivity check#72
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The bug

nl2sql doctor — the command a user runs when something is already wrong — crashed instead of diagnosing:

$ nl2sql doctor
File "packages/nl2sql/src/nl2sql/cli/checks.py", line 20, in verify_connectivity
from nl2sql.datasources import load_profiles
ImportError: cannot import name 'load_profiles' from 'nl2sql.datasources'
Please report this bug to the nl2sql team.

verify_connectivity() carried two phantom imports against an API that does not exist:

  • from nl2sql.datasources import load_profilesnl2sql.datasources exports DatasourceRegistry, discover_adapters, the models and the adapter protocol. There is no load_profiles.
  • from nl2sql.diagnostics import check_connectivity as core_check — there is no nl2sql.diagnostics module at all.

Both imports sat at lines 19-21, outside the try: that begins at line 23. That is why the ImportError escaped the function's own error handling and surfaced as an unhandled-exception traceback rather than a failed check.

nl2sql setup was 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 alongside cli/commands/doctor.py:48.

The fix

verify_connectivity() is rewritten against the real API, following the construction order already used by nl2sql/context.py and cli/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.

doctor must never crash, so each failure mode is reported instead of raised:

FailureBehaviour
Config file missing or unparseableConnectivity check failed: ... message, returns False
Adapter driver not installed (mssql without pyodbc)Failed row with the driver error
Unknown engine typeFailed row
Unresolvable ${env:...} secretFailed row
test_connection() returns FalseFailed row
test_connection() raisesFailed row with the exception text
Zero datasources configuredNo datasources configured. message, returns True

test_connection() on BaseSQLAlchemyAdapter returns False on failure, but the protocol only declares -> bool and a third-party adapter may raise, so both are handled.

The return contract is unchanged — True only when every datasource connected — because setup.py branches 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.checks is imported only from cli/commands/, and none of nl2sql.configs, nl2sql.datasources or nl2sql.secrets import anything under nl2sql.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 as Text rather than a markup string — a driver error containing a bracket sequence such as [/{style}] must not raise MarkupError or be silently swallowed. This is the discipline test_cli_error_markup.py exists 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_connectivity returns True when all adapters connect, False when one fails, and does not raise in either case
  • a missing config, and an unparseable config, are reported rather than raised
  • an adapter raising inside test_connection() is caught and reported — with markup-shaped text in the exception message
  • an adapter returning False is reported
  • an unresolvable ${env:...} secret is reported
  • zero datasources is reported
  • nl2sql doctor exits 0 and prints the connectivity table — the CLI smoke test that would have caught the original bug. Against main it fails with assert 1 == 0 and the ImportError traceback 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-randomly active):

  • pytest -m "not integration"241 passed, 1 skipped, 47 deselected (baseline 231 + 10 new)
  • pytest -m "integration and not llm"28 passed, 261 deselected

@nadeem4
nadeem4 merged commit 2abb600 into mainAug 28, 2026
8 checks passed
@nadeem4
nadeem4 deleted the fix/doctor-connectivity-check branch August 28, 2026 18:48
Sign up for freeto 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.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(cli): repair the doctor connectivity check - #72

Merged
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check
Aug 28, 2026
Merged

fix(cli): repair the doctor connectivity check#72
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The bug

nl2sql doctor — the command a user runs when something is already wrong — crashed instead of diagnosing:

$ nl2sql doctor
File "packages/nl2sql/src/nl2sql/cli/checks.py", line 20, in verify_connectivity
from nl2sql.datasources import load_profiles
ImportError: cannot import name 'load_profiles' from 'nl2sql.datasources'
Please report this bug to the nl2sql team.

verify_connectivity() carried two phantom imports against an API that does not exist:

  • from nl2sql.datasources import load_profilesnl2sql.datasources exports DatasourceRegistry, discover_adapters, the models and the adapter protocol. There is no load_profiles.
  • from nl2sql.diagnostics import check_connectivity as core_check — there is no nl2sql.diagnostics module at all.

Both imports sat at lines 19-21, outside the try: that begins at line 23. That is why the ImportError escaped the function's own error handling and surfaced as an unhandled-exception traceback rather than a failed check.

nl2sql setup was 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 alongside cli/commands/doctor.py:48.

The fix

verify_connectivity() is rewritten against the real API, following the construction order already used by nl2sql/context.py and cli/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.

doctor must never crash, so each failure mode is reported instead of raised:

FailureBehaviour
Config file missing or unparseableConnectivity check failed: ... message, returns False
Adapter driver not installed (mssql without pyodbc)Failed row with the driver error
Unknown engine typeFailed row
Unresolvable ${env:...} secretFailed row
test_connection() returns FalseFailed row
test_connection() raisesFailed row with the exception text
Zero datasources configuredNo datasources configured. message, returns True

test_connection() on BaseSQLAlchemyAdapter returns False on failure, but the protocol only declares -> bool and a third-party adapter may raise, so both are handled.

The return contract is unchanged — True only when every datasource connected — because setup.py branches 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.checks is imported only from cli/commands/, and none of nl2sql.configs, nl2sql.datasources or nl2sql.secrets import anything under nl2sql.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 as Text rather than a markup string — a driver error containing a bracket sequence such as [/{style}] must not raise MarkupError or be silently swallowed. This is the discipline test_cli_error_markup.py exists 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_connectivity returns True when all adapters connect, False when one fails, and does not raise in either case
  • a missing config, and an unparseable config, are reported rather than raised
  • an adapter raising inside test_connection() is caught and reported — with markup-shaped text in the exception message
  • an adapter returning False is reported
  • an unresolvable ${env:...} secret is reported
  • zero datasources is reported
  • nl2sql doctor exits 0 and prints the connectivity table — the CLI smoke test that would have caught the original bug. Against main it fails with assert 1 == 0 and the ImportError traceback 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-randomly active):

  • pytest -m "not integration"241 passed, 1 skipped, 47 deselected (baseline 231 + 10 new)
  • pytest -m "integration and not llm"28 passed, 261 deselected

@nadeem4
nadeem4 merged commit 2abb600 into mainAug 28, 2026
8 checks passed
@nadeem4
nadeem4 deleted the fix/doctor-connectivity-check branch August 28, 2026 18:48
Sign up for freeto 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.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(cli): repair the doctor connectivity check - #72

Merged
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check
Aug 28, 2026
Merged

fix(cli): repair the doctor connectivity check#72
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The bug

nl2sql doctor — the command a user runs when something is already wrong — crashed instead of diagnosing:

$ nl2sql doctor
File "packages/nl2sql/src/nl2sql/cli/checks.py", line 20, in verify_connectivity
from nl2sql.datasources import load_profiles
ImportError: cannot import name 'load_profiles' from 'nl2sql.datasources'
Please report this bug to the nl2sql team.

verify_connectivity() carried two phantom imports against an API that does not exist:

  • from nl2sql.datasources import load_profilesnl2sql.datasources exports DatasourceRegistry, discover_adapters, the models and the adapter protocol. There is no load_profiles.
  • from nl2sql.diagnostics import check_connectivity as core_check — there is no nl2sql.diagnostics module at all.

Both imports sat at lines 19-21, outside the try: that begins at line 23. That is why the ImportError escaped the function's own error handling and surfaced as an unhandled-exception traceback rather than a failed check.

nl2sql setup was 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 alongside cli/commands/doctor.py:48.

The fix

verify_connectivity() is rewritten against the real API, following the construction order already used by nl2sql/context.py and cli/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.

doctor must never crash, so each failure mode is reported instead of raised:

FailureBehaviour
Config file missing or unparseableConnectivity check failed: ... message, returns False
Adapter driver not installed (mssql without pyodbc)Failed row with the driver error
Unknown engine typeFailed row
Unresolvable ${env:...} secretFailed row
test_connection() returns FalseFailed row
test_connection() raisesFailed row with the exception text
Zero datasources configuredNo datasources configured. message, returns True

test_connection() on BaseSQLAlchemyAdapter returns False on failure, but the protocol only declares -> bool and a third-party adapter may raise, so both are handled.

The return contract is unchanged — True only when every datasource connected — because setup.py branches 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.checks is imported only from cli/commands/, and none of nl2sql.configs, nl2sql.datasources or nl2sql.secrets import anything under nl2sql.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 as Text rather than a markup string — a driver error containing a bracket sequence such as [/{style}] must not raise MarkupError or be silently swallowed. This is the discipline test_cli_error_markup.py exists 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_connectivity returns True when all adapters connect, False when one fails, and does not raise in either case
  • a missing config, and an unparseable config, are reported rather than raised
  • an adapter raising inside test_connection() is caught and reported — with markup-shaped text in the exception message
  • an adapter returning False is reported
  • an unresolvable ${env:...} secret is reported
  • zero datasources is reported
  • nl2sql doctor exits 0 and prints the connectivity table — the CLI smoke test that would have caught the original bug. Against main it fails with assert 1 == 0 and the ImportError traceback 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-randomly active):

  • pytest -m "not integration"241 passed, 1 skipped, 47 deselected (baseline 231 + 10 new)
  • pytest -m "integration and not llm"28 passed, 261 deselected

@nadeem4
nadeem4 merged commit 2abb600 into mainAug 28, 2026
8 checks passed
@nadeem4
nadeem4 deleted the fix/doctor-connectivity-check branch August 28, 2026 18:48
Sign up for freeto 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.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(cli): repair the doctor connectivity check - #72

Merged
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check
Aug 28, 2026
Merged

fix(cli): repair the doctor connectivity check#72
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The bug

nl2sql doctor — the command a user runs when something is already wrong — crashed instead of diagnosing:

$ nl2sql doctor
File "packages/nl2sql/src/nl2sql/cli/checks.py", line 20, in verify_connectivity
from nl2sql.datasources import load_profiles
ImportError: cannot import name 'load_profiles' from 'nl2sql.datasources'
Please report this bug to the nl2sql team.

verify_connectivity() carried two phantom imports against an API that does not exist:

  • from nl2sql.datasources import load_profilesnl2sql.datasources exports DatasourceRegistry, discover_adapters, the models and the adapter protocol. There is no load_profiles.
  • from nl2sql.diagnostics import check_connectivity as core_check — there is no nl2sql.diagnostics module at all.

Both imports sat at lines 19-21, outside the try: that begins at line 23. That is why the ImportError escaped the function's own error handling and surfaced as an unhandled-exception traceback rather than a failed check.

nl2sql setup was 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 alongside cli/commands/doctor.py:48.

The fix

verify_connectivity() is rewritten against the real API, following the construction order already used by nl2sql/context.py and cli/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.

doctor must never crash, so each failure mode is reported instead of raised:

FailureBehaviour
Config file missing or unparseableConnectivity check failed: ... message, returns False
Adapter driver not installed (mssql without pyodbc)Failed row with the driver error
Unknown engine typeFailed row
Unresolvable ${env:...} secretFailed row
test_connection() returns FalseFailed row
test_connection() raisesFailed row with the exception text
Zero datasources configuredNo datasources configured. message, returns True

test_connection() on BaseSQLAlchemyAdapter returns False on failure, but the protocol only declares -> bool and a third-party adapter may raise, so both are handled.

The return contract is unchanged — True only when every datasource connected — because setup.py branches 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.checks is imported only from cli/commands/, and none of nl2sql.configs, nl2sql.datasources or nl2sql.secrets import anything under nl2sql.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 as Text rather than a markup string — a driver error containing a bracket sequence such as [/{style}] must not raise MarkupError or be silently swallowed. This is the discipline test_cli_error_markup.py exists 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_connectivity returns True when all adapters connect, False when one fails, and does not raise in either case
  • a missing config, and an unparseable config, are reported rather than raised
  • an adapter raising inside test_connection() is caught and reported — with markup-shaped text in the exception message
  • an adapter returning False is reported
  • an unresolvable ${env:...} secret is reported
  • zero datasources is reported
  • nl2sql doctor exits 0 and prints the connectivity table — the CLI smoke test that would have caught the original bug. Against main it fails with assert 1 == 0 and the ImportError traceback 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-randomly active):

  • pytest -m "not integration"241 passed, 1 skipped, 47 deselected (baseline 231 + 10 new)
  • pytest -m "integration and not llm"28 passed, 261 deselected

@nadeem4
nadeem4 merged commit 2abb600 into mainAug 28, 2026
8 checks passed
@nadeem4
nadeem4 deleted the fix/doctor-connectivity-check branch August 28, 2026 18:48
Sign up for freeto 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.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(cli): repair the doctor connectivity check - #72

Merged
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check
Aug 28, 2026
Merged

fix(cli): repair the doctor connectivity check#72
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The bug

nl2sql doctor — the command a user runs when something is already wrong — crashed instead of diagnosing:

$ nl2sql doctor
File "packages/nl2sql/src/nl2sql/cli/checks.py", line 20, in verify_connectivity
from nl2sql.datasources import load_profiles
ImportError: cannot import name 'load_profiles' from 'nl2sql.datasources'
Please report this bug to the nl2sql team.

verify_connectivity() carried two phantom imports against an API that does not exist:

  • from nl2sql.datasources import load_profilesnl2sql.datasources exports DatasourceRegistry, discover_adapters, the models and the adapter protocol. There is no load_profiles.
  • from nl2sql.diagnostics import check_connectivity as core_check — there is no nl2sql.diagnostics module at all.

Both imports sat at lines 19-21, outside the try: that begins at line 23. That is why the ImportError escaped the function's own error handling and surfaced as an unhandled-exception traceback rather than a failed check.

nl2sql setup was 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 alongside cli/commands/doctor.py:48.

The fix

verify_connectivity() is rewritten against the real API, following the construction order already used by nl2sql/context.py and cli/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.

doctor must never crash, so each failure mode is reported instead of raised:

FailureBehaviour
Config file missing or unparseableConnectivity check failed: ... message, returns False
Adapter driver not installed (mssql without pyodbc)Failed row with the driver error
Unknown engine typeFailed row
Unresolvable ${env:...} secretFailed row
test_connection() returns FalseFailed row
test_connection() raisesFailed row with the exception text
Zero datasources configuredNo datasources configured. message, returns True

test_connection() on BaseSQLAlchemyAdapter returns False on failure, but the protocol only declares -> bool and a third-party adapter may raise, so both are handled.

The return contract is unchanged — True only when every datasource connected — because setup.py branches 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.checks is imported only from cli/commands/, and none of nl2sql.configs, nl2sql.datasources or nl2sql.secrets import anything under nl2sql.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 as Text rather than a markup string — a driver error containing a bracket sequence such as [/{style}] must not raise MarkupError or be silently swallowed. This is the discipline test_cli_error_markup.py exists 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_connectivity returns True when all adapters connect, False when one fails, and does not raise in either case
  • a missing config, and an unparseable config, are reported rather than raised
  • an adapter raising inside test_connection() is caught and reported — with markup-shaped text in the exception message
  • an adapter returning False is reported
  • an unresolvable ${env:...} secret is reported
  • zero datasources is reported
  • nl2sql doctor exits 0 and prints the connectivity table — the CLI smoke test that would have caught the original bug. Against main it fails with assert 1 == 0 and the ImportError traceback 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-randomly active):

  • pytest -m "not integration"241 passed, 1 skipped, 47 deselected (baseline 231 + 10 new)
  • pytest -m "integration and not llm"28 passed, 261 deselected

@nadeem4
nadeem4 merged commit 2abb600 into mainAug 28, 2026
8 checks passed
@nadeem4
nadeem4 deleted the fix/doctor-connectivity-check branch August 28, 2026 18:48
Sign up for freeto 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.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(cli): repair the doctor connectivity check - #72

Merged
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check
Aug 28, 2026
Merged

fix(cli): repair the doctor connectivity check#72
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The bug

nl2sql doctor — the command a user runs when something is already wrong — crashed instead of diagnosing:

$ nl2sql doctor
File "packages/nl2sql/src/nl2sql/cli/checks.py", line 20, in verify_connectivity
from nl2sql.datasources import load_profiles
ImportError: cannot import name 'load_profiles' from 'nl2sql.datasources'
Please report this bug to the nl2sql team.

verify_connectivity() carried two phantom imports against an API that does not exist:

  • from nl2sql.datasources import load_profilesnl2sql.datasources exports DatasourceRegistry, discover_adapters, the models and the adapter protocol. There is no load_profiles.
  • from nl2sql.diagnostics import check_connectivity as core_check — there is no nl2sql.diagnostics module at all.

Both imports sat at lines 19-21, outside the try: that begins at line 23. That is why the ImportError escaped the function's own error handling and surfaced as an unhandled-exception traceback rather than a failed check.

nl2sql setup was 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 alongside cli/commands/doctor.py:48.

The fix

verify_connectivity() is rewritten against the real API, following the construction order already used by nl2sql/context.py and cli/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.

doctor must never crash, so each failure mode is reported instead of raised:

FailureBehaviour
Config file missing or unparseableConnectivity check failed: ... message, returns False
Adapter driver not installed (mssql without pyodbc)Failed row with the driver error
Unknown engine typeFailed row
Unresolvable ${env:...} secretFailed row
test_connection() returns FalseFailed row
test_connection() raisesFailed row with the exception text
Zero datasources configuredNo datasources configured. message, returns True

test_connection() on BaseSQLAlchemyAdapter returns False on failure, but the protocol only declares -> bool and a third-party adapter may raise, so both are handled.

The return contract is unchanged — True only when every datasource connected — because setup.py branches 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.checks is imported only from cli/commands/, and none of nl2sql.configs, nl2sql.datasources or nl2sql.secrets import anything under nl2sql.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 as Text rather than a markup string — a driver error containing a bracket sequence such as [/{style}] must not raise MarkupError or be silently swallowed. This is the discipline test_cli_error_markup.py exists 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_connectivity returns True when all adapters connect, False when one fails, and does not raise in either case
  • a missing config, and an unparseable config, are reported rather than raised
  • an adapter raising inside test_connection() is caught and reported — with markup-shaped text in the exception message
  • an adapter returning False is reported
  • an unresolvable ${env:...} secret is reported
  • zero datasources is reported
  • nl2sql doctor exits 0 and prints the connectivity table — the CLI smoke test that would have caught the original bug. Against main it fails with assert 1 == 0 and the ImportError traceback 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-randomly active):

  • pytest -m "not integration"241 passed, 1 skipped, 47 deselected (baseline 231 + 10 new)
  • pytest -m "integration and not llm"28 passed, 261 deselected

@nadeem4
nadeem4 merged commit 2abb600 into mainAug 28, 2026
8 checks passed
@nadeem4
nadeem4 deleted the fix/doctor-connectivity-check branch August 28, 2026 18:48
Sign up for freeto 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.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(cli): repair the doctor connectivity check - #72

Merged
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check
Aug 28, 2026
Merged

fix(cli): repair the doctor connectivity check#72
nadeem4 merged 1 commit into
mainfrom
fix/doctor-connectivity-check

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The bug

nl2sql doctor — the command a user runs when something is already wrong — crashed instead of diagnosing:

$ nl2sql doctor
File "packages/nl2sql/src/nl2sql/cli/checks.py", line 20, in verify_connectivity
from nl2sql.datasources import load_profiles
ImportError: cannot import name 'load_profiles' from 'nl2sql.datasources'
Please report this bug to the nl2sql team.

verify_connectivity() carried two phantom imports against an API that does not exist:

  • from nl2sql.datasources import load_profilesnl2sql.datasources exports DatasourceRegistry, discover_adapters, the models and the adapter protocol. There is no load_profiles.
  • from nl2sql.diagnostics import check_connectivity as core_check — there is no nl2sql.diagnostics module at all.

Both imports sat at lines 19-21, outside the try: that begins at line 23. That is why the ImportError escaped the function's own error handling and surfaced as an unhandled-exception traceback rather than a failed check.

nl2sql setup was 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 alongside cli/commands/doctor.py:48.

The fix

verify_connectivity() is rewritten against the real API, following the construction order already used by nl2sql/context.py and cli/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.

doctor must never crash, so each failure mode is reported instead of raised:

FailureBehaviour
Config file missing or unparseableConnectivity check failed: ... message, returns False
Adapter driver not installed (mssql without pyodbc)Failed row with the driver error
Unknown engine typeFailed row
Unresolvable ${env:...} secretFailed row
test_connection() returns FalseFailed row
test_connection() raisesFailed row with the exception text
Zero datasources configuredNo datasources configured. message, returns True

test_connection() on BaseSQLAlchemyAdapter returns False on failure, but the protocol only declares -> bool and a third-party adapter may raise, so both are handled.

The return contract is unchanged — True only when every datasource connected — because setup.py branches 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.checks is imported only from cli/commands/, and none of nl2sql.configs, nl2sql.datasources or nl2sql.secrets import anything under nl2sql.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 as Text rather than a markup string — a driver error containing a bracket sequence such as [/{style}] must not raise MarkupError or be silently swallowed. This is the discipline test_cli_error_markup.py exists 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_connectivity returns True when all adapters connect, False when one fails, and does not raise in either case
  • a missing config, and an unparseable config, are reported rather than raised
  • an adapter raising inside test_connection() is caught and reported — with markup-shaped text in the exception message
  • an adapter returning False is reported
  • an unresolvable ${env:...} secret is reported
  • zero datasources is reported
  • nl2sql doctor exits 0 and prints the connectivity table — the CLI smoke test that would have caught the original bug. Against main it fails with assert 1 == 0 and the ImportError traceback 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-randomly active):

  • pytest -m "not integration"241 passed, 1 skipped, 47 deselected (baseline 231 + 10 new)
  • pytest -m "integration and not llm"28 passed, 261 deselected

@nadeem4
nadeem4 merged commit 2abb600 into mainAug 28, 2026
8 checks passed
@nadeem4
nadeem4 deleted the fix/doctor-connectivity-check branch August 28, 2026 18:48
Sign up for freeto 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.

1 participant

@nadeem4