sqlsaber 0.31.0__tar.gz → 0.32.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.
Potentially problematic release.
This version of sqlsaber might be problematic. Click here for more details.
- sqlsaber-0.32.0/AGENTS.md +44 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/PKG-INFO +1 -1
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/content/docs/changelog.md +6 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/pyproject.toml +1 -1
- sqlsaber-0.32.0/sqlsaber.gif +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/commands.py +49 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_cli/test_commands.py +47 -1
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/uv.lock +1 -1
- sqlsaber-0.31.0/AGENT.md +0 -23
- sqlsaber-0.31.0/sqlsaber.gif +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/.github/workflows/claude-code-review.yml +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/.github/workflows/claude.yml +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/.github/workflows/deploy-docs.yml +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/.github/workflows/publish.yml +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/.github/workflows/test.yml +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/.gitignore +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/.python-version +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/CLAUDE.md +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/LICENSE +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/README.md +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/.gitignore +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/.vscode/extensions.json +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/.vscode/launch.json +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/CLAUDE.md +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/astro.config.mjs +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/package-lock.json +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/package.json +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/public/CNAME +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/public/favicon.svg +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/assets/sqlsaber.gif +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/content/docs/guides/authentication.mdx +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/content/docs/guides/database-setup.mdx +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/content/docs/guides/getting-started.mdx +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/content/docs/guides/memory.mdx +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/content/docs/guides/models.mdx +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/content/docs/guides/queries.mdx +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/content/docs/guides/threads.md +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/content/docs/index.mdx +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/content/docs/installation.mdx +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/content/docs/reference/commands.md +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/content.config.ts +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/src/styles/global.css +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/docs/tsconfig.json +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/legislators.db +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/pytest.ini +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/sqlsaber.svg +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/__main__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/agents/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/agents/base.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/agents/pydantic_ai_agent.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/application/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/application/auth_setup.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/application/db_setup.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/application/model_selection.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/application/prompts.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/auth.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/completers.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/database.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/display.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/interactive.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/memory.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/models.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/onboarding.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/streaming.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/theme.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/cli/threads.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/config/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/config/api_keys.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/config/auth.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/config/database.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/config/logging.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/config/oauth_flow.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/config/oauth_tokens.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/config/providers.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/config/settings.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/database/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/database/base.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/database/csv.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/database/duckdb.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/database/mysql.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/database/postgresql.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/database/resolver.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/database/schema.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/database/sqlite.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/memory/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/memory/manager.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/memory/storage.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/theme/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/theme/manager.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/threads/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/threads/storage.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/tools/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/tools/base.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/tools/registry.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/tools/sql_guard.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/src/sqlsaber/tools/sql_tools.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/conftest.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_cli/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_cli/test_auth_reset.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_cli/test_threads.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_config/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_config/test_database.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_config/test_oauth.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_config/test_providers.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_config/test_settings.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_database/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_database/test_connection.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_database/test_csv_connection.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_database/test_csv_module.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_database/test_duckdb_module.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_database/test_schema.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_database/test_schema_display.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_database/test_sqlite_module.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_database/test_timeout.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_database_resolver.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_theme/test_manager.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_threads_storage.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_tools/__init__.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_tools/test_base.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_tools/test_registry.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_tools/test_sql_guard.py +0 -0
- {sqlsaber-0.31.0 → sqlsaber-0.32.0}/tests/test_tools/test_sql_tools.py +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Repository Guidelines
|
|
2
|
+
|
|
3
|
+
## Project Structure & Module Organization
|
|
4
|
+
- Source: `src/sqlsaber/`
|
|
5
|
+
- `cli/`: CLI entry (`saber`, `sqlsaber`), REPL, prompts.
|
|
6
|
+
- `agents/`: agent implementations (pydantic‑ai).
|
|
7
|
+
- `tools/`: SQL, introspection, registry.
|
|
8
|
+
- `database/`: connection, resolver, schema utilities.
|
|
9
|
+
- `memory/`, `conversation/`: state and persistence.
|
|
10
|
+
- `config/`: settings, API keys, OAuth, DB configs.
|
|
11
|
+
- Tests: `tests/` mirror modules (`test_cli/`, `test_tools/`, …).
|
|
12
|
+
- Docs & assets: `docs/`, `sqlsaber.gif`, `sqlsaber.svg`.
|
|
13
|
+
|
|
14
|
+
## Build, Test, and Development Commands
|
|
15
|
+
- Install (editable): `uv sync`
|
|
16
|
+
- Lint: `uv run ruff check .`
|
|
17
|
+
- Format: `uv run ruff format .`
|
|
18
|
+
- Tests (all): `uv run pytest -q`
|
|
19
|
+
- Tests (targeted): `uv run pytest tests/test_tools -q`
|
|
20
|
+
- Run CLI (dev): `uv run saber` or `uv run python -m sqlsaber`
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
Note: Prefer `uv run ruff ...` over `uvx ruff ...` to avoid hitting user-level uv caches that may be restricted in sandboxed environments.
|
|
24
|
+
|
|
25
|
+
## Coding Style & Naming Conventions
|
|
26
|
+
- Python 3.12+, 4‑space indent, use modern type hints.
|
|
27
|
+
- Ruff is the linter/formatter; code must be clean and formatted.
|
|
28
|
+
- Naming: modules/files `snake_case.py`; classes `PascalCase`; functions/vars `snake_case`; constants `UPPER_SNAKE`.
|
|
29
|
+
- Keep public CLI surfaces in `cli/`; factor reusable logic into modules under `sqlsaber/`.
|
|
30
|
+
|
|
31
|
+
## Testing Guidelines
|
|
32
|
+
- Framework: `pytest` with `pytest-asyncio`.
|
|
33
|
+
- Place tests under `tests/`, name files `test_*.py` and mirror package layout.
|
|
34
|
+
- Include tests for new behavior and bug fixes; prefer async tests for async code.
|
|
35
|
+
- Use fixtures from `tests/conftest.py` where possible.
|
|
36
|
+
|
|
37
|
+
## Commit & Pull Request Guidelines
|
|
38
|
+
- Commits: short, imperative; prefer conventional prefixes (e.g., `feat:`, `fix:`, `docs:`). Reference issues/PRs when relevant.
|
|
39
|
+
- PRs must: describe the change and rationale, include tests, pass `ruff` and `pytest`, and update docs/README for user‑visible changes.
|
|
40
|
+
- For CLI UX changes, include before/after samples (command + output snippet).
|
|
41
|
+
|
|
42
|
+
## Security & Configuration Tips
|
|
43
|
+
- Never commit secrets. Configure via CLI: `saber db add` and `saber models set` (credentials stored via system keyring).
|
|
44
|
+
- Queries run read‑only by default; avoid introducing mutating behavior in tools without explicit safeguards.
|
|
@@ -9,6 +9,12 @@ All notable changes to SQLsaber will be documented here.
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
### v0.32.0 - 2025-10-14
|
|
13
|
+
|
|
14
|
+
#### Added
|
|
15
|
+
|
|
16
|
+
- Optional MLflow autologging
|
|
17
|
+
- Set `MLFLOW_URI` and `MLFLOW_EXP` before running `sqlsaber` to forward telemetry via `mlflow.pydantic_ai.autolog()` with no runtime requirement when the MLflow package is absent.
|
|
12
18
|
|
|
13
19
|
### v0.31.0 - 2025-10-13
|
|
14
20
|
|
|
Binary file
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""CLI command definitions and handlers."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import os
|
|
4
5
|
import sys
|
|
5
6
|
from typing import Annotated
|
|
6
7
|
|
|
@@ -43,6 +44,52 @@ app.command(create_threads_app(), name="threads")
|
|
|
43
44
|
console = create_console()
|
|
44
45
|
config_manager = DatabaseConfigManager()
|
|
45
46
|
|
|
47
|
+
_MLFLOW_CONFIGURED = False
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _maybe_configure_mlflow(log) -> bool:
|
|
51
|
+
"""Enable mlflow autologging when environment variables are present."""
|
|
52
|
+
global _MLFLOW_CONFIGURED
|
|
53
|
+
if _MLFLOW_CONFIGURED:
|
|
54
|
+
return True
|
|
55
|
+
|
|
56
|
+
tracking_uri = os.getenv("MLFLOW_URI")
|
|
57
|
+
experiment = os.getenv("MLFLOW_EXP")
|
|
58
|
+
if not tracking_uri and not experiment:
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
import mlflow
|
|
63
|
+
except ModuleNotFoundError:
|
|
64
|
+
log.warning(
|
|
65
|
+
"mlflow.setup.skipped",
|
|
66
|
+
reason="mlflow package not installed",
|
|
67
|
+
uri=tracking_uri,
|
|
68
|
+
experiment=experiment,
|
|
69
|
+
)
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
mlflow.pydantic_ai.autolog()
|
|
74
|
+
except Exception:
|
|
75
|
+
log.warning("mlflow.autolog.failed", exc_info=True)
|
|
76
|
+
try:
|
|
77
|
+
if tracking_uri:
|
|
78
|
+
mlflow.set_tracking_uri(tracking_uri)
|
|
79
|
+
if experiment:
|
|
80
|
+
mlflow.set_experiment(experiment)
|
|
81
|
+
except Exception:
|
|
82
|
+
log.warning("mlflow.setup.failed", exc_info=True)
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
_MLFLOW_CONFIGURED = True
|
|
86
|
+
log.info(
|
|
87
|
+
"mlflow.setup.enabled",
|
|
88
|
+
uri=tracking_uri,
|
|
89
|
+
experiment=experiment,
|
|
90
|
+
)
|
|
91
|
+
return True
|
|
92
|
+
|
|
46
93
|
|
|
47
94
|
@app.meta.default
|
|
48
95
|
def meta_handler(
|
|
@@ -175,6 +222,7 @@ def query(
|
|
|
175
222
|
|
|
176
223
|
# Create pydantic-ai agent instance with database name for memory context
|
|
177
224
|
sqlsaber_agent = SQLSaberAgent(db_conn, db_name, thinking_enabled=thinking)
|
|
225
|
+
_maybe_configure_mlflow(log)
|
|
178
226
|
|
|
179
227
|
try:
|
|
180
228
|
if actual_query:
|
|
@@ -188,6 +236,7 @@ def query(
|
|
|
188
236
|
run = await streaming_handler.execute_streaming_query(
|
|
189
237
|
actual_query, sqlsaber_agent
|
|
190
238
|
)
|
|
239
|
+
|
|
191
240
|
# Persist non-interactive run as a thread snapshot so it can be resumed later
|
|
192
241
|
try:
|
|
193
242
|
if run is not None:
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"""Tests for CLI commands."""
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import sys
|
|
4
|
+
from unittest.mock import MagicMock, patch
|
|
4
5
|
|
|
5
6
|
import pytest
|
|
6
7
|
|
|
8
|
+
from sqlsaber.cli import commands
|
|
7
9
|
from sqlsaber.cli.commands import app
|
|
8
10
|
from sqlsaber.config.database import DatabaseConfig
|
|
9
11
|
|
|
@@ -61,3 +63,47 @@ class TestCLICommands:
|
|
|
61
63
|
assert "memory" in captured.out
|
|
62
64
|
assert "models" in captured.out
|
|
63
65
|
assert "auth" in captured.out
|
|
66
|
+
|
|
67
|
+
def test_maybe_configure_mlflow_no_env(self, monkeypatch):
|
|
68
|
+
"""MLflow stays disabled when env vars are absent."""
|
|
69
|
+
monkeypatch.delenv("MLFLOW_URI", raising=False)
|
|
70
|
+
monkeypatch.delenv("MLFLOW_EXP", raising=False)
|
|
71
|
+
commands._MLFLOW_CONFIGURED = False
|
|
72
|
+
logger = MagicMock()
|
|
73
|
+
|
|
74
|
+
assert not commands._maybe_configure_mlflow(logger)
|
|
75
|
+
logger.warning.assert_not_called()
|
|
76
|
+
|
|
77
|
+
def test_maybe_configure_mlflow_with_env(self, monkeypatch):
|
|
78
|
+
"""MLflow autolog is configured when env vars and package are present."""
|
|
79
|
+
monkeypatch.setenv("MLFLOW_URI", "http://localhost:5000")
|
|
80
|
+
monkeypatch.setenv("MLFLOW_EXP", "sqlsaber-bench")
|
|
81
|
+
commands._MLFLOW_CONFIGURED = False
|
|
82
|
+
autolog_called = MagicMock()
|
|
83
|
+
set_uri_called = MagicMock()
|
|
84
|
+
set_exp_called = MagicMock()
|
|
85
|
+
|
|
86
|
+
class FakeMlflow:
|
|
87
|
+
def __init__(self):
|
|
88
|
+
self.pydantic_ai = MagicMock(autolog=autolog_called)
|
|
89
|
+
|
|
90
|
+
def set_tracking_uri(self, uri):
|
|
91
|
+
set_uri_called(uri)
|
|
92
|
+
|
|
93
|
+
def set_experiment(self, exp):
|
|
94
|
+
set_exp_called(exp)
|
|
95
|
+
|
|
96
|
+
monkeypatch.setitem(sys.modules, "mlflow", FakeMlflow())
|
|
97
|
+
logger = MagicMock()
|
|
98
|
+
|
|
99
|
+
assert commands._maybe_configure_mlflow(logger)
|
|
100
|
+
autolog_called.assert_called_once()
|
|
101
|
+
set_uri_called.assert_called_once_with("http://localhost:5000")
|
|
102
|
+
set_exp_called.assert_called_once_with("sqlsaber-bench")
|
|
103
|
+
logger.info.assert_called()
|
|
104
|
+
|
|
105
|
+
# Ensure subsequent calls short-circuit
|
|
106
|
+
logger.reset_mock()
|
|
107
|
+
assert commands._maybe_configure_mlflow(logger)
|
|
108
|
+
logger.info.assert_not_called()
|
|
109
|
+
commands._MLFLOW_CONFIGURED = False
|
sqlsaber-0.31.0/AGENT.md
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# SQLSaber Agent Guide
|
|
2
|
-
|
|
3
|
-
## Commands
|
|
4
|
-
|
|
5
|
-
- **Run Python**: `uv run python`
|
|
6
|
-
- **Run tests**: `uv run python -m pytest`
|
|
7
|
-
- **Run single test**: `uv run python -m pytest tests/test_path/test_file.py::test_function`
|
|
8
|
-
- **Lint**: `uv run ruff check --fix`
|
|
9
|
-
- **Format**: `uv run ruff format`
|
|
10
|
-
|
|
11
|
-
## Architecture
|
|
12
|
-
|
|
13
|
-
- **CLI App**: Agentic SQL assistant for natural language to SQL
|
|
14
|
-
- **Core modules**: `agents/` (AI logic), `cli/` (commands), `database/` (connections)
|
|
15
|
-
- **Database support**: PostgreSQL, SQLite, MySQL via asyncpg/aiosqlite/aiomysql
|
|
16
|
-
|
|
17
|
-
## Code Style
|
|
18
|
-
|
|
19
|
-
- **Imports**: stdlib → 3rd party → local, use relative imports within modules
|
|
20
|
-
- **Naming**: snake_case functions/vars, PascalCase classes, UPPER_SNAKE constants, `_private` methods
|
|
21
|
-
- **Types**: Always use modern type hints (3.12+), async functions for I/O
|
|
22
|
-
- **Errors**: Use try/finally for cleanup
|
|
23
|
-
- **Docstrings**: Triple-quoted with Args/Returns sections
|
sqlsaber-0.31.0/sqlsaber.gif
DELETED
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|