talktodb-api-connector 0.1.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.
@@ -0,0 +1,38 @@
1
+ # Build talktodb-api-connector and upload wheel + sdist to PyPI.
2
+ name: Publish talktodb-api-connector
3
+
4
+ on:
5
+ push:
6
+ # branches:
7
+ # - main
8
+ # - master
9
+ tags:
10
+ - "v*"
11
+ workflow_dispatch:
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ build-and-publish:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - name: Checkout
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v5
25
+
26
+ - name: Set up Python
27
+ uses: actions/setup-python@v5
28
+ with:
29
+ python-version: "3.12"
30
+
31
+ - name: Build distributions
32
+ run: uv build
33
+
34
+ - name: Publish to PyPI
35
+ uses: pypa/gh-action-pypi-publish@release/v1
36
+ with:
37
+ password: ${{ secrets.PYPI_API_TOKEN }}
38
+ packages-dir: dist
@@ -0,0 +1,20 @@
1
+ # Build outputs
2
+ dist/
3
+ build/
4
+ *.egg-info/
5
+
6
+ # Bytecode
7
+ __pycache__/
8
+ *.py[cod]
9
+ *$py.class
10
+
11
+ # Local virtual environments
12
+ .venv/
13
+ venv/
14
+ git-personal-config.sh
15
+ # Test / coverage caches (local only)
16
+ .pytest_cache/
17
+ .coverage
18
+ .coverage.*
19
+ htmlcov/
20
+ .ruff_cache/
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.5
2
+ Name: talktodb-api-connector
3
+ Version: 0.1.0
4
+ Summary: FastAPI app: configurable SQL backend, read-only mode, access controls
5
+ Author-email: Biman Kumar Das <daskumarbiman2020@gmail.com>
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: asyncpg>=0.32.0
8
+ Requires-Dist: fastapi>=0.141.1
9
+ Requires-Dist: pydantic>=2.13.4
10
+ Requires-Dist: sqlalchemy[asyncio]>=2.0
11
+ Requires-Dist: typer>=0.28.0
12
+ Requires-Dist: uvicorn>=0.52.4
13
+ Description-Content-Type: text/markdown
14
+
15
+ # talktodb-api-connector
16
+
17
+ Runs a small HTTP API on your machine that reads database settings from a local config file and executes SQL you send it. A command-line tool creates and edits that config, starts or stops the API, and on Windows can register the API as a system service. Nothing in the package ships your data off the machine except SQL you choose to run against your own database.
18
+
19
+ ## Install
20
+
21
+ Install from PyPI with ```pip install talktodb-api-connector```. The talktodb command is added to your PATH.
22
+
23
+ ## Commands
24
+
25
+ | Command | Description |
26
+ |---------|-------------|
27
+ | talktodb config set | Set one setting using a dotted name and a value (for example database.host and localhost). |
28
+ | talktodb config ls | Show the current config as JSON; the database password is never printed. |
29
+ | talktodb api start | Check config and database driver, print the config, then start the API in a background process and remember its process id. |
30
+ | talktodb api stop | Stop the API using the saved process id. |
31
+ | talktodb service install | Windows only. Register the API as a Windows service using WinSW; the service is not started automatically. |
32
+ | talktodb service remove | Windows only. Unregister that service and remove the WinSW service definition file. |
33
+
34
+ ### Manual run vs Windows service
35
+
36
+ - **talktodb api start** — Run the API yourself as a background process in your user session.
37
+ - **talktodb service install** — Register the same API with Windows so it can start at boot or from Services; each time the service starts, it reads the config file again from disk.
38
+
39
+ ## Configuration
40
+
41
+ Settings live in a JSON file in your home directory named .talktodb.config. Use talktodb config set with paths such as server.port or database.host. talktodb config ls shows everything except the database password.
42
+
43
+ ### Server (HTTP API)
44
+
45
+ - **server.port** — TCP port the API listens on (default 2026).
46
+ - **server.allowed_origins** — Browser Origin values allowed for cross-origin requests (CORS); default empty list. An empty list means browsers on other sites cannot call the API.
47
+
48
+ The API always binds to 127.0.0.1 on your machine. That address is not stored in the config file.
49
+
50
+ ### Database
51
+
52
+ - **database.dialect** — Database kind and async driver (see supported values below); default postgresql.
53
+ - **database.host** — Database server hostname or IP; default 127.0.0.1.
54
+ - **database.port** — Database server port; default 5432.
55
+ - **database.username** — Login user name; default empty.
56
+ - **database.password** — Login password; default empty.
57
+ - **database.database** — Database name to connect to; default empty.
58
+ - **database.read_only** — When true, only read-style SQL (SELECT and similar) is allowed; writes are rejected before they run; default false.
59
+
60
+ #### Supported dialect values
61
+
62
+ The CLI maps these names to async SQLAlchemy drivers:
63
+
64
+ - postgresql or postgres
65
+ - mysql or mariadb
66
+ - sqlite
67
+ - mssql or sqlserver
68
+ - oracle
69
+
70
+ You may also set dialect to a full driver string that already includes a plus sign (for example postgresql+asyncpg). Install the matching Python driver package (such as asyncpg for PostgreSQL) before starting the API.
71
+
72
+ ### Example Commands
73
+ ```bash
74
+ talktodb config set database.dialect postgresql
75
+ talktodb config set database.host localhost
76
+ talktodb config set database.port 5432
77
+ talktodb config set database.username <csv_user>
78
+ talktodb config set database.password <password>
79
+ talktodb config set database.database talktodb
80
+ talktodb config set database.read_only false
81
+ talktodb config set server.port 2026
82
+ talktodb config set server.allowed_origins []
83
+ ```
@@ -0,0 +1,69 @@
1
+ # talktodb-api-connector
2
+
3
+ Runs a small HTTP API on your machine that reads database settings from a local config file and executes SQL you send it. A command-line tool creates and edits that config, starts or stops the API, and on Windows can register the API as a system service. Nothing in the package ships your data off the machine except SQL you choose to run against your own database.
4
+
5
+ ## Install
6
+
7
+ Install from PyPI with ```pip install talktodb-api-connector```. The talktodb command is added to your PATH.
8
+
9
+ ## Commands
10
+
11
+ | Command | Description |
12
+ |---------|-------------|
13
+ | talktodb config set | Set one setting using a dotted name and a value (for example database.host and localhost). |
14
+ | talktodb config ls | Show the current config as JSON; the database password is never printed. |
15
+ | talktodb api start | Check config and database driver, print the config, then start the API in a background process and remember its process id. |
16
+ | talktodb api stop | Stop the API using the saved process id. |
17
+ | talktodb service install | Windows only. Register the API as a Windows service using WinSW; the service is not started automatically. |
18
+ | talktodb service remove | Windows only. Unregister that service and remove the WinSW service definition file. |
19
+
20
+ ### Manual run vs Windows service
21
+
22
+ - **talktodb api start** — Run the API yourself as a background process in your user session.
23
+ - **talktodb service install** — Register the same API with Windows so it can start at boot or from Services; each time the service starts, it reads the config file again from disk.
24
+
25
+ ## Configuration
26
+
27
+ Settings live in a JSON file in your home directory named .talktodb.config. Use talktodb config set with paths such as server.port or database.host. talktodb config ls shows everything except the database password.
28
+
29
+ ### Server (HTTP API)
30
+
31
+ - **server.port** — TCP port the API listens on (default 2026).
32
+ - **server.allowed_origins** — Browser Origin values allowed for cross-origin requests (CORS); default empty list. An empty list means browsers on other sites cannot call the API.
33
+
34
+ The API always binds to 127.0.0.1 on your machine. That address is not stored in the config file.
35
+
36
+ ### Database
37
+
38
+ - **database.dialect** — Database kind and async driver (see supported values below); default postgresql.
39
+ - **database.host** — Database server hostname or IP; default 127.0.0.1.
40
+ - **database.port** — Database server port; default 5432.
41
+ - **database.username** — Login user name; default empty.
42
+ - **database.password** — Login password; default empty.
43
+ - **database.database** — Database name to connect to; default empty.
44
+ - **database.read_only** — When true, only read-style SQL (SELECT and similar) is allowed; writes are rejected before they run; default false.
45
+
46
+ #### Supported dialect values
47
+
48
+ The CLI maps these names to async SQLAlchemy drivers:
49
+
50
+ - postgresql or postgres
51
+ - mysql or mariadb
52
+ - sqlite
53
+ - mssql or sqlserver
54
+ - oracle
55
+
56
+ You may also set dialect to a full driver string that already includes a plus sign (for example postgresql+asyncpg). Install the matching Python driver package (such as asyncpg for PostgreSQL) before starting the API.
57
+
58
+ ### Example Commands
59
+ ```bash
60
+ talktodb config set database.dialect postgresql
61
+ talktodb config set database.host localhost
62
+ talktodb config set database.port 5432
63
+ talktodb config set database.username <csv_user>
64
+ talktodb config set database.password <password>
65
+ talktodb config set database.database talktodb
66
+ talktodb config set database.read_only false
67
+ talktodb config set server.port 2026
68
+ talktodb config set server.allowed_origins []
69
+ ```
@@ -0,0 +1,27 @@
1
+ [project]
2
+ name = "talktodb-api-connector"
3
+ version = "0.1.0"
4
+ description = "FastAPI app: configurable SQL backend, read-only mode, access controls"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Biman Kumar Das", email = "daskumarbiman2020@gmail.com" }
8
+ ]
9
+ requires-python = ">=3.12"
10
+ dependencies = [
11
+ "asyncpg>=0.32.0",
12
+ "fastapi>=0.141.1",
13
+ "pydantic>=2.13.4",
14
+ "sqlalchemy[asyncio]>=2.0",
15
+ "typer>=0.28.0",
16
+ "uvicorn>=0.52.4",
17
+ ]
18
+
19
+ [project.scripts]
20
+ talktodb = "talktodb_api_connector.cli.main:main"
21
+
22
+ [build-system]
23
+ requires = ["hatchling"]
24
+ build-backend = "hatchling.build"
25
+
26
+ [tool.hatch.build.targets.wheel]
27
+ packages = ["src/talktodb_api_connector"]
@@ -0,0 +1,5 @@
1
+ """talktodb-api-connector: configurable SQL API (skeleton)."""
2
+
3
+ from talktodb_api_connector.api.main import app
4
+
5
+ __all__ = ["app"]
@@ -0,0 +1,5 @@
1
+ """HTTP API: FastAPI app, routes, and request/response schemas."""
2
+
3
+ from talktodb_api_connector.api.main import app
4
+
5
+ __all__ = ["app"]
@@ -0,0 +1,72 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import sys
5
+ from contextlib import asynccontextmanager
6
+
7
+ from fastapi import FastAPI, Request
8
+ from starlette.middleware.cors import CORSMiddleware
9
+
10
+ from talktodb_api_connector.api.routes import router as api_router
11
+ from talktodb_api_connector.config import load_settings
12
+ from talktodb_api_connector.database_registry import DatabaseConnectionRegistry
13
+
14
+
15
+ def _ensure_app_logging() -> None:
16
+ """Configure root logging to stderr when nothing else (e.g. uvicorn) configured it."""
17
+ root = logging.getLogger()
18
+ if root.handlers:
19
+ return
20
+ logging.basicConfig(
21
+ level=logging.INFO,
22
+ format="%(asctime)s %(levelname)s %(name)s: %(message)s",
23
+ stream=sys.stderr,
24
+ )
25
+
26
+
27
+ @asynccontextmanager
28
+ async def lifespan(app: FastAPI):
29
+ _ensure_app_logging()
30
+ settings = load_settings()
31
+ app.state.settings = settings
32
+ DatabaseConnectionRegistry.initialize(settings)
33
+ # CORS ingress: only attach middleware when origins are configured. With an
34
+ # empty allowlist we skip CORSMiddleware so browsers receive no
35
+ # Access-Control-Allow-Origin for cross-origin requests (same-origin still works).
36
+ if settings.server.allowed_origins:
37
+ app.add_middleware(
38
+ CORSMiddleware,
39
+ allow_origins=list(settings.server.allowed_origins),
40
+ allow_credentials=True,
41
+ allow_methods=["*"],
42
+ allow_headers=["*"],
43
+ )
44
+ yield
45
+ await DatabaseConnectionRegistry.close()
46
+
47
+
48
+ app = FastAPI(title="talktodb-api-connector", lifespan=lifespan)
49
+ app.include_router(api_router)
50
+
51
+
52
+ @app.get("/")
53
+ def root(request: Request) -> dict[str, str]:
54
+ """Health-style root endpoint."""
55
+ settings = request.app.state.settings
56
+ if settings.server.allowed_origins:
57
+ cors_note = (
58
+ f"CORS enabled for {len(settings.server.allowed_origins)} browser origin(s) "
59
+ "(not database access control)"
60
+ )
61
+ else:
62
+ cors_note = (
63
+ "CORS off (allowed_origins empty; no CORSMiddleware — "
64
+ "cross-origin browser requests blocked)"
65
+ )
66
+ return {
67
+ "status": "ok",
68
+ "message": "talktodb-api-connector",
69
+ "bind_host": "127.0.0.1",
70
+ "settings": ("loaded from ~/.talktodb.config (JSON only)"),
71
+ "cors": cors_note,
72
+ }
@@ -0,0 +1,48 @@
1
+ """HTTP routes for talktodb-api-connector."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Annotated
6
+
7
+ from fastapi import APIRouter, Depends, Request
8
+
9
+ from talktodb_api_connector.api.schemas import (
10
+ RunDbQueryOutput,
11
+ RunDbQueryRequest,
12
+ SettingsPublic,
13
+ )
14
+ from talktodb_api_connector.service import QueryService
15
+ from talktodb_api_connector.unit_of_work import UnitOfWork
16
+
17
+ router = APIRouter()
18
+
19
+
20
+ async def get_unit_of_work():
21
+ """Request-scoped unit of work: session + repository; closes on exit."""
22
+ async with UnitOfWork() as uow:
23
+ yield uow
24
+
25
+
26
+ def get_query_service(
27
+ request: Request,
28
+ uow: Annotated[UnitOfWork, Depends(get_unit_of_work)],
29
+ ) -> QueryService:
30
+ """Build :class:`QueryService` from app settings and the request-scoped unit of work."""
31
+ return QueryService(uow, request.app.state.settings)
32
+
33
+
34
+ @router.get("/settings", response_model=SettingsPublic)
35
+ async def get_settings(request: Request) -> SettingsPublic:
36
+ """Return loaded application settings without the database password."""
37
+ return SettingsPublic.model_validate(
38
+ request.app.state.settings.model_dump(exclude={"database": {"password": True}})
39
+ )
40
+
41
+
42
+ @router.post("/query", response_model=RunDbQueryOutput)
43
+ async def post_query(
44
+ body: RunDbQueryRequest,
45
+ service: Annotated[QueryService, Depends(get_query_service)],
46
+ ) -> RunDbQueryOutput:
47
+ """Execute SQL; delegates to :class:`QueryService`."""
48
+ return await service.run_query(body.sql, body.params)
@@ -0,0 +1,77 @@
1
+ """API response models aligned with the agent server tool contracts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel, ConfigDict, Field
8
+
9
+
10
+ class ServerConfigPublic(BaseModel):
11
+ """Server subsection returned by ``GET /settings``."""
12
+
13
+ model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
14
+
15
+ port: int = Field(default=2026, description="HTTP API bind port (uvicorn; default 2026).")
16
+ allowed_origins: list[str] = Field(
17
+ default_factory=list,
18
+ description="CORS allowlisted browser origins.",
19
+ )
20
+
21
+
22
+ class DatabaseConfigPublic(BaseModel):
23
+ """Database subsection returned by ``GET /settings`` (password never included)."""
24
+
25
+ model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
26
+
27
+ dialect: str
28
+ host: str = Field(default="127.0.0.1", description="Database server hostname (SQLAlchemy URL).")
29
+ port: int = Field(default=5432, description="Database server port (SQLAlchemy URL).")
30
+ username: str
31
+ database: str
32
+ read_only: bool = Field(default=False, description="When true, only read-style SQL is allowed.")
33
+
34
+
35
+ class SettingsPublic(BaseModel):
36
+ """Configuration returned by ``GET /settings`` (nested shape; database password omitted)."""
37
+
38
+ model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
39
+
40
+ server: ServerConfigPublic
41
+ database: DatabaseConfigPublic
42
+
43
+
44
+ class RunDbQueryRequest(BaseModel):
45
+ """Body for ``POST /query`` — raw SQL and optional bind parameters."""
46
+
47
+ model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
48
+
49
+ sql: str = Field(..., description="SQL statement to execute.")
50
+ params: dict[str, Any] | None = Field(
51
+ default=None,
52
+ description="Optional named parameters for bound placeholders in ``sql``.",
53
+ )
54
+
55
+
56
+ class RunDbQueryOutput(BaseModel):
57
+ """Structured result for ``run_db_query``-style tooling (matches agent_server shape)."""
58
+
59
+ model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
60
+
61
+ success: bool = Field(..., description="Whether the query completed successfully.")
62
+ error: str | None = Field(
63
+ default=None,
64
+ description="Error message when ``success`` is false.",
65
+ )
66
+ columns: list[str] | None = Field(
67
+ default=None,
68
+ description="Column names in order for row-returning queries.",
69
+ )
70
+ rows: list[list[Any]] | None = Field(
71
+ default=None,
72
+ description="Row values aligned with ``columns`` (list of lists).",
73
+ )
74
+ row_count: int | None = Field(
75
+ default=None,
76
+ description="Number of rows returned or affected, depending on query type.",
77
+ )
@@ -0,0 +1 @@
1
+ """Command-line interface for talktodb-api-connector."""