databar 2.0.4__tar.gz → 2.0.6__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.
- {databar-2.0.4/src/databar.egg-info → databar-2.0.6}/PKG-INFO +1 -1
- {databar-2.0.4 → databar-2.0.6}/pyproject.toml +1 -1
- {databar-2.0.4 → databar-2.0.6}/src/databar/__init__.py +3 -1
- databar-2.0.6/src/databar/cli/_guide.py +137 -0
- databar-2.0.6/src/databar/cli/_onboard.py +289 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar/cli/app.py +16 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar/client.py +7 -4
- {databar-2.0.4 → databar-2.0.6}/src/databar/models.py +32 -0
- {databar-2.0.4 → databar-2.0.6/src/databar.egg-info}/PKG-INFO +1 -1
- {databar-2.0.4 → databar-2.0.6}/src/databar.egg-info/SOURCES.txt +2 -0
- {databar-2.0.4 → databar-2.0.6}/tests/test_cli.py +1 -1
- {databar-2.0.4 → databar-2.0.6}/LICENSE +0 -0
- {databar-2.0.4 → databar-2.0.6}/README.md +0 -0
- {databar-2.0.4 → databar-2.0.6}/setup.cfg +0 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar/cli/__init__.py +0 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar/cli/_auth.py +0 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar/cli/_output.py +0 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar/cli/enrichments.py +0 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar/cli/tables.py +0 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar/cli/tasks.py +0 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar/cli/waterfalls.py +0 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar/exceptions.py +0 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar.egg-info/dependency_links.txt +0 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar.egg-info/entry_points.txt +0 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar.egg-info/requires.txt +0 -0
- {databar-2.0.4 → databar-2.0.6}/src/databar.egg-info/top_level.txt +0 -0
- {databar-2.0.4 → databar-2.0.6}/tests/test_client.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "databar"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.6"
|
|
8
8
|
description = "Official Databar.ai Python SDK and CLI — connect to enrichments, waterfalls, and tables via api.databar.ai"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -45,6 +45,7 @@ from .models import (
|
|
|
45
45
|
EnrichmentSummary,
|
|
46
46
|
InsertOptions,
|
|
47
47
|
InsertRow,
|
|
48
|
+
RowsResponse,
|
|
48
49
|
RunResponse,
|
|
49
50
|
Table,
|
|
50
51
|
TableEnrichment,
|
|
@@ -57,7 +58,7 @@ from .models import (
|
|
|
57
58
|
WaterfallEnrichment,
|
|
58
59
|
)
|
|
59
60
|
|
|
60
|
-
__version__ = "2.0.
|
|
61
|
+
__version__ = "2.0.6"
|
|
61
62
|
__all__ = [
|
|
62
63
|
"DatabarClient",
|
|
63
64
|
# exceptions
|
|
@@ -87,6 +88,7 @@ __all__ = [
|
|
|
87
88
|
"Table",
|
|
88
89
|
"Column",
|
|
89
90
|
"TableEnrichment",
|
|
91
|
+
"RowsResponse",
|
|
90
92
|
"InsertRow",
|
|
91
93
|
"InsertOptions",
|
|
92
94
|
"DedupeOptions",
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""Embedded agent guide — printed by `databar agent-guide`."""
|
|
2
|
+
|
|
3
|
+
AGENT_GUIDE = r"""# Databar SDK & CLI — Agent Guide
|
|
4
|
+
|
|
5
|
+
Official Databar Python SDK and CLI (`pip install databar`).
|
|
6
|
+
Run data enrichments, waterfall lookups, and manage tables via api.databar.ai/v1.
|
|
7
|
+
|
|
8
|
+
## Setup
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install databar
|
|
12
|
+
export DATABAR_API_KEY=YOUR_API_KEY # or: databar login --api-key YOUR_API_KEY
|
|
13
|
+
databar whoami # verify auth
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
If `databar` command not found after install:
|
|
17
|
+
```bash
|
|
18
|
+
export PATH="$(python3 -m site --user-base)/bin:$PATH"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## CLI Quick Reference
|
|
22
|
+
|
|
23
|
+
All commands support `--format table|json|csv` (default: table) and `--help`.
|
|
24
|
+
**For machine-parseable output, always use `--format json`.**
|
|
25
|
+
|
|
26
|
+
### Enrichments
|
|
27
|
+
```
|
|
28
|
+
databar enrich list # list all enrichments
|
|
29
|
+
databar enrich list --query "linkedin" # search enrichments
|
|
30
|
+
databar enrich get <id> # get enrichment details (params, response fields)
|
|
31
|
+
databar enrich choices <id> <param> # list choices for a select param
|
|
32
|
+
databar enrich run <id> --params '{"key": "value"}' # run single
|
|
33
|
+
databar enrich bulk <id> --input data.csv --out results.csv
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Waterfalls
|
|
37
|
+
```
|
|
38
|
+
databar waterfall list
|
|
39
|
+
databar waterfall get <identifier> # e.g. email_getter
|
|
40
|
+
databar waterfall run <identifier> --params '{"key": "value"}'
|
|
41
|
+
databar waterfall bulk <identifier> --input data.csv --out results.csv
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Tables
|
|
45
|
+
```
|
|
46
|
+
databar table list
|
|
47
|
+
databar table create --name "My Table" --columns "email,name,company"
|
|
48
|
+
databar table columns <table-uuid>
|
|
49
|
+
databar table rows <table-uuid>
|
|
50
|
+
databar table rows <table-uuid> --format json
|
|
51
|
+
|
|
52
|
+
databar table insert <table-uuid> --data '[{"email":"a@b.com","name":"Alice"}]'
|
|
53
|
+
databar table insert <table-uuid> --input data.csv --allow-new-columns
|
|
54
|
+
|
|
55
|
+
databar table enrichments <table-uuid>
|
|
56
|
+
databar table add-enrichment <table-uuid> --enrichment-id <id> --mapping '{"param": "column_name"}'
|
|
57
|
+
databar table run-enrichment <table-uuid> --enrichment-id <TABLE-ENRICHMENT-ID>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Note: `run-enrichment` uses the TABLE-ENRICHMENT ID (from `add-enrichment` or `table enrichments`), NOT the catalog enrichment ID.
|
|
61
|
+
|
|
62
|
+
### Tasks
|
|
63
|
+
```
|
|
64
|
+
databar task get <task-id> # check status once
|
|
65
|
+
databar task get <task-id> --poll # poll until complete
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Account
|
|
69
|
+
```
|
|
70
|
+
databar whoami
|
|
71
|
+
databar whoami --format json
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Python SDK Quick Reference
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from databar import DatabarClient
|
|
78
|
+
|
|
79
|
+
client = DatabarClient() # reads DATABAR_API_KEY from env
|
|
80
|
+
|
|
81
|
+
# Enrichments
|
|
82
|
+
enrichments = client.list_enrichments(q="linkedin")
|
|
83
|
+
enrichment = client.get_enrichment(123)
|
|
84
|
+
# enrichment.params → list of EnrichmentParam (fields: .name, .is_required, .description)
|
|
85
|
+
# enrichment.response_fields → list of EnrichmentResponseField (fields: .name, .type_field)
|
|
86
|
+
|
|
87
|
+
result = client.run_enrichment_sync(123, {"email": "alice@example.com"})
|
|
88
|
+
|
|
89
|
+
# Waterfalls
|
|
90
|
+
waterfalls = client.list_waterfalls()
|
|
91
|
+
# waterfall.identifier → slug like "email_getter" (also available as .slug)
|
|
92
|
+
result = client.run_waterfall_sync("email_getter", {"linkedin_url": "..."})
|
|
93
|
+
|
|
94
|
+
# Tables
|
|
95
|
+
tables = client.list_tables()
|
|
96
|
+
# table.identifier → UUID (also available as .id and .uuid)
|
|
97
|
+
table = client.create_table(name="Leads", columns=["email", "name"])
|
|
98
|
+
resp = client.get_rows(table.identifier)
|
|
99
|
+
# resp.data → list of row dicts, resp.has_next_page, resp.total_count, resp.page
|
|
100
|
+
|
|
101
|
+
from databar import InsertRow
|
|
102
|
+
client.create_rows(table.identifier, [
|
|
103
|
+
InsertRow(fields={"email": "alice@example.com", "name": "Alice"}),
|
|
104
|
+
])
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Key Concepts
|
|
108
|
+
|
|
109
|
+
- All enrichment/waterfall runs are async: submit → get task_id → poll until completed.
|
|
110
|
+
The `*_sync` methods handle this automatically.
|
|
111
|
+
- task_id is the universal identifier for polling. Use it with poll_task() or `databar task get`.
|
|
112
|
+
- Results expire after 1 hour (status becomes "gone").
|
|
113
|
+
- Table enrichments are a two-step process: add_enrichment() then run_table_enrichment().
|
|
114
|
+
The ID from add_enrichment is a TABLE-ENRICHMENT ID, different from the catalog enrichment ID.
|
|
115
|
+
- The SDK auto-resolves column names to UUIDs in add_enrichment().
|
|
116
|
+
|
|
117
|
+
## Model Field Aliases
|
|
118
|
+
|
|
119
|
+
Common aliases that work on all models:
|
|
120
|
+
- Table: .id, .uuid → .identifier
|
|
121
|
+
- Waterfall: .slug → .identifier
|
|
122
|
+
- EnrichmentParam: .slug → .name, .label → .description, .required → .is_required
|
|
123
|
+
- EnrichmentResponseField: .slug → .name, .label → .name
|
|
124
|
+
|
|
125
|
+
## Error Handling
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from databar import (
|
|
129
|
+
DatabarAuthError, # 401/403
|
|
130
|
+
DatabarInsufficientCreditsError, # 406
|
|
131
|
+
DatabarNotFoundError, # 404
|
|
132
|
+
DatabarTaskFailedError, # task completed with error
|
|
133
|
+
DatabarTimeoutError, # polling timed out
|
|
134
|
+
DatabarGoneError, # task data expired (>1 hour)
|
|
135
|
+
)
|
|
136
|
+
```
|
|
137
|
+
"""
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`databar onboard` — interactive first-run setup wizard.
|
|
3
|
+
|
|
4
|
+
Guides the user through:
|
|
5
|
+
1. Displaying the Databar welcome banner
|
|
6
|
+
2. API key entry & verification
|
|
7
|
+
3. PATH detection & optional auto-fix
|
|
8
|
+
4. Usage preference (CLI / Python SDK / both)
|
|
9
|
+
5. Tailored next-steps cheatsheet
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
import shutil
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
import typer
|
|
20
|
+
from rich.console import Console
|
|
21
|
+
from rich.panel import Panel
|
|
22
|
+
from rich.prompt import Confirm, Prompt
|
|
23
|
+
from rich.rule import Rule
|
|
24
|
+
from rich.text import Text
|
|
25
|
+
|
|
26
|
+
console = Console()
|
|
27
|
+
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
# ASCII banner
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
BANNER = r"""
|
|
33
|
+
____ _ _
|
|
34
|
+
| _ \ __ _| |_ __ _| |__ __ _ _ __
|
|
35
|
+
| | | |/ _` | __/ _` | '_ \ / _` | '__|
|
|
36
|
+
| |_| | (_| | || (_| | |_) | (_| | |
|
|
37
|
+
|____/ \__,_|\__\__,_|_.__/ \__,_|_|
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
TAGLINE = "Data enrichment at your fingertips."
|
|
42
|
+
|
|
43
|
+
# ---------------------------------------------------------------------------
|
|
44
|
+
# Config helpers (mirrors _auth.py)
|
|
45
|
+
# ---------------------------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
CONFIG_DIR = Path.home() / ".databar"
|
|
48
|
+
CONFIG_FILE = CONFIG_DIR / "config"
|
|
49
|
+
_KEY_PREFIX = "api_key="
|
|
50
|
+
_PREF_PREFIX = "preferred_interface="
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _save_key(api_key: str) -> None:
|
|
54
|
+
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
55
|
+
lines: list[str] = []
|
|
56
|
+
if CONFIG_FILE.exists():
|
|
57
|
+
lines = [
|
|
58
|
+
l for l in CONFIG_FILE.read_text().splitlines()
|
|
59
|
+
if not l.startswith(_KEY_PREFIX)
|
|
60
|
+
]
|
|
61
|
+
lines.append(f"{_KEY_PREFIX}{api_key}")
|
|
62
|
+
CONFIG_FILE.write_text("\n".join(lines) + "\n")
|
|
63
|
+
CONFIG_FILE.chmod(0o600)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _save_preference(pref: str) -> None:
|
|
67
|
+
lines: list[str] = []
|
|
68
|
+
if CONFIG_FILE.exists():
|
|
69
|
+
lines = [
|
|
70
|
+
l for l in CONFIG_FILE.read_text().splitlines()
|
|
71
|
+
if not l.startswith(_PREF_PREFIX)
|
|
72
|
+
]
|
|
73
|
+
lines.append(f"{_PREF_PREFIX}{pref}")
|
|
74
|
+
CONFIG_FILE.write_text("\n".join(lines) + "\n")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _get_bin_dir() -> Path:
|
|
78
|
+
return Path(sys.executable).parent
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _databar_on_path() -> bool:
|
|
82
|
+
return shutil.which("databar") is not None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _detect_shell_profile() -> Path | None:
|
|
86
|
+
shell = os.environ.get("SHELL", "")
|
|
87
|
+
home = Path.home()
|
|
88
|
+
if "zsh" in shell:
|
|
89
|
+
return home / ".zshrc"
|
|
90
|
+
if "bash" in shell:
|
|
91
|
+
profile = home / ".bash_profile"
|
|
92
|
+
return profile if profile.exists() else home / ".bashrc"
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _add_to_path(bin_dir: Path) -> bool:
|
|
97
|
+
"""Append export PATH line to the detected shell profile. Returns True on success."""
|
|
98
|
+
profile = _detect_shell_profile()
|
|
99
|
+
if profile is None:
|
|
100
|
+
return False
|
|
101
|
+
export_line = f'\nexport PATH="{bin_dir}:$PATH" # added by databar onboard\n'
|
|
102
|
+
with open(profile, "a") as f:
|
|
103
|
+
f.write(export_line)
|
|
104
|
+
return True
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# ---------------------------------------------------------------------------
|
|
108
|
+
# Onboard steps
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
def _print_banner() -> None:
|
|
112
|
+
banner_text = Text(BANNER, style="bold cyan")
|
|
113
|
+
tagline_text = Text(f" {TAGLINE}\n", style="dim")
|
|
114
|
+
console.print(banner_text, end="")
|
|
115
|
+
console.print(tagline_text)
|
|
116
|
+
console.print(Rule(style="cyan"))
|
|
117
|
+
console.print()
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _step_api_key() -> str | None:
|
|
121
|
+
"""Prompt for API key, save it, and verify with a whoami call."""
|
|
122
|
+
console.print("[bold]Step 1 — Connect your account[/bold]")
|
|
123
|
+
console.print(
|
|
124
|
+
"[dim]Get your API key at [link=https://databar.ai]databar.ai[/link] "
|
|
125
|
+
"→ Settings → API Keys[/dim]\n"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
existing_key: str | None = None
|
|
129
|
+
if CONFIG_FILE.exists():
|
|
130
|
+
for line in CONFIG_FILE.read_text().splitlines():
|
|
131
|
+
if line.startswith(_KEY_PREFIX):
|
|
132
|
+
existing_key = line[len(_KEY_PREFIX):].strip()
|
|
133
|
+
break
|
|
134
|
+
if not existing_key:
|
|
135
|
+
existing_key = os.environ.get("DATABAR_API_KEY", "").strip() or None
|
|
136
|
+
|
|
137
|
+
if existing_key:
|
|
138
|
+
masked = existing_key[:6] + "•" * (len(existing_key) - 10) + existing_key[-4:]
|
|
139
|
+
use_existing = Confirm.ask(
|
|
140
|
+
f" Found existing key [bold]{masked}[/bold] — use it?",
|
|
141
|
+
default=True,
|
|
142
|
+
)
|
|
143
|
+
if use_existing:
|
|
144
|
+
api_key = existing_key
|
|
145
|
+
else:
|
|
146
|
+
api_key = Prompt.ask(" Enter your Databar API key", password=True).strip()
|
|
147
|
+
else:
|
|
148
|
+
api_key = Prompt.ask(" Enter your Databar API key", password=True).strip()
|
|
149
|
+
|
|
150
|
+
if not api_key:
|
|
151
|
+
console.print("[yellow] Skipped — you can run `databar login` later.[/yellow]\n")
|
|
152
|
+
return None
|
|
153
|
+
|
|
154
|
+
console.print(" [dim]Verifying…[/dim]", end="")
|
|
155
|
+
try:
|
|
156
|
+
from databar.client import DatabarClient
|
|
157
|
+
client = DatabarClient(api_key=api_key)
|
|
158
|
+
user = client.get_user()
|
|
159
|
+
client.close()
|
|
160
|
+
_save_key(api_key)
|
|
161
|
+
console.print(
|
|
162
|
+
f"\r [bold green]✓[/bold green] Authenticated as "
|
|
163
|
+
f"[bold]{user.first_name or user.email}[/bold] "
|
|
164
|
+
f"([dim]{user.balance:.0f} credits[/dim])\n"
|
|
165
|
+
)
|
|
166
|
+
return api_key
|
|
167
|
+
except Exception as e:
|
|
168
|
+
console.print(f"\r [bold red]✗[/bold red] Could not verify key: {e}\n")
|
|
169
|
+
console.print(" [dim]Key not saved. Run `databar login` to try again.[/dim]\n")
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _step_path() -> None:
|
|
174
|
+
"""Check PATH and offer to fix it."""
|
|
175
|
+
console.print("[bold]Step 2 — Fix PATH (so `databar` works anywhere)[/bold]")
|
|
176
|
+
|
|
177
|
+
if _databar_on_path():
|
|
178
|
+
console.print(" [bold green]✓[/bold green] `databar` is already on your PATH.\n")
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
bin_dir = _get_bin_dir()
|
|
182
|
+
console.print(
|
|
183
|
+
f" [yellow]![/yellow] `databar` is not on PATH.\n"
|
|
184
|
+
f" It's installed at: [bold]{bin_dir}/databar[/bold]\n"
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
profile = _detect_shell_profile()
|
|
188
|
+
profile_label = str(profile) if profile else "your shell profile"
|
|
189
|
+
fix = Confirm.ask(
|
|
190
|
+
f" Add `{bin_dir}` to PATH in {profile_label} automatically?",
|
|
191
|
+
default=True,
|
|
192
|
+
)
|
|
193
|
+
if fix:
|
|
194
|
+
ok = _add_to_path(bin_dir)
|
|
195
|
+
if ok:
|
|
196
|
+
console.print(
|
|
197
|
+
f" [bold green]✓[/bold green] Added to {profile_label}.\n"
|
|
198
|
+
f" Run [bold]source {profile_label}[/bold] or open a new terminal to apply.\n"
|
|
199
|
+
)
|
|
200
|
+
else:
|
|
201
|
+
console.print(
|
|
202
|
+
f" [yellow]Could not detect your shell profile.[/yellow]\n"
|
|
203
|
+
f" Add this manually:\n\n"
|
|
204
|
+
f" [bold]export PATH=\"{bin_dir}:$PATH\"[/bold]\n"
|
|
205
|
+
)
|
|
206
|
+
else:
|
|
207
|
+
console.print(
|
|
208
|
+
f" [dim]Skipped. Use the full path for now: [bold]{bin_dir}/databar[/bold][/dim]\n"
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _step_preference() -> str:
|
|
213
|
+
"""Ask how the user plans to use Databar and return their choice."""
|
|
214
|
+
console.print("[bold]Step 3 — How do you plan to use Databar?[/bold]\n")
|
|
215
|
+
console.print(" [bold cyan]1[/bold cyan] CLI — terminal commands, scripts, AI agents (Claude Code etc.)")
|
|
216
|
+
console.print(" [bold cyan]2[/bold cyan] Python — import DatabarClient in your Python code")
|
|
217
|
+
console.print(" [bold cyan]3[/bold cyan] Both — I'll use whichever fits the task\n")
|
|
218
|
+
|
|
219
|
+
choice = Prompt.ask(" Your choice", choices=["1", "2", "3"], default="3")
|
|
220
|
+
pref_map = {"1": "cli", "2": "python", "3": "both"}
|
|
221
|
+
pref = pref_map[choice]
|
|
222
|
+
_save_preference(pref)
|
|
223
|
+
console.print()
|
|
224
|
+
return pref
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _step_next_steps(pref: str) -> None:
|
|
228
|
+
"""Print tailored next steps based on preference."""
|
|
229
|
+
console.print(Rule(style="cyan"))
|
|
230
|
+
console.print()
|
|
231
|
+
console.print("[bold green]You're all set![/bold green] Here's where to start:\n")
|
|
232
|
+
|
|
233
|
+
if pref in ("cli", "both"):
|
|
234
|
+
console.print(Panel(
|
|
235
|
+
"[bold]CLI Quick Start[/bold]\n\n"
|
|
236
|
+
" databar enrich list [dim]# browse enrichments[/dim]\n"
|
|
237
|
+
" databar enrich get <id> [dim]# inspect params[/dim]\n"
|
|
238
|
+
" databar enrich run <id> --params '{...}' [dim]# run one row[/dim]\n"
|
|
239
|
+
" databar enrich bulk <id> --input data.csv [dim]# bulk from CSV[/dim]\n\n"
|
|
240
|
+
" databar waterfall list\n"
|
|
241
|
+
" databar waterfall run <identifier> --params '{...}'\n\n"
|
|
242
|
+
" databar table create --name 'Leads' --columns 'email,name'\n"
|
|
243
|
+
" databar table rows <uuid> --format json\n\n"
|
|
244
|
+
" [dim]Tip: always use --format json when piping output.[/dim]",
|
|
245
|
+
border_style="cyan",
|
|
246
|
+
title="[cyan]CLI[/cyan]",
|
|
247
|
+
))
|
|
248
|
+
|
|
249
|
+
if pref in ("python", "both"):
|
|
250
|
+
console.print(Panel(
|
|
251
|
+
"[bold]Python SDK Quick Start[/bold]\n\n"
|
|
252
|
+
" from databar import DatabarClient\n\n"
|
|
253
|
+
" client = DatabarClient() [dim]# reads DATABAR_API_KEY from env or ~/.databar/config[/dim]\n\n"
|
|
254
|
+
" enrichments = client.list_enrichments(q='email')\n"
|
|
255
|
+
" result = client.run_enrichment_sync(123, {'email': 'alice@example.com'})\n\n"
|
|
256
|
+
" tables = client.list_tables()\n"
|
|
257
|
+
" rows = client.get_rows(table.identifier) [dim]# returns RowsResponse[/dim]\n"
|
|
258
|
+
" rows.data [dim]# list of row dicts[/dim]",
|
|
259
|
+
border_style="cyan",
|
|
260
|
+
title="[cyan]Python[/cyan]",
|
|
261
|
+
))
|
|
262
|
+
|
|
263
|
+
console.print(
|
|
264
|
+
"\n [dim]Full reference: [bold]databar agent-guide[/bold] | "
|
|
265
|
+
"Docs: [link=https://build.databar.ai]build.databar.ai[/link][/dim]\n"
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
# ---------------------------------------------------------------------------
|
|
270
|
+
# Command entry point
|
|
271
|
+
# ---------------------------------------------------------------------------
|
|
272
|
+
|
|
273
|
+
def onboard() -> None:
|
|
274
|
+
"""Interactive setup wizard — configure auth, PATH, and get started."""
|
|
275
|
+
_print_banner()
|
|
276
|
+
console.print(
|
|
277
|
+
" Welcome to [bold cyan]Databar[/bold cyan]! This wizard takes ~1 minute "
|
|
278
|
+
"and sets up everything you need.\n"
|
|
279
|
+
" [dim]Press Ctrl+C at any time to exit.[/dim]\n"
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
try:
|
|
283
|
+
_step_api_key()
|
|
284
|
+
_step_path()
|
|
285
|
+
pref = _step_preference()
|
|
286
|
+
_step_next_steps(pref)
|
|
287
|
+
except (KeyboardInterrupt, typer.Abort):
|
|
288
|
+
console.print("\n\n[dim]Onboarding cancelled. Run `databar onboard` any time to restart.[/dim]")
|
|
289
|
+
raise typer.Exit(0)
|
|
@@ -30,6 +30,22 @@ app.add_typer(tables.app, name="table")
|
|
|
30
30
|
app.add_typer(tasks.app, name="task")
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
@app.command("onboard")
|
|
34
|
+
def onboard() -> None:
|
|
35
|
+
"""Interactive setup wizard — configure auth, PATH, and get started."""
|
|
36
|
+
from ._onboard import onboard as _run_onboard
|
|
37
|
+
|
|
38
|
+
_run_onboard()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@app.command("agent-guide")
|
|
42
|
+
def agent_guide() -> None:
|
|
43
|
+
"""Print the full agent usage guide (SDK + CLI reference for AI agents)."""
|
|
44
|
+
from ._guide import AGENT_GUIDE
|
|
45
|
+
|
|
46
|
+
typer.echo(AGENT_GUIDE)
|
|
47
|
+
|
|
48
|
+
|
|
33
49
|
def _version_callback(value: bool) -> None:
|
|
34
50
|
if value:
|
|
35
51
|
typer.echo(f"databar {__version__}")
|
|
@@ -43,6 +43,7 @@ from .models import (
|
|
|
43
43
|
EnrichmentSummary,
|
|
44
44
|
InsertOptions,
|
|
45
45
|
InsertRow,
|
|
46
|
+
RowsResponse,
|
|
46
47
|
RunResponse,
|
|
47
48
|
Table,
|
|
48
49
|
TableEnrichment,
|
|
@@ -522,20 +523,22 @@ class DatabarClient:
|
|
|
522
523
|
table_uuid: str,
|
|
523
524
|
page: int = 1,
|
|
524
525
|
per_page: int = 100,
|
|
525
|
-
) ->
|
|
526
|
+
) -> RowsResponse:
|
|
526
527
|
"""
|
|
527
528
|
Get rows from a table with pagination.
|
|
528
529
|
|
|
529
|
-
Returns a
|
|
530
|
-
|
|
530
|
+
Returns a :class:`RowsResponse` with ``.data`` (list of row dicts),
|
|
531
|
+
``.has_next_page``, ``.total_count``, ``.page``.
|
|
532
|
+
Each row dict is keyed by column name and includes an ``id`` key.
|
|
531
533
|
|
|
532
534
|
``per_page`` max is 500 (API limit). Default is 100.
|
|
533
535
|
"""
|
|
534
|
-
|
|
536
|
+
data = self._request(
|
|
535
537
|
"GET",
|
|
536
538
|
f"/table/{table_uuid}/rows",
|
|
537
539
|
params={"page": page, "per_page": per_page},
|
|
538
540
|
)
|
|
541
|
+
return RowsResponse.model_validate(data)
|
|
539
542
|
|
|
540
543
|
def create_rows(
|
|
541
544
|
self,
|
|
@@ -297,6 +297,38 @@ class TableEnrichment(BaseModel):
|
|
|
297
297
|
name: str
|
|
298
298
|
|
|
299
299
|
|
|
300
|
+
# ===========================================================================
|
|
301
|
+
# Rows — Query
|
|
302
|
+
# ===========================================================================
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class RowsResponse(BaseModel):
|
|
306
|
+
"""Paginated rows returned by get_rows().
|
|
307
|
+
|
|
308
|
+
Fields: data, has_next_page, total_count, page.
|
|
309
|
+
|
|
310
|
+
Property alias: .rows → .data.
|
|
311
|
+
|
|
312
|
+
Usage::
|
|
313
|
+
|
|
314
|
+
resp = client.get_rows(table.identifier)
|
|
315
|
+
for row in resp.data:
|
|
316
|
+
print(row["email"])
|
|
317
|
+
if resp.has_next_page:
|
|
318
|
+
resp2 = client.get_rows(table.identifier, page=2)
|
|
319
|
+
"""
|
|
320
|
+
|
|
321
|
+
data: List[Dict[str, Any]] = Field(description="List of row dicts keyed by column name. Each row also has an 'id' key with the row UUID.")
|
|
322
|
+
has_next_page: bool = Field(default=False)
|
|
323
|
+
total_count: int = Field(default=0)
|
|
324
|
+
page: int = Field(default=1)
|
|
325
|
+
|
|
326
|
+
@property
|
|
327
|
+
def rows(self) -> List[Dict[str, Any]]:
|
|
328
|
+
"""Alias for data."""
|
|
329
|
+
return self.data
|
|
330
|
+
|
|
331
|
+
|
|
300
332
|
# ===========================================================================
|
|
301
333
|
# Rows — Insert
|
|
302
334
|
# ===========================================================================
|
|
@@ -13,6 +13,8 @@ src/databar.egg-info/requires.txt
|
|
|
13
13
|
src/databar.egg-info/top_level.txt
|
|
14
14
|
src/databar/cli/__init__.py
|
|
15
15
|
src/databar/cli/_auth.py
|
|
16
|
+
src/databar/cli/_guide.py
|
|
17
|
+
src/databar/cli/_onboard.py
|
|
16
18
|
src/databar/cli/_output.py
|
|
17
19
|
src/databar/cli/app.py
|
|
18
20
|
src/databar/cli/enrichments.py
|
|
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
|