duckrun 0.2.18.dev2__py3-none-any.whl → 0.2.18.dev3__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.
Potentially problematic release.
This version of duckrun might be problematic. Click here for more details.
- duckrun/core.py +7 -7
- duckrun/semantic_model.py +88 -4
- {duckrun-0.2.18.dev2.dist-info → duckrun-0.2.18.dev3.dist-info}/METADATA +1 -1
- {duckrun-0.2.18.dev2.dist-info → duckrun-0.2.18.dev3.dist-info}/RECORD +7 -7
- {duckrun-0.2.18.dev2.dist-info → duckrun-0.2.18.dev3.dist-info}/WHEEL +0 -0
- {duckrun-0.2.18.dev2.dist-info → duckrun-0.2.18.dev3.dist-info}/licenses/LICENSE +0 -0
- {duckrun-0.2.18.dev2.dist-info → duckrun-0.2.18.dev3.dist-info}/top_level.txt +0 -0
duckrun/core.py
CHANGED
|
@@ -1188,7 +1188,7 @@ class Duckrun(WorkspaceOperationsMixin):
|
|
|
1188
1188
|
- URL: "https://raw.githubusercontent.com/.../model.bim"
|
|
1189
1189
|
- Local file: "model.bim"
|
|
1190
1190
|
- Workspace/Model: "workspace_name/model_name"
|
|
1191
|
-
dataset_name: Name for the semantic model (default:
|
|
1191
|
+
dataset_name: Name for the semantic model (default: schema name)
|
|
1192
1192
|
wait_seconds: Seconds to wait for permission propagation (default: 5)
|
|
1193
1193
|
|
|
1194
1194
|
Returns:
|
|
@@ -1197,14 +1197,14 @@ class Duckrun(WorkspaceOperationsMixin):
|
|
|
1197
1197
|
Examples:
|
|
1198
1198
|
dr = Duckrun.connect("My Workspace/My Lakehouse.lakehouse/dbo")
|
|
1199
1199
|
|
|
1200
|
+
# Deploy with schema name as dataset name (dbo)
|
|
1201
|
+
dr.deploy("https://github.com/.../model.bim")
|
|
1202
|
+
|
|
1200
1203
|
# Deploy from workspace/model (uses same name by default)
|
|
1201
1204
|
dr.deploy("Source Workspace/Source Model") # Creates "Source Model"
|
|
1202
1205
|
|
|
1203
1206
|
# Deploy with custom name
|
|
1204
|
-
dr.deploy("
|
|
1205
|
-
|
|
1206
|
-
# Deploy from URL or local file
|
|
1207
|
-
dr.deploy("https://raw.githubusercontent.com/.../model.bim", dataset_name="My Model")
|
|
1207
|
+
dr.deploy("https://github.com/.../model.bim", dataset_name="Sales Model")
|
|
1208
1208
|
"""
|
|
1209
1209
|
from .semantic_model import deploy_semantic_model
|
|
1210
1210
|
|
|
@@ -1216,9 +1216,9 @@ class Duckrun(WorkspaceOperationsMixin):
|
|
|
1216
1216
|
if len(parts) == 2:
|
|
1217
1217
|
dataset_name = parts[1] # Use the model name
|
|
1218
1218
|
else:
|
|
1219
|
-
dataset_name =
|
|
1219
|
+
dataset_name = self.schema # Use schema name
|
|
1220
1220
|
else:
|
|
1221
|
-
dataset_name =
|
|
1221
|
+
dataset_name = self.schema # Use schema name
|
|
1222
1222
|
|
|
1223
1223
|
# Call the deployment function (DirectLake only)
|
|
1224
1224
|
return deploy_semantic_model(
|
duckrun/semantic_model.py
CHANGED
|
@@ -135,6 +135,8 @@ def refresh_dataset(dataset_name, workspace_id, client, dataset_id=None):
|
|
|
135
135
|
For DirectLake models, performs a two-step refresh:
|
|
136
136
|
1. clearValues - Purges data from memory
|
|
137
137
|
2. full - Reframes data from Delta tables
|
|
138
|
+
|
|
139
|
+
If a refresh is already in progress, waits for it to complete before starting a new one.
|
|
138
140
|
"""
|
|
139
141
|
|
|
140
142
|
# If dataset_id not provided, look it up by name
|
|
@@ -145,6 +147,46 @@ def refresh_dataset(dataset_name, workspace_id, client, dataset_id=None):
|
|
|
145
147
|
powerbi_url = f"https://api.powerbi.com/v1.0/myorg/datasets/{dataset_id}/refreshes"
|
|
146
148
|
headers = client._get_headers()
|
|
147
149
|
|
|
150
|
+
# Check for in-progress refreshes
|
|
151
|
+
print(" Checking for in-progress refreshes...")
|
|
152
|
+
try:
|
|
153
|
+
status_response = requests.get(f"{powerbi_url}?$top=1", headers=headers)
|
|
154
|
+
if status_response.status_code == 200:
|
|
155
|
+
refreshes = status_response.json().get('value', [])
|
|
156
|
+
if refreshes:
|
|
157
|
+
latest_refresh = refreshes[0]
|
|
158
|
+
status = latest_refresh.get('status')
|
|
159
|
+
if status in ['InProgress', 'Unknown']:
|
|
160
|
+
refresh_id = latest_refresh.get('requestId')
|
|
161
|
+
print(f" ⚠️ Found in-progress refresh (ID: {refresh_id})")
|
|
162
|
+
print(f" Waiting for current refresh to complete...")
|
|
163
|
+
|
|
164
|
+
# Wait for the in-progress refresh to complete
|
|
165
|
+
max_wait_attempts = 60
|
|
166
|
+
for attempt in range(max_wait_attempts):
|
|
167
|
+
time.sleep(5)
|
|
168
|
+
check_response = requests.get(f"{powerbi_url}/{refresh_id}", headers=headers)
|
|
169
|
+
if check_response.status_code == 200:
|
|
170
|
+
current_status = check_response.json().get('status')
|
|
171
|
+
|
|
172
|
+
if current_status == 'Completed':
|
|
173
|
+
print(f" ✓ Previous refresh completed")
|
|
174
|
+
break
|
|
175
|
+
elif current_status == 'Failed':
|
|
176
|
+
print(f" ⚠️ Previous refresh failed, continuing with new refresh")
|
|
177
|
+
break
|
|
178
|
+
elif current_status == 'Cancelled':
|
|
179
|
+
print(f" ⚠️ Previous refresh was cancelled, continuing with new refresh")
|
|
180
|
+
break
|
|
181
|
+
|
|
182
|
+
if attempt % 6 == 0:
|
|
183
|
+
print(f" Still waiting... (status: {current_status})")
|
|
184
|
+
else:
|
|
185
|
+
print(f" ⚠️ Timeout waiting for previous refresh, will attempt new refresh anyway")
|
|
186
|
+
except Exception as e:
|
|
187
|
+
print(f" ⚠️ Could not check refresh status: {e}")
|
|
188
|
+
print(f" Continuing with refresh attempt...")
|
|
189
|
+
|
|
148
190
|
# Step 1: clearValues - Purge data from memory
|
|
149
191
|
print(" Step 1: Clearing values from memory...")
|
|
150
192
|
clearvalues_payload = {
|
|
@@ -158,9 +200,45 @@ def refresh_dataset(dataset_name, workspace_id, client, dataset_id=None):
|
|
|
158
200
|
response = requests.post(powerbi_url, headers=headers, json=clearvalues_payload)
|
|
159
201
|
|
|
160
202
|
if response.status_code in [200, 202]:
|
|
161
|
-
|
|
203
|
+
# For 202, monitor the clearValues operation
|
|
204
|
+
if response.status_code == 202:
|
|
205
|
+
location = response.headers.get('Location')
|
|
206
|
+
if location:
|
|
207
|
+
clear_refresh_id = location.split('/')[-1]
|
|
208
|
+
print(" ✓ Clear values initiated, monitoring progress...")
|
|
209
|
+
|
|
210
|
+
max_attempts = 60
|
|
211
|
+
for attempt in range(max_attempts):
|
|
212
|
+
time.sleep(2)
|
|
213
|
+
|
|
214
|
+
status_url = f"https://api.powerbi.com/v1.0/myorg/datasets/{dataset_id}/refreshes/{clear_refresh_id}"
|
|
215
|
+
status_response = requests.get(status_url, headers=headers)
|
|
216
|
+
status_response.raise_for_status()
|
|
217
|
+
status = status_response.json().get('status')
|
|
218
|
+
|
|
219
|
+
if status == 'Completed':
|
|
220
|
+
print(f" ✓ Clear values completed")
|
|
221
|
+
break
|
|
222
|
+
elif status == 'Failed':
|
|
223
|
+
error = status_response.json().get('serviceExceptionJson', '')
|
|
224
|
+
raise Exception(f"Clear values failed: {error}")
|
|
225
|
+
elif status == 'Cancelled':
|
|
226
|
+
raise Exception("Clear values was cancelled")
|
|
227
|
+
|
|
228
|
+
if attempt % 10 == 0 and attempt > 0:
|
|
229
|
+
print(f" Clear values status: {status}...")
|
|
230
|
+
else:
|
|
231
|
+
raise Exception(f"Clear values timed out")
|
|
232
|
+
else:
|
|
233
|
+
print(" ✓ Clear values completed")
|
|
162
234
|
else:
|
|
163
|
-
|
|
235
|
+
# Provide detailed error message
|
|
236
|
+
try:
|
|
237
|
+
error_details = response.json()
|
|
238
|
+
error_message = error_details.get('error', {}).get('message', response.text)
|
|
239
|
+
raise Exception(f"Clear values failed with status {response.status_code}: {error_message}")
|
|
240
|
+
except (json.JSONDecodeError, ValueError):
|
|
241
|
+
response.raise_for_status()
|
|
164
242
|
|
|
165
243
|
# Step 2: full refresh - Reframe data from Delta tables
|
|
166
244
|
print(" Step 2: Full refresh to reframe data...")
|
|
@@ -175,7 +253,7 @@ def refresh_dataset(dataset_name, workspace_id, client, dataset_id=None):
|
|
|
175
253
|
response = requests.post(powerbi_url, headers=headers, json=full_payload)
|
|
176
254
|
|
|
177
255
|
if response.status_code in [200, 202]:
|
|
178
|
-
print(f"✓ Refresh initiated")
|
|
256
|
+
print(f" ✓ Refresh initiated")
|
|
179
257
|
|
|
180
258
|
# For 202, get the refresh_id from the Location header
|
|
181
259
|
if response.status_code == 202:
|
|
@@ -207,7 +285,13 @@ def refresh_dataset(dataset_name, workspace_id, client, dataset_id=None):
|
|
|
207
285
|
|
|
208
286
|
raise Exception(f"Refresh timed out")
|
|
209
287
|
else:
|
|
210
|
-
|
|
288
|
+
# Provide detailed error message
|
|
289
|
+
try:
|
|
290
|
+
error_details = response.json()
|
|
291
|
+
error_message = error_details.get('error', {}).get('message', response.text)
|
|
292
|
+
raise Exception(f"Refresh request failed with status {response.status_code}: {error_message}")
|
|
293
|
+
except (json.JSONDecodeError, ValueError):
|
|
294
|
+
response.raise_for_status()
|
|
211
295
|
|
|
212
296
|
|
|
213
297
|
def download_bim_from_github(url_or_path):
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
duckrun/__init__.py,sha256=vqv_bJjHjrrXGs8Zyxuy-GKTCyJlZ5z3npPQgE9ipBY,355
|
|
2
2
|
duckrun/auth.py,sha256=EMaf-L2zeNOjbHOT97xYxfZNfWo4WrwrU1h3vBQTgEc,9624
|
|
3
|
-
duckrun/core.py,sha256=
|
|
3
|
+
duckrun/core.py,sha256=irIepj0d-4J7Er5YeQIaOZQuycBYQ1FSNmTEBgaGVm4,68270
|
|
4
4
|
duckrun/files.py,sha256=Fvdjg3DyHJzIVzKo8M_j-eGz4zU61lOB38Y_onbQJkI,10137
|
|
5
5
|
duckrun/lakehouse.py,sha256=j--Z3zo8AOWt1GF9VzRosmmTAy6ey2D0LVubti58twU,14109
|
|
6
6
|
duckrun/notebook.py,sha256=SzdKTpvzHiWMrvg7mCd3DN6R4gU_6Gm7gfkuETzylaE,12103
|
|
7
7
|
duckrun/runner.py,sha256=NGVyerJA44UP2umRdndfL0fuFM_gdOZmuJUz-PLOFf0,13461
|
|
8
|
-
duckrun/semantic_model.py,sha256=
|
|
8
|
+
duckrun/semantic_model.py,sha256=kc-g97A-Lbsa1H89EtumZTUPmGYN2uXhspGbG6ZuG2M,35049
|
|
9
9
|
duckrun/stats.py,sha256=qvWnPk2P8Ob_tzaiNfdQmUQqMVq2FWv3EgArE7hPl44,15482
|
|
10
10
|
duckrun/writer.py,sha256=wIsU77DSj4J7d9_bIhvk6AbC51uUrLW0e6pcSPQOY1c,9424
|
|
11
|
-
duckrun-0.2.18.
|
|
12
|
-
duckrun-0.2.18.
|
|
13
|
-
duckrun-0.2.18.
|
|
14
|
-
duckrun-0.2.18.
|
|
15
|
-
duckrun-0.2.18.
|
|
11
|
+
duckrun-0.2.18.dev3.dist-info/licenses/LICENSE,sha256=-DeQQwdbCbkB4507ZF3QbocysB-EIjDtaLexvqRkGZc,1083
|
|
12
|
+
duckrun-0.2.18.dev3.dist-info/METADATA,sha256=tGhjPWM7NxHEQQbBp_PkSWNamMXJwJ92Ns8Qfse8TXs,20807
|
|
13
|
+
duckrun-0.2.18.dev3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
14
|
+
duckrun-0.2.18.dev3.dist-info/top_level.txt,sha256=BknMEwebbUHrVAp3SC92ps8MPhK7XSYsaogTvi_DmEU,8
|
|
15
|
+
duckrun-0.2.18.dev3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|