databar 2.0.5__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.
Files changed (27) hide show
  1. {databar-2.0.5/src/databar.egg-info → databar-2.0.6}/PKG-INFO +1 -1
  2. {databar-2.0.5 → databar-2.0.6}/pyproject.toml +1 -1
  3. {databar-2.0.5 → databar-2.0.6}/src/databar/__init__.py +1 -1
  4. databar-2.0.6/src/databar/cli/_onboard.py +289 -0
  5. {databar-2.0.5 → databar-2.0.6}/src/databar/cli/app.py +8 -0
  6. {databar-2.0.5 → databar-2.0.6/src/databar.egg-info}/PKG-INFO +1 -1
  7. {databar-2.0.5 → databar-2.0.6}/src/databar.egg-info/SOURCES.txt +1 -0
  8. {databar-2.0.5 → databar-2.0.6}/tests/test_cli.py +1 -1
  9. {databar-2.0.5 → databar-2.0.6}/LICENSE +0 -0
  10. {databar-2.0.5 → databar-2.0.6}/README.md +0 -0
  11. {databar-2.0.5 → databar-2.0.6}/setup.cfg +0 -0
  12. {databar-2.0.5 → databar-2.0.6}/src/databar/cli/__init__.py +0 -0
  13. {databar-2.0.5 → databar-2.0.6}/src/databar/cli/_auth.py +0 -0
  14. {databar-2.0.5 → databar-2.0.6}/src/databar/cli/_guide.py +0 -0
  15. {databar-2.0.5 → databar-2.0.6}/src/databar/cli/_output.py +0 -0
  16. {databar-2.0.5 → databar-2.0.6}/src/databar/cli/enrichments.py +0 -0
  17. {databar-2.0.5 → databar-2.0.6}/src/databar/cli/tables.py +0 -0
  18. {databar-2.0.5 → databar-2.0.6}/src/databar/cli/tasks.py +0 -0
  19. {databar-2.0.5 → databar-2.0.6}/src/databar/cli/waterfalls.py +0 -0
  20. {databar-2.0.5 → databar-2.0.6}/src/databar/client.py +0 -0
  21. {databar-2.0.5 → databar-2.0.6}/src/databar/exceptions.py +0 -0
  22. {databar-2.0.5 → databar-2.0.6}/src/databar/models.py +0 -0
  23. {databar-2.0.5 → databar-2.0.6}/src/databar.egg-info/dependency_links.txt +0 -0
  24. {databar-2.0.5 → databar-2.0.6}/src/databar.egg-info/entry_points.txt +0 -0
  25. {databar-2.0.5 → databar-2.0.6}/src/databar.egg-info/requires.txt +0 -0
  26. {databar-2.0.5 → databar-2.0.6}/src/databar.egg-info/top_level.txt +0 -0
  27. {databar-2.0.5 → databar-2.0.6}/tests/test_client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databar
3
- Version: 2.0.5
3
+ Version: 2.0.6
4
4
  Summary: Official Databar.ai Python SDK and CLI — connect to enrichments, waterfalls, and tables via api.databar.ai
5
5
  Author-email: "Databar.ai Team" <info@databar.ai>
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "databar"
7
- version = "2.0.5"
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" }
@@ -58,7 +58,7 @@ from .models import (
58
58
  WaterfallEnrichment,
59
59
  )
60
60
 
61
- __version__ = "2.0.5"
61
+ __version__ = "2.0.6"
62
62
  __all__ = [
63
63
  "DatabarClient",
64
64
  # exceptions
@@ -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,14 @@ 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
+
33
41
  @app.command("agent-guide")
34
42
  def agent_guide() -> None:
35
43
  """Print the full agent usage guide (SDK + CLI reference for AI agents)."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databar
3
- Version: 2.0.5
3
+ Version: 2.0.6
4
4
  Summary: Official Databar.ai Python SDK and CLI — connect to enrichments, waterfalls, and tables via api.databar.ai
5
5
  Author-email: "Databar.ai Team" <info@databar.ai>
6
6
  License: MIT License
@@ -14,6 +14,7 @@ src/databar.egg-info/top_level.txt
14
14
  src/databar/cli/__init__.py
15
15
  src/databar/cli/_auth.py
16
16
  src/databar/cli/_guide.py
17
+ src/databar/cli/_onboard.py
17
18
  src/databar/cli/_output.py
18
19
  src/databar/cli/app.py
19
20
  src/databar/cli/enrichments.py
@@ -329,4 +329,4 @@ def test_task_get_poll(monkeypatch):
329
329
  def test_version_flag():
330
330
  result = runner.invoke(app, ["--version"])
331
331
  assert result.exit_code == 0
332
- assert "2.0.5" in result.output
332
+ assert "2.0.6" in result.output
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes