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.
Files changed (25) hide show
  1. {databar-2.0.2/src/databar.egg-info → databar-2.0.4}/PKG-INFO +1 -1
  2. {databar-2.0.2 → databar-2.0.4}/pyproject.toml +1 -1
  3. {databar-2.0.2 → databar-2.0.4}/src/databar/__init__.py +1 -1
  4. {databar-2.0.2 → databar-2.0.4}/src/databar/client.py +69 -6
  5. {databar-2.0.2 → databar-2.0.4}/src/databar/models.py +120 -11
  6. {databar-2.0.2 → databar-2.0.4/src/databar.egg-info}/PKG-INFO +1 -1
  7. {databar-2.0.2 → databar-2.0.4}/tests/test_cli.py +1 -1
  8. {databar-2.0.2 → databar-2.0.4}/LICENSE +0 -0
  9. {databar-2.0.2 → databar-2.0.4}/README.md +0 -0
  10. {databar-2.0.2 → databar-2.0.4}/setup.cfg +0 -0
  11. {databar-2.0.2 → databar-2.0.4}/src/databar/cli/__init__.py +0 -0
  12. {databar-2.0.2 → databar-2.0.4}/src/databar/cli/_auth.py +0 -0
  13. {databar-2.0.2 → databar-2.0.4}/src/databar/cli/_output.py +0 -0
  14. {databar-2.0.2 → databar-2.0.4}/src/databar/cli/app.py +0 -0
  15. {databar-2.0.2 → databar-2.0.4}/src/databar/cli/enrichments.py +0 -0
  16. {databar-2.0.2 → databar-2.0.4}/src/databar/cli/tables.py +0 -0
  17. {databar-2.0.2 → databar-2.0.4}/src/databar/cli/tasks.py +0 -0
  18. {databar-2.0.2 → databar-2.0.4}/src/databar/cli/waterfalls.py +0 -0
  19. {databar-2.0.2 → databar-2.0.4}/src/databar/exceptions.py +0 -0
  20. {databar-2.0.2 → databar-2.0.4}/src/databar.egg-info/SOURCES.txt +0 -0
  21. {databar-2.0.2 → databar-2.0.4}/src/databar.egg-info/dependency_links.txt +0 -0
  22. {databar-2.0.2 → databar-2.0.4}/src/databar.egg-info/entry_points.txt +0 -0
  23. {databar-2.0.2 → databar-2.0.4}/src/databar.egg-info/requires.txt +0 -0
  24. {databar-2.0.2 → databar-2.0.4}/src/databar.egg-info/top_level.txt +0 -0
  25. {databar-2.0.2 → databar-2.0.4}/tests/test_client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databar
3
- Version: 2.0.2
3
+ Version: 2.0.4
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.2"
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" }
@@ -57,7 +57,7 @@ from .models import (
57
57
  WaterfallEnrichment,
58
58
  )
59
59
 
60
- __version__ = "2.0.2"
60
+ __version__ = "2.0.4"
61
61
  __all__ = [
62
62
  "DatabarClient",
63
63
  # exceptions
@@ -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
- ) -> Any:
442
- """Add an enrichment to a table with a parameter-to-column mapping."""
443
- payload = {"enrichment": enrichment_id, "mapping": mapping}
444
- return self._request("POST", f"/table/{table_uuid}/add-enrichment", json=payload)
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 = 1000,
524
+ per_page: int = 100,
469
525
  ) -> Dict[str, Any]:
470
- """Get rows from a table with pagination. Returns raw dict with has_next_page etc."""
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
- name: str
55
- is_required: bool
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
- name: str
65
- type_field: str
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
- identifier: str
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
- identifier: str
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
- identifier: str
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databar
3
- Version: 2.0.2
3
+ Version: 2.0.4
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
@@ -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.2" in result.output
332
+ assert "2.0.4" in result.output
File without changes
File without changes
File without changes
File without changes
File without changes