sql-glider 0.1.8__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.
@@ -0,0 +1,121 @@
1
+ """Catalog registry with plugin discovery via entry points.
2
+
3
+ This module handles discovering and instantiating catalog providers from
4
+ Python entry points, allowing third-party packages to register
5
+ custom catalogs.
6
+ """
7
+
8
+ import sys
9
+ from typing import Dict, List, Type
10
+
11
+ from sqlglider.catalog.base import Catalog, CatalogError
12
+
13
+ # Cache for discovered catalogs
14
+ _catalog_cache: Dict[str, Type[Catalog]] = {}
15
+ _discovery_done: bool = False
16
+
17
+
18
+ def _discover_catalogs() -> None:
19
+ """Discover catalogs from entry points.
20
+
21
+ Uses importlib.metadata to find all registered catalogs
22
+ in the 'sqlglider.catalogs' entry point group.
23
+ """
24
+ global _discovery_done, _catalog_cache
25
+
26
+ if _discovery_done:
27
+ return
28
+
29
+ if sys.version_info >= (3, 10):
30
+ from importlib.metadata import entry_points
31
+
32
+ eps = entry_points(group="sqlglider.catalogs")
33
+ else:
34
+ from importlib.metadata import entry_points
35
+
36
+ all_eps = entry_points()
37
+ eps = all_eps.get("sqlglider.catalogs", [])
38
+
39
+ for ep in eps:
40
+ try:
41
+ catalog_class = ep.load()
42
+ if isinstance(catalog_class, type) and issubclass(catalog_class, Catalog):
43
+ _catalog_cache[ep.name] = catalog_class
44
+ except Exception:
45
+ # Skip catalogs that fail to load
46
+ # This allows graceful handling of missing optional dependencies
47
+ pass
48
+
49
+ _discovery_done = True
50
+
51
+
52
+ def get_catalog(name: str) -> Catalog:
53
+ """Get a catalog instance by name.
54
+
55
+ Args:
56
+ name: The name of the catalog (e.g., "databricks").
57
+
58
+ Returns:
59
+ An instance of the requested catalog.
60
+
61
+ Raises:
62
+ CatalogError: If the catalog is not found.
63
+
64
+ Example:
65
+ >>> catalog = get_catalog("databricks")
66
+ >>> ddl = catalog.get_ddl("my_catalog.my_schema.my_table")
67
+ """
68
+ _discover_catalogs()
69
+
70
+ if name not in _catalog_cache:
71
+ available = ", ".join(sorted(_catalog_cache.keys()))
72
+ raise CatalogError(
73
+ f"Unknown catalog '{name}'. Available catalogs: {available or 'none'}. "
74
+ f"You may need to install an optional dependency (e.g., pip install sql-glider[databricks])."
75
+ )
76
+
77
+ return _catalog_cache[name]()
78
+
79
+
80
+ def list_catalogs() -> List[str]:
81
+ """List all available catalog names.
82
+
83
+ Returns:
84
+ A sorted list of available catalog names.
85
+
86
+ Example:
87
+ >>> catalogs = list_catalogs()
88
+ >>> print(catalogs)
89
+ ['databricks']
90
+ """
91
+ _discover_catalogs()
92
+ return sorted(_catalog_cache.keys())
93
+
94
+
95
+ def register_catalog(name: str, catalog_class: Type[Catalog]) -> None:
96
+ """Register a catalog programmatically.
97
+
98
+ This is primarily useful for testing or for registering catalogs
99
+ that aren't installed via entry points.
100
+
101
+ Args:
102
+ name: The name to register the catalog under.
103
+ catalog_class: The catalog class to register.
104
+
105
+ Raises:
106
+ ValueError: If catalog_class is not a subclass of Catalog.
107
+ """
108
+ if not isinstance(catalog_class, type) or not issubclass(catalog_class, Catalog):
109
+ raise ValueError(f"{catalog_class} must be a subclass of Catalog")
110
+
111
+ _catalog_cache[name] = catalog_class
112
+
113
+
114
+ def clear_registry() -> None:
115
+ """Clear the catalog registry.
116
+
117
+ This is primarily useful for testing.
118
+ """
119
+ global _discovery_done, _catalog_cache
120
+ _catalog_cache.clear()
121
+ _discovery_done = False