databar 2.0.2__tar.gz → 2.0.4__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.2/src/databar.egg-info → databar-2.0.4}/PKG-INFO +1 -1
- {databar-2.0.2 → databar-2.0.4}/pyproject.toml +1 -1
- {databar-2.0.2 → databar-2.0.4}/src/databar/__init__.py +1 -1
- {databar-2.0.2 → databar-2.0.4}/src/databar/client.py +69 -6
- {databar-2.0.2 → databar-2.0.4}/src/databar/models.py +120 -11
- {databar-2.0.2 → databar-2.0.4/src/databar.egg-info}/PKG-INFO +1 -1
- {databar-2.0.2 → databar-2.0.4}/tests/test_cli.py +1 -1
- {databar-2.0.2 → databar-2.0.4}/LICENSE +0 -0
- {databar-2.0.2 → databar-2.0.4}/README.md +0 -0
- {databar-2.0.2 → databar-2.0.4}/setup.cfg +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar/cli/__init__.py +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar/cli/_auth.py +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar/cli/_output.py +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar/cli/app.py +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar/cli/enrichments.py +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar/cli/tables.py +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar/cli/tasks.py +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar/cli/waterfalls.py +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar/exceptions.py +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar.egg-info/SOURCES.txt +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar.egg-info/dependency_links.txt +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar.egg-info/entry_points.txt +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar.egg-info/requires.txt +0 -0
- {databar-2.0.2 → databar-2.0.4}/src/databar.egg-info/top_level.txt +0 -0
- {databar-2.0.2 → databar-2.0.4}/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.4"
|
|
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" }
|
|
@@ -16,6 +16,7 @@ in databar_mcp/src/databar-client.ts.
|
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
18
|
import os
|
|
19
|
+
import re
|
|
19
20
|
import time
|
|
20
21
|
from typing import Any, Dict, List, Optional
|
|
21
22
|
|
|
@@ -438,10 +439,65 @@ class DatabarClient:
|
|
|
438
439
|
table_uuid: str,
|
|
439
440
|
enrichment_id: int,
|
|
440
441
|
mapping: Dict[str, Any],
|
|
441
|
-
) ->
|
|
442
|
-
"""
|
|
443
|
-
|
|
444
|
-
|
|
442
|
+
) -> TableEnrichment:
|
|
443
|
+
"""
|
|
444
|
+
Add an enrichment to a table with a parameter-to-column mapping.
|
|
445
|
+
|
|
446
|
+
``mapping`` keys are enrichment parameter names. Values are dicts with:
|
|
447
|
+
- ``{"type": "mapping", "value": "<column-name-or-uuid>"}``
|
|
448
|
+
— reads the value from a table column per row.
|
|
449
|
+
You may pass a human-readable column name; the SDK will automatically
|
|
450
|
+
resolve it to the required column UUID via GET /table/{uuid}/columns.
|
|
451
|
+
- ``{"type": "simple", "value": "<static-value>"}``
|
|
452
|
+
— uses the same hardcoded value for every row.
|
|
453
|
+
|
|
454
|
+
Returns the newly added :class:`TableEnrichment` (with ``id`` and ``name``),
|
|
455
|
+
resolved by diffing enrichments before and after the add.
|
|
456
|
+
"""
|
|
457
|
+
# Auto-resolve column names → UUIDs for mapping-type entries
|
|
458
|
+
resolved_mapping: Dict[str, Any] = {}
|
|
459
|
+
column_map: Optional[Dict[str, str]] = None # name → uuid, built lazily
|
|
460
|
+
|
|
461
|
+
for param, entry in mapping.items():
|
|
462
|
+
if not isinstance(entry, dict) or entry.get("type") != "mapping":
|
|
463
|
+
resolved_mapping[param] = entry
|
|
464
|
+
continue
|
|
465
|
+
|
|
466
|
+
value = entry.get("value", "")
|
|
467
|
+
# Looks like a UUID already — 8-4-4-4-12 hex pattern
|
|
468
|
+
if re.fullmatch(r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", str(value), re.IGNORECASE):
|
|
469
|
+
resolved_mapping[param] = entry
|
|
470
|
+
continue
|
|
471
|
+
|
|
472
|
+
# Build the column name→uuid map once
|
|
473
|
+
if column_map is None:
|
|
474
|
+
columns = self.get_columns(table_uuid)
|
|
475
|
+
column_map = {c.name: c.identifier for c in columns}
|
|
476
|
+
|
|
477
|
+
uuid = column_map.get(value)
|
|
478
|
+
if uuid is None:
|
|
479
|
+
# Not a known column name — pass through and let the API surface the error
|
|
480
|
+
resolved_mapping[param] = entry
|
|
481
|
+
else:
|
|
482
|
+
resolved_mapping[param] = {**entry, "value": uuid}
|
|
483
|
+
|
|
484
|
+
# Snapshot existing enrichment IDs so we can detect the new one
|
|
485
|
+
before_ids = {e.id for e in self.get_table_enrichments(table_uuid)}
|
|
486
|
+
|
|
487
|
+
payload = {"enrichment": enrichment_id, "mapping": resolved_mapping}
|
|
488
|
+
self._request("POST", f"/table/{table_uuid}/add-enrichment", json=payload)
|
|
489
|
+
|
|
490
|
+
# Fetch updated list and return the newly created TableEnrichment
|
|
491
|
+
after = self.get_table_enrichments(table_uuid)
|
|
492
|
+
new_enrichments = [e for e in after if e.id not in before_ids]
|
|
493
|
+
if new_enrichments:
|
|
494
|
+
return new_enrichments[-1]
|
|
495
|
+
|
|
496
|
+
# Fallback: return the last enrichment in the list if we can't detect which is new
|
|
497
|
+
if after:
|
|
498
|
+
return after[-1]
|
|
499
|
+
|
|
500
|
+
raise DatabarError("Enrichment was added but could not be retrieved. Use get_table_enrichments() to fetch it manually.")
|
|
445
501
|
|
|
446
502
|
def run_table_enrichment(
|
|
447
503
|
self,
|
|
@@ -465,9 +521,16 @@ class DatabarClient:
|
|
|
465
521
|
self,
|
|
466
522
|
table_uuid: str,
|
|
467
523
|
page: int = 1,
|
|
468
|
-
per_page: int =
|
|
524
|
+
per_page: int = 100,
|
|
469
525
|
) -> Dict[str, Any]:
|
|
470
|
-
"""
|
|
526
|
+
"""
|
|
527
|
+
Get rows from a table with pagination.
|
|
528
|
+
|
|
529
|
+
Returns a dict with keys: ``data`` (list of row dicts), ``has_next_page``,
|
|
530
|
+
``total_count``, ``page``. Each row dict is keyed by column name.
|
|
531
|
+
|
|
532
|
+
``per_page`` max is 500 (API limit). Default is 100.
|
|
533
|
+
"""
|
|
471
534
|
return self._request(
|
|
472
535
|
"GET",
|
|
473
536
|
f"/table/{table_uuid}/rows",
|
|
@@ -20,6 +20,11 @@ from pydantic import BaseModel, Field
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class User(BaseModel):
|
|
23
|
+
"""Authenticated user profile.
|
|
24
|
+
|
|
25
|
+
Fields: first_name, email, balance, plan.
|
|
26
|
+
"""
|
|
27
|
+
|
|
23
28
|
first_name: Optional[str] = None
|
|
24
29
|
email: str
|
|
25
30
|
balance: float
|
|
@@ -51,22 +56,64 @@ class Choices(BaseModel):
|
|
|
51
56
|
|
|
52
57
|
|
|
53
58
|
class EnrichmentParam(BaseModel):
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
"""A parameter required or accepted by an enrichment.
|
|
60
|
+
|
|
61
|
+
Fields: name, is_required, type_field, description, choices.
|
|
62
|
+
|
|
63
|
+
Property aliases: .slug → .name, .label → .description, .required → .is_required.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
name: str = Field(description="Parameter slug used as the key in the params dict.")
|
|
67
|
+
is_required: bool = Field(description="Whether this parameter is required.")
|
|
56
68
|
type_field: str = Field(
|
|
57
69
|
description="Input type. Common values: text, select, mselect, datetime."
|
|
58
70
|
)
|
|
59
|
-
description: str
|
|
71
|
+
description: str = Field(description="Human-readable label / description.")
|
|
60
72
|
choices: Optional[Choices] = None
|
|
61
73
|
|
|
74
|
+
@property
|
|
75
|
+
def slug(self) -> str:
|
|
76
|
+
"""Alias for name."""
|
|
77
|
+
return self.name
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def label(self) -> str:
|
|
81
|
+
"""Alias for description."""
|
|
82
|
+
return self.description
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def required(self) -> bool:
|
|
86
|
+
"""Alias for is_required."""
|
|
87
|
+
return self.is_required
|
|
88
|
+
|
|
62
89
|
|
|
63
90
|
class EnrichmentResponseField(BaseModel):
|
|
64
|
-
|
|
65
|
-
|
|
91
|
+
"""A field returned in the enrichment result data.
|
|
92
|
+
|
|
93
|
+
Fields: name, type_field.
|
|
94
|
+
|
|
95
|
+
Property aliases: .slug → .name, .label → .name.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
name: str = Field(description="Field name as it appears in the result data.")
|
|
99
|
+
type_field: str = Field(description="Data type of this field.")
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def slug(self) -> str:
|
|
103
|
+
"""Alias for name."""
|
|
104
|
+
return self.name
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def label(self) -> str:
|
|
108
|
+
"""Alias for name."""
|
|
109
|
+
return self.name
|
|
66
110
|
|
|
67
111
|
|
|
68
112
|
class EnrichmentSummary(BaseModel):
|
|
69
|
-
"""Enrichment as returned by the list endpoint (no params/response_fields).
|
|
113
|
+
"""Enrichment as returned by the list endpoint (no params/response_fields).
|
|
114
|
+
|
|
115
|
+
Fields: id, name, description, data_source, price, auth_method.
|
|
116
|
+
"""
|
|
70
117
|
|
|
71
118
|
id: int
|
|
72
119
|
name: str
|
|
@@ -77,7 +124,16 @@ class EnrichmentSummary(BaseModel):
|
|
|
77
124
|
|
|
78
125
|
|
|
79
126
|
class Enrichment(EnrichmentSummary):
|
|
80
|
-
"""Full enrichment detail including params and response fields.
|
|
127
|
+
"""Full enrichment detail including params and response fields.
|
|
128
|
+
|
|
129
|
+
Fields: id, name, description, data_source, price, auth_method, params, response_fields.
|
|
130
|
+
|
|
131
|
+
Usage::
|
|
132
|
+
|
|
133
|
+
enrichment = client.get_enrichment(123)
|
|
134
|
+
for p in enrichment.params:
|
|
135
|
+
print(p.name, p.is_required, p.description)
|
|
136
|
+
"""
|
|
81
137
|
|
|
82
138
|
params: Optional[List[EnrichmentParam]] = None
|
|
83
139
|
response_fields: Optional[List[EnrichmentResponseField]] = None
|
|
@@ -153,7 +209,20 @@ class WaterfallEnrichment(BaseModel):
|
|
|
153
209
|
|
|
154
210
|
|
|
155
211
|
class Waterfall(BaseModel):
|
|
156
|
-
|
|
212
|
+
"""A waterfall enrichment that tries multiple providers in sequence.
|
|
213
|
+
|
|
214
|
+
Fields: identifier, name, description, input_params, output_fields,
|
|
215
|
+
available_enrichments, is_email_verifying, email_verifiers.
|
|
216
|
+
|
|
217
|
+
Property aliases: .slug → .identifier.
|
|
218
|
+
|
|
219
|
+
Usage::
|
|
220
|
+
|
|
221
|
+
wf = client.get_waterfall("email_getter")
|
|
222
|
+
result = client.run_waterfall_sync(wf.identifier, {...})
|
|
223
|
+
"""
|
|
224
|
+
|
|
225
|
+
identifier: str = Field(description="Slug-style identifier, e.g. 'email_getter'. Use this when calling run_waterfall().")
|
|
157
226
|
name: str
|
|
158
227
|
description: str
|
|
159
228
|
input_params: List[Dict[str, Any]]
|
|
@@ -162,6 +231,11 @@ class Waterfall(BaseModel):
|
|
|
162
231
|
is_email_verifying: bool
|
|
163
232
|
email_verifiers: List[Any]
|
|
164
233
|
|
|
234
|
+
@property
|
|
235
|
+
def slug(self) -> str:
|
|
236
|
+
"""Alias for identifier."""
|
|
237
|
+
return self.identifier
|
|
238
|
+
|
|
165
239
|
|
|
166
240
|
# ===========================================================================
|
|
167
241
|
# Tables
|
|
@@ -169,21 +243,56 @@ class Waterfall(BaseModel):
|
|
|
169
243
|
|
|
170
244
|
|
|
171
245
|
class Table(BaseModel):
|
|
172
|
-
|
|
246
|
+
"""A Databar table.
|
|
247
|
+
|
|
248
|
+
Fields: identifier, name, created_at, updated_at.
|
|
249
|
+
|
|
250
|
+
Property aliases: .id → .identifier, .uuid → .identifier.
|
|
251
|
+
|
|
252
|
+
Usage::
|
|
253
|
+
|
|
254
|
+
table = client.create_table(name="Leads", columns=["email", "name"])
|
|
255
|
+
rows = client.get_rows(table.identifier)
|
|
256
|
+
"""
|
|
257
|
+
|
|
258
|
+
identifier: str = Field(description="Table UUID. Use this in all table operations.")
|
|
173
259
|
name: str
|
|
174
260
|
created_at: str
|
|
175
261
|
updated_at: str
|
|
176
262
|
|
|
263
|
+
@property
|
|
264
|
+
def id(self) -> str:
|
|
265
|
+
"""Alias for identifier."""
|
|
266
|
+
return self.identifier
|
|
267
|
+
|
|
268
|
+
@property
|
|
269
|
+
def uuid(self) -> str:
|
|
270
|
+
"""Alias for identifier."""
|
|
271
|
+
return self.identifier
|
|
272
|
+
|
|
177
273
|
|
|
178
274
|
class Column(BaseModel):
|
|
179
|
-
|
|
275
|
+
"""A column defined on a table.
|
|
276
|
+
|
|
277
|
+
Fields: identifier, internal_name, name, type_of_value, data_processor_id.
|
|
278
|
+
"""
|
|
279
|
+
|
|
280
|
+
identifier: str = Field(description="Column UUID.")
|
|
180
281
|
internal_name: str
|
|
181
|
-
name: str
|
|
282
|
+
name: str = Field(description="Human-readable column name.")
|
|
182
283
|
type_of_value: str
|
|
183
284
|
data_processor_id: Optional[int] = None
|
|
184
285
|
|
|
185
286
|
|
|
186
287
|
class TableEnrichment(BaseModel):
|
|
288
|
+
"""An enrichment configured on a table.
|
|
289
|
+
|
|
290
|
+
Fields: id, name.
|
|
291
|
+
|
|
292
|
+
The id here is the TABLE-ENRICHMENT id — use it with run_table_enrichment(),
|
|
293
|
+
not the enrichment catalog id.
|
|
294
|
+
"""
|
|
295
|
+
|
|
187
296
|
id: int
|
|
188
297
|
name: str
|
|
189
298
|
|
|
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
|