duckrun 0.2.10__tar.gz → 0.2.10.dev1__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.
Potentially problematic release.
This version of duckrun might be problematic. Click here for more details.
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/PKG-INFO +1 -1
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun/core.py +146 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun.egg-info/PKG-INFO +1 -1
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/pyproject.toml +1 -1
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/LICENSE +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/README.md +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun/__init__.py +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun/auth.py +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun/files.py +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun/lakehouse.py +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun/runner.py +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun/semantic_model.py +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun/stats.py +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun/writer.py +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun.egg-info/SOURCES.txt +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun.egg-info/dependency_links.txt +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun.egg-info/requires.txt +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/duckrun.egg-info/top_level.txt +0 -0
- {duckrun-0.2.10 → duckrun-0.2.10.dev1}/setup.cfg +0 -0
|
@@ -94,6 +94,7 @@ class Duckrun:
|
|
|
94
94
|
pass # Not in Colab, use default transport
|
|
95
95
|
|
|
96
96
|
self._attach_lakehouse()
|
|
97
|
+
self._register_lookup_functions()
|
|
97
98
|
|
|
98
99
|
@classmethod
|
|
99
100
|
def connect(cls, connection_string: str, sql_folder: Optional[str] = None,
|
|
@@ -457,6 +458,151 @@ class Duckrun:
|
|
|
457
458
|
print(f"❌ Error attaching lakehouse: {e}")
|
|
458
459
|
print("Continuing without pre-attached tables.")
|
|
459
460
|
|
|
461
|
+
def _register_lookup_functions(self):
|
|
462
|
+
"""
|
|
463
|
+
Register Fabric API lookup functions as DuckDB UDFs.
|
|
464
|
+
Allows SQL queries to resolve workspace/lakehouse names from IDs and vice versa.
|
|
465
|
+
|
|
466
|
+
Functions registered:
|
|
467
|
+
- get_workspace_name(workspace_id) -> str
|
|
468
|
+
- get_lakehouse_name(workspace_id, lakehouse_id) -> str
|
|
469
|
+
- get_workspace_id_from_name(workspace_name) -> str
|
|
470
|
+
- get_lakehouse_id_from_name(workspace_id, lakehouse_name) -> str
|
|
471
|
+
"""
|
|
472
|
+
# Cache to avoid repeated API calls
|
|
473
|
+
self._name_cache = {
|
|
474
|
+
'workspace_id_to_name': {},
|
|
475
|
+
'workspace_name_to_id': {},
|
|
476
|
+
'lakehouse_id_to_name': {},
|
|
477
|
+
'lakehouse_name_to_id': {}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
def get_workspace_name(workspace_id: str) -> str:
|
|
481
|
+
"""Get workspace display name from workspace ID (GUID)"""
|
|
482
|
+
if workspace_id in self._name_cache['workspace_id_to_name']:
|
|
483
|
+
return self._name_cache['workspace_id_to_name'][workspace_id]
|
|
484
|
+
|
|
485
|
+
try:
|
|
486
|
+
from .auth import get_fabric_api_token
|
|
487
|
+
token = get_fabric_api_token()
|
|
488
|
+
if not token:
|
|
489
|
+
return None
|
|
490
|
+
|
|
491
|
+
url = "https://api.fabric.microsoft.com/v1/workspaces"
|
|
492
|
+
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
|
493
|
+
response = requests.get(url, headers=headers)
|
|
494
|
+
response.raise_for_status()
|
|
495
|
+
|
|
496
|
+
workspaces = response.json().get("value", [])
|
|
497
|
+
for workspace in workspaces:
|
|
498
|
+
if workspace.get("id") == workspace_id:
|
|
499
|
+
name = workspace.get("displayName", "")
|
|
500
|
+
self._name_cache['workspace_id_to_name'][workspace_id] = name
|
|
501
|
+
self._name_cache['workspace_name_to_id'][name] = workspace_id
|
|
502
|
+
return name
|
|
503
|
+
|
|
504
|
+
return None
|
|
505
|
+
except Exception as e:
|
|
506
|
+
return None
|
|
507
|
+
|
|
508
|
+
def get_lakehouse_name(workspace_id: str, lakehouse_id: str) -> str:
|
|
509
|
+
"""Get lakehouse display name from workspace ID and lakehouse ID (GUIDs)"""
|
|
510
|
+
cache_key = f"{workspace_id}/{lakehouse_id}"
|
|
511
|
+
if cache_key in self._name_cache['lakehouse_id_to_name']:
|
|
512
|
+
return self._name_cache['lakehouse_id_to_name'][cache_key]
|
|
513
|
+
|
|
514
|
+
try:
|
|
515
|
+
from .auth import get_fabric_api_token
|
|
516
|
+
token = get_fabric_api_token()
|
|
517
|
+
if not token:
|
|
518
|
+
return None
|
|
519
|
+
|
|
520
|
+
url = f"https://api.fabric.microsoft.com/v1/workspaces/{workspace_id}/lakehouses"
|
|
521
|
+
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
|
522
|
+
response = requests.get(url, headers=headers)
|
|
523
|
+
response.raise_for_status()
|
|
524
|
+
|
|
525
|
+
lakehouses = response.json().get("value", [])
|
|
526
|
+
for lakehouse in lakehouses:
|
|
527
|
+
if lakehouse.get("id") == lakehouse_id:
|
|
528
|
+
name = lakehouse.get("displayName", "")
|
|
529
|
+
self._name_cache['lakehouse_id_to_name'][cache_key] = name
|
|
530
|
+
lh_cache_key = f"{workspace_id}/{name}"
|
|
531
|
+
self._name_cache['lakehouse_name_to_id'][lh_cache_key] = lakehouse_id
|
|
532
|
+
return name
|
|
533
|
+
|
|
534
|
+
return None
|
|
535
|
+
except Exception as e:
|
|
536
|
+
return None
|
|
537
|
+
|
|
538
|
+
def get_workspace_id_from_name(workspace_name: str) -> str:
|
|
539
|
+
"""Get workspace ID (GUID) from workspace display name"""
|
|
540
|
+
if workspace_name in self._name_cache['workspace_name_to_id']:
|
|
541
|
+
return self._name_cache['workspace_name_to_id'][workspace_name]
|
|
542
|
+
|
|
543
|
+
try:
|
|
544
|
+
from .auth import get_fabric_api_token
|
|
545
|
+
token = get_fabric_api_token()
|
|
546
|
+
if not token:
|
|
547
|
+
return None
|
|
548
|
+
|
|
549
|
+
url = "https://api.fabric.microsoft.com/v1/workspaces"
|
|
550
|
+
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
|
551
|
+
response = requests.get(url, headers=headers)
|
|
552
|
+
response.raise_for_status()
|
|
553
|
+
|
|
554
|
+
workspaces = response.json().get("value", [])
|
|
555
|
+
for workspace in workspaces:
|
|
556
|
+
if workspace.get("displayName") == workspace_name:
|
|
557
|
+
workspace_id = workspace.get("id", "")
|
|
558
|
+
self._name_cache['workspace_name_to_id'][workspace_name] = workspace_id
|
|
559
|
+
self._name_cache['workspace_id_to_name'][workspace_id] = workspace_name
|
|
560
|
+
return workspace_id
|
|
561
|
+
|
|
562
|
+
return None
|
|
563
|
+
except Exception as e:
|
|
564
|
+
return None
|
|
565
|
+
|
|
566
|
+
def get_lakehouse_id_from_name(workspace_id: str, lakehouse_name: str) -> str:
|
|
567
|
+
"""Get lakehouse ID (GUID) from workspace ID and lakehouse display name"""
|
|
568
|
+
cache_key = f"{workspace_id}/{lakehouse_name}"
|
|
569
|
+
if cache_key in self._name_cache['lakehouse_name_to_id']:
|
|
570
|
+
return self._name_cache['lakehouse_name_to_id'][cache_key]
|
|
571
|
+
|
|
572
|
+
try:
|
|
573
|
+
from .auth import get_fabric_api_token
|
|
574
|
+
token = get_fabric_api_token()
|
|
575
|
+
if not token:
|
|
576
|
+
return None
|
|
577
|
+
|
|
578
|
+
url = f"https://api.fabric.microsoft.com/v1/workspaces/{workspace_id}/lakehouses"
|
|
579
|
+
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
|
580
|
+
response = requests.get(url, headers=headers)
|
|
581
|
+
response.raise_for_status()
|
|
582
|
+
|
|
583
|
+
lakehouses = response.json().get("value", [])
|
|
584
|
+
for lakehouse in lakehouses:
|
|
585
|
+
if lakehouse.get("displayName") == lakehouse_name:
|
|
586
|
+
lakehouse_id = lakehouse.get("id", "")
|
|
587
|
+
self._name_cache['lakehouse_name_to_id'][cache_key] = lakehouse_id
|
|
588
|
+
id_cache_key = f"{workspace_id}/{lakehouse_id}"
|
|
589
|
+
self._name_cache['lakehouse_id_to_name'][id_cache_key] = lakehouse_name
|
|
590
|
+
return lakehouse_id
|
|
591
|
+
|
|
592
|
+
return None
|
|
593
|
+
except Exception as e:
|
|
594
|
+
return None
|
|
595
|
+
|
|
596
|
+
# Register functions in DuckDB
|
|
597
|
+
try:
|
|
598
|
+
self.con.create_function("get_workspace_name", get_workspace_name)
|
|
599
|
+
self.con.create_function("get_lakehouse_name", get_lakehouse_name)
|
|
600
|
+
self.con.create_function("get_workspace_id_from_name", get_workspace_id_from_name)
|
|
601
|
+
self.con.create_function("get_lakehouse_id_from_name", get_lakehouse_id_from_name)
|
|
602
|
+
print("✅ Registered lookup functions: get_workspace_name, get_lakehouse_name, get_workspace_id_from_name, get_lakehouse_id_from_name")
|
|
603
|
+
except Exception as e:
|
|
604
|
+
print(f"⚠️ Warning: Could not register lookup functions: {e}")
|
|
605
|
+
|
|
460
606
|
def get_workspace_id(self) -> str:
|
|
461
607
|
"""
|
|
462
608
|
Get the workspace ID (GUID or name without spaces).
|
|
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
|