definite-sdk 0.1.9__py3-none-any.whl → 0.1.12__py3-none-any.whl
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.
- definite_sdk/client.py +50 -0
- definite_sdk/sql.py +37 -16
- {definite_sdk-0.1.9.dist-info → definite_sdk-0.1.12.dist-info}/METADATA +35 -1
- {definite_sdk-0.1.9.dist-info → definite_sdk-0.1.12.dist-info}/RECORD +6 -6
- {definite_sdk-0.1.9.dist-info → definite_sdk-0.1.12.dist-info}/LICENSE +0 -0
- {definite_sdk-0.1.9.dist-info → definite_sdk-0.1.12.dist-info}/WHEEL +0 -0
definite_sdk/client.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from typing import Optional
|
|
3
3
|
|
|
4
|
+
import requests
|
|
4
5
|
from definite_sdk.integration import DefiniteIntegrationStore
|
|
5
6
|
from definite_sdk.message import DefiniteMessageClient
|
|
6
7
|
from definite_sdk.secret import DefiniteSecretStore
|
|
@@ -66,6 +67,55 @@ class DefiniteClient:
|
|
|
66
67
|
|
|
67
68
|
return DefiniteSqlClient(self.api_key, self.api_url)
|
|
68
69
|
|
|
70
|
+
def attach_ducklake(self, alias: str = "lake") -> str:
|
|
71
|
+
"""Generates SQL statements to attach DuckLake to a DuckDB connection.
|
|
72
|
+
|
|
73
|
+
This method fetches the team's DuckLake integration credentials and generates
|
|
74
|
+
the necessary SQL statements to create a GCS secret and attach DuckLake.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
alias: The alias name for the attached DuckLake database (default: "lake")
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
str: SQL statements to execute for attaching DuckLake
|
|
81
|
+
|
|
82
|
+
Example:
|
|
83
|
+
>>> client = DefiniteClient(os.environ["DEFINITE_API_KEY"])
|
|
84
|
+
>>> sql = client.attach_ducklake()
|
|
85
|
+
>>> conn.execute(sql)
|
|
86
|
+
"""
|
|
87
|
+
# Fetch DuckLake integration details
|
|
88
|
+
response = requests.get(
|
|
89
|
+
f"{self.api_url}/v1/api/integration/DuckLake",
|
|
90
|
+
headers={"Authorization": f"Bearer {self.api_key}"},
|
|
91
|
+
)
|
|
92
|
+
response.raise_for_status()
|
|
93
|
+
dl_integration = response.json()
|
|
94
|
+
|
|
95
|
+
# Generate SQL statements
|
|
96
|
+
create_secret_sql = f"""CREATE SECRET (
|
|
97
|
+
TYPE gcs,
|
|
98
|
+
KEY_ID '{dl_integration['gcs_access_key_id']}',
|
|
99
|
+
SECRET '{dl_integration['gcs_secret_access_key']}'
|
|
100
|
+
);"""
|
|
101
|
+
|
|
102
|
+
# Build PostgreSQL connection string
|
|
103
|
+
pg_conn_str = (
|
|
104
|
+
f"postgresql://{dl_integration['pg_user']}:"
|
|
105
|
+
f"{dl_integration['pg_password']}@"
|
|
106
|
+
f"{dl_integration['pg_host']}:"
|
|
107
|
+
f"{dl_integration['pg_port']}/"
|
|
108
|
+
f"{dl_integration['pg_database']}"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
attach_sql = (
|
|
112
|
+
f"ATTACH 'ducklake:postgres:{pg_conn_str}' AS {alias} "
|
|
113
|
+
f"(DATA_PATH 'gs://{dl_integration['gcs_bucket_path']}', "
|
|
114
|
+
f"METADATA_SCHEMA '{dl_integration['pg_schema']}');"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return f"{create_secret_sql}\n\n{attach_sql}"
|
|
118
|
+
|
|
69
119
|
# Alias methods for consistency
|
|
70
120
|
def kv_store(self, name: str) -> DefiniteKVStore:
|
|
71
121
|
"""Alias for get_kv_store."""
|
definite_sdk/sql.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any, Dict,
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
2
|
|
|
3
3
|
import requests
|
|
4
4
|
|
|
@@ -31,7 +31,9 @@ class DefiniteSqlClient:
|
|
|
31
31
|
... "timeDimensions": [{"dimension": "sales.date", "granularity": "month"}],
|
|
32
32
|
... "limit": 1000
|
|
33
33
|
... }
|
|
34
|
-
>>> result = sql_client.execute_cube_query(
|
|
34
|
+
>>> result = sql_client.execute_cube_query(
|
|
35
|
+
... cube_query, integration_id="my_cube_integration"
|
|
36
|
+
... )
|
|
35
37
|
>>> print(result)
|
|
36
38
|
"""
|
|
37
39
|
|
|
@@ -46,11 +48,7 @@ class DefiniteSqlClient:
|
|
|
46
48
|
self._api_key = api_key
|
|
47
49
|
self._sql_url = api_url + SQL_ENDPOINT
|
|
48
50
|
|
|
49
|
-
def execute(
|
|
50
|
-
self,
|
|
51
|
-
sql: str,
|
|
52
|
-
integration_id: Optional[str] = None
|
|
53
|
-
) -> Dict[str, Any]:
|
|
51
|
+
def execute(self, sql: str, integration_id: Optional[str] = None) -> Dict[str, Any]:
|
|
54
52
|
"""
|
|
55
53
|
Executes a SQL query against a database integration.
|
|
56
54
|
|
|
@@ -69,7 +67,7 @@ class DefiniteSqlClient:
|
|
|
69
67
|
>>> result = sql_client.execute("SELECT COUNT(*) FROM users")
|
|
70
68
|
>>> print(result)
|
|
71
69
|
"""
|
|
72
|
-
payload = {"sql": sql}
|
|
70
|
+
payload: Dict[str, Any] = {"sql": sql}
|
|
73
71
|
if integration_id:
|
|
74
72
|
payload["integration_id"] = integration_id
|
|
75
73
|
|
|
@@ -82,9 +80,12 @@ class DefiniteSqlClient:
|
|
|
82
80
|
return response.json()
|
|
83
81
|
|
|
84
82
|
def execute_cube_query(
|
|
85
|
-
self,
|
|
86
|
-
cube_query: Dict[str, Any],
|
|
87
|
-
integration_id: Optional[str] = None
|
|
83
|
+
self,
|
|
84
|
+
cube_query: Dict[str, Any],
|
|
85
|
+
integration_id: Optional[str] = None,
|
|
86
|
+
persist: bool = True,
|
|
87
|
+
invalidate: bool = False,
|
|
88
|
+
raw: bool = False,
|
|
88
89
|
) -> Dict[str, Any]:
|
|
89
90
|
"""
|
|
90
91
|
Executes a Cube query against a Cube integration.
|
|
@@ -93,6 +94,9 @@ class DefiniteSqlClient:
|
|
|
93
94
|
cube_query (Dict[str, Any]): The Cube query in JSON format.
|
|
94
95
|
integration_id (Optional[str]): The Cube integration ID to query against.
|
|
95
96
|
If not provided, the default integration will be used.
|
|
97
|
+
persist (bool): Whether to persist the query result to the cache.
|
|
98
|
+
invalidate (bool): Whether to invalidate the cached result.
|
|
99
|
+
raw (bool): Whether to return raw/unformatted cube results.
|
|
96
100
|
|
|
97
101
|
Returns:
|
|
98
102
|
Dict[str, Any]: The query result as returned by the API.
|
|
@@ -106,21 +110,38 @@ class DefiniteSqlClient:
|
|
|
106
110
|
... "measures": ["sales.total_amount"],
|
|
107
111
|
... "timeDimensions": [{
|
|
108
112
|
... "dimension": "sales.date",
|
|
109
|
-
... "granularity": "month"
|
|
113
|
+
... "granularity": "month",
|
|
110
114
|
... }],
|
|
111
115
|
... "limit": 1000
|
|
112
116
|
... }
|
|
113
|
-
>>> result = sql_client.execute_cube_query(
|
|
117
|
+
>>> result = sql_client.execute_cube_query(
|
|
118
|
+
... cube_query, "my_cube_integration"
|
|
119
|
+
... )
|
|
114
120
|
>>> print(result)
|
|
121
|
+
|
|
122
|
+
>>> # To get raw/unformatted results:
|
|
123
|
+
>>> raw_result = sql_client.execute_cube_query(
|
|
124
|
+
... cube_query, "my_cube_integration", raw=True
|
|
125
|
+
... )
|
|
126
|
+
>>> print(raw_result)
|
|
115
127
|
"""
|
|
116
|
-
payload = {"cube_query": cube_query}
|
|
128
|
+
payload: Dict[str, Any] = {"cube_query": cube_query}
|
|
117
129
|
if integration_id:
|
|
118
130
|
payload["integration_id"] = integration_id
|
|
131
|
+
if persist:
|
|
132
|
+
payload["persist"] = persist
|
|
133
|
+
if invalidate:
|
|
134
|
+
payload["invalidate"] = invalidate
|
|
135
|
+
|
|
136
|
+
# Build URL with query parameters
|
|
137
|
+
url = self._sql_url
|
|
138
|
+
if raw:
|
|
139
|
+
url += "?raw=true"
|
|
119
140
|
|
|
120
141
|
response = requests.post(
|
|
121
|
-
|
|
142
|
+
url,
|
|
122
143
|
json=payload,
|
|
123
144
|
headers={"Authorization": "Bearer " + self._api_key},
|
|
124
145
|
)
|
|
125
146
|
response.raise_for_status()
|
|
126
|
-
return response.json()
|
|
147
|
+
return response.json()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: definite-sdk
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.12
|
|
4
4
|
Summary: Definite SDK for Python
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Definite
|
|
@@ -59,6 +59,7 @@ client = DefiniteClient("YOUR_API_KEY")
|
|
|
59
59
|
- **Integration Store**: Read-only access to integration configurations
|
|
60
60
|
- **Messaging**: Send messages through various channels (Slack, and more coming soon)
|
|
61
61
|
- **dlt Integration**: Run dlt pipelines with automatic state persistence to Definite
|
|
62
|
+
- **DuckLake Integration**: Easy attachment of your team's DuckLake to DuckDB connections
|
|
62
63
|
- **DuckDB Support**: Automatic discovery and connection to team's DuckDB integrations
|
|
63
64
|
|
|
64
65
|
## Basic Usage
|
|
@@ -231,6 +232,39 @@ pipeline.run(orders())
|
|
|
231
232
|
last_cursor = pipeline.get_state("orders")
|
|
232
233
|
```
|
|
233
234
|
|
|
235
|
+
### DuckLake Integration
|
|
236
|
+
|
|
237
|
+
Attach your team's DuckLake to a DuckDB connection for seamless data access:
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
import duckdb
|
|
241
|
+
from definite_sdk import DefiniteClient
|
|
242
|
+
|
|
243
|
+
# Initialize the client
|
|
244
|
+
client = DefiniteClient("YOUR_API_KEY")
|
|
245
|
+
|
|
246
|
+
# Connect to DuckDB and attach DuckLake
|
|
247
|
+
conn = duckdb.connect()
|
|
248
|
+
conn.execute(client.attach_ducklake())
|
|
249
|
+
|
|
250
|
+
# Now you can use DuckLake tables
|
|
251
|
+
conn.execute("CREATE SCHEMA IF NOT EXISTS lake.my_schema;")
|
|
252
|
+
conn.execute("CREATE OR REPLACE TABLE lake.my_schema.users AS SELECT * FROM df")
|
|
253
|
+
|
|
254
|
+
# Query your DuckLake data
|
|
255
|
+
result = conn.sql("SELECT * FROM lake.my_schema.users").df()
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
You can also specify a custom alias for the attached DuckLake:
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
# Attach with custom alias
|
|
262
|
+
conn.execute(client.attach_ducklake(alias="warehouse"))
|
|
263
|
+
|
|
264
|
+
# Use the custom alias
|
|
265
|
+
conn.execute("SELECT * FROM warehouse.my_schema.users")
|
|
266
|
+
```
|
|
267
|
+
|
|
234
268
|
### DuckDB Integration Discovery
|
|
235
269
|
|
|
236
270
|
```python
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
definite_sdk/__init__.py,sha256=Y3GwfDOkpWt6EILoZ7PRT7nXuoVnk0zHrNOPHlkEHS4,604
|
|
2
|
-
definite_sdk/client.py,sha256=
|
|
2
|
+
definite_sdk/client.py,sha256=mpXFpJVmK3JVYsNrn7f4bzqlxMbIsS3meRu3XMiXWZ4,5075
|
|
3
3
|
definite_sdk/dlt.py,sha256=JC-S1jd6zqnpGSnvk9kYb8GQ1IPZRd1zVKTVYAbeA4w,7188
|
|
4
4
|
definite_sdk/integration.py,sha256=v15QIpWm3eAZr-cmavfA39LXTjpskEEQ2SM_TBV4E1U,3395
|
|
5
5
|
definite_sdk/message.py,sha256=I3qx2v9gIcC9NZyr5zEp_Seft8clRoER4WeUbAaDiFc,6549
|
|
6
6
|
definite_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
definite_sdk/secret.py,sha256=3wvEnTZ946hOxJBdB29dxvppwJ0x-TJV_LxRcXGqtis,2503
|
|
8
|
-
definite_sdk/sql.py,sha256=
|
|
8
|
+
definite_sdk/sql.py,sha256=o2ume-S7__wp8hMBy2aC6dmGYV4s-IXMlMAyEuyAP84,4705
|
|
9
9
|
definite_sdk/store.py,sha256=7VYvROIrlWyM_ZX3LpqWWAfVLNDm0XMccMLv6qi9id8,5575
|
|
10
|
-
definite_sdk-0.1.
|
|
11
|
-
definite_sdk-0.1.
|
|
12
|
-
definite_sdk-0.1.
|
|
13
|
-
definite_sdk-0.1.
|
|
10
|
+
definite_sdk-0.1.12.dist-info/LICENSE,sha256=jMd7PtwNWiMoGIDgFutC1v4taO69W9SRZLKe9o470Vk,1064
|
|
11
|
+
definite_sdk-0.1.12.dist-info/METADATA,sha256=mR32ZrkWtX_q7BBMF6dtE2f2lHicy2SBo1lkMxOTFto,9136
|
|
12
|
+
definite_sdk-0.1.12.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
13
|
+
definite_sdk-0.1.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|