sqlspec 0.21.1__py3-none-any.whl → 0.22.0__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 sqlspec might be problematic. Click here for more details.
- sqlspec/base.py +4 -4
- sqlspec/loader.py +65 -68
- sqlspec/protocols.py +3 -5
- sqlspec/storage/__init__.py +2 -12
- sqlspec/storage/backends/__init__.py +1 -0
- sqlspec/storage/backends/fsspec.py +87 -147
- sqlspec/storage/backends/local.py +310 -0
- sqlspec/storage/backends/obstore.py +210 -192
- sqlspec/storage/registry.py +101 -70
- sqlspec/utils/sync_tools.py +8 -5
- {sqlspec-0.21.1.dist-info → sqlspec-0.22.0.dist-info}/METADATA +1 -1
- {sqlspec-0.21.1.dist-info → sqlspec-0.22.0.dist-info}/RECORD +16 -16
- sqlspec/storage/capabilities.py +0 -102
- {sqlspec-0.21.1.dist-info → sqlspec-0.22.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.21.1.dist-info → sqlspec-0.22.0.dist-info}/entry_points.txt +0 -0
- {sqlspec-0.21.1.dist-info → sqlspec-0.22.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.21.1.dist-info → sqlspec-0.22.0.dist-info}/licenses/NOTICE +0 -0
sqlspec/storage/registry.py
CHANGED
|
@@ -14,7 +14,6 @@ from mypy_extensions import mypyc_attr
|
|
|
14
14
|
|
|
15
15
|
from sqlspec.exceptions import ImproperConfigurationError, MissingDependencyError
|
|
16
16
|
from sqlspec.protocols import ObjectStoreProtocol
|
|
17
|
-
from sqlspec.storage.capabilities import StorageCapabilities
|
|
18
17
|
from sqlspec.typing import FSSPEC_INSTALLED, OBSTORE_INSTALLED
|
|
19
18
|
|
|
20
19
|
__all__ = ("StorageRegistry", "storage_registry")
|
|
@@ -22,34 +21,52 @@ __all__ = ("StorageRegistry", "storage_registry")
|
|
|
22
21
|
logger = logging.getLogger(__name__)
|
|
23
22
|
|
|
24
23
|
|
|
24
|
+
def _is_local_uri(uri: str) -> bool:
|
|
25
|
+
"""Check if URI represents a local filesystem path."""
|
|
26
|
+
if "://" in uri and not uri.startswith("file://"):
|
|
27
|
+
return False
|
|
28
|
+
windows_drive_min_length = 3
|
|
29
|
+
return (
|
|
30
|
+
Path(uri).exists()
|
|
31
|
+
or Path(uri).is_absolute()
|
|
32
|
+
or uri.startswith(("~", ".", "/"))
|
|
33
|
+
or (len(uri) >= windows_drive_min_length and uri[1:3] == ":\\")
|
|
34
|
+
or "/" in uri
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
25
38
|
SCHEME_REGEX: Final = re.compile(r"([a-zA-Z0-9+.-]+)://")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
GCS_PROTOCOL: Final[str] = "gs"
|
|
29
|
-
AZURE_PROTOCOL: Final[str] = "az"
|
|
39
|
+
|
|
40
|
+
|
|
30
41
|
FSSPEC_ONLY_SCHEMES: Final[frozenset[str]] = frozenset({"http", "https", "ftp", "sftp", "ssh"})
|
|
31
42
|
|
|
32
43
|
|
|
33
44
|
@mypyc_attr(allow_interpreted_subclasses=True)
|
|
34
45
|
class StorageRegistry:
|
|
35
|
-
"""
|
|
46
|
+
"""Global storage registry for named backend configurations.
|
|
36
47
|
|
|
37
|
-
|
|
38
|
-
|
|
48
|
+
Allows registering named storage backends that can be accessed from anywhere
|
|
49
|
+
in your application. Backends are automatically selected based on URI scheme
|
|
50
|
+
unless explicitly overridden.
|
|
39
51
|
|
|
40
52
|
Examples:
|
|
41
|
-
|
|
42
|
-
backend = registry.get("
|
|
43
|
-
backend = registry.get("
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
+
# Direct URI access to storage containers
|
|
54
|
+
backend = registry.get("s3://my-bucket")
|
|
55
|
+
backend = registry.get("file:///tmp/data")
|
|
56
|
+
backend = registry.get("gs://my-gcs-bucket")
|
|
57
|
+
|
|
58
|
+
# Named store pattern for environment-specific backends
|
|
59
|
+
# Development
|
|
60
|
+
registry.register_alias("my_app_store", "file:///tmp/dev_data")
|
|
61
|
+
|
|
62
|
+
# Production
|
|
63
|
+
registry.register_alias("my_app_store", "s3://prod-bucket/data")
|
|
64
|
+
|
|
65
|
+
# Access from anywhere in your app
|
|
66
|
+
store = registry.get("my_app_store") # Works in both environments
|
|
67
|
+
|
|
68
|
+
# Force specific backend when multiple options available
|
|
69
|
+
backend = registry.get("s3://bucket", backend="fsspec") # Force fsspec over obstore
|
|
53
70
|
"""
|
|
54
71
|
|
|
55
72
|
__slots__ = ("_alias_configs", "_aliases", "_cache", "_instances")
|
|
@@ -60,44 +77,47 @@ class StorageRegistry:
|
|
|
60
77
|
self._instances: dict[Union[str, tuple[str, tuple[tuple[str, Any], ...]]], ObjectStoreProtocol] = {}
|
|
61
78
|
self._cache: dict[str, tuple[str, type[ObjectStoreProtocol]]] = {}
|
|
62
79
|
|
|
80
|
+
def _make_hashable(self, obj: Any) -> Any:
|
|
81
|
+
"""Convert nested dict/list structures to hashable tuples."""
|
|
82
|
+
if isinstance(obj, dict):
|
|
83
|
+
return tuple(sorted((k, self._make_hashable(v)) for k, v in obj.items()))
|
|
84
|
+
if isinstance(obj, list):
|
|
85
|
+
return tuple(self._make_hashable(item) for item in obj)
|
|
86
|
+
if isinstance(obj, set):
|
|
87
|
+
return tuple(sorted(self._make_hashable(item) for item in obj))
|
|
88
|
+
return obj
|
|
89
|
+
|
|
63
90
|
def register_alias(
|
|
64
|
-
self,
|
|
65
|
-
alias: str,
|
|
66
|
-
uri: str,
|
|
67
|
-
*,
|
|
68
|
-
backend: Optional[type[ObjectStoreProtocol]] = None,
|
|
69
|
-
base_path: str = "",
|
|
70
|
-
config: Optional[dict[str, Any]] = None,
|
|
71
|
-
**kwargs: Any,
|
|
91
|
+
self, alias: str, uri: str, *, backend: Optional[str] = None, base_path: str = "", **kwargs: Any
|
|
72
92
|
) -> None:
|
|
73
93
|
"""Register a named alias for a storage configuration.
|
|
74
94
|
|
|
75
95
|
Args:
|
|
76
|
-
alias: Unique alias name
|
|
77
|
-
uri: Storage URI (e.g., "s3://bucket", "file:///path")
|
|
78
|
-
backend:
|
|
96
|
+
alias: Unique alias name (e.g., "my_app_store", "user_uploads")
|
|
97
|
+
uri: Storage URI (e.g., "s3://bucket", "file:///path", "gs://bucket")
|
|
98
|
+
backend: Force specific backend ("local", "fsspec", "obstore") instead of auto-detection
|
|
79
99
|
base_path: Base path to prepend to all operations
|
|
80
|
-
config: Additional configuration dict
|
|
81
100
|
**kwargs: Backend-specific configuration options
|
|
82
101
|
"""
|
|
83
|
-
if backend
|
|
84
|
-
backend = self._determine_backend_class(uri)
|
|
102
|
+
backend_cls = self._get_backend_class(backend) if backend else self._determine_backend_class(uri)
|
|
85
103
|
|
|
86
|
-
|
|
87
|
-
config.update(kwargs)
|
|
88
|
-
backend_config = dict(config)
|
|
104
|
+
backend_config = dict(kwargs)
|
|
89
105
|
if base_path:
|
|
90
106
|
backend_config["base_path"] = base_path
|
|
91
|
-
self._alias_configs[alias] = (
|
|
107
|
+
self._alias_configs[alias] = (backend_cls, uri, backend_config)
|
|
108
|
+
|
|
92
109
|
test_config = dict(backend_config)
|
|
93
110
|
test_config["uri"] = uri
|
|
94
111
|
self._aliases[alias] = test_config
|
|
95
112
|
|
|
96
|
-
def get(
|
|
113
|
+
def get(
|
|
114
|
+
self, uri_or_alias: Union[str, Path], *, backend: Optional[str] = None, **kwargs: Any
|
|
115
|
+
) -> ObjectStoreProtocol:
|
|
97
116
|
"""Get backend instance using URI-first routing with automatic backend selection.
|
|
98
117
|
|
|
99
118
|
Args:
|
|
100
|
-
uri_or_alias: URI to resolve directly OR named alias
|
|
119
|
+
uri_or_alias: URI to resolve directly OR named alias (e.g., "my_app_store")
|
|
120
|
+
backend: Force specific backend ("local", "fsspec", "obstore") instead of auto-selection
|
|
101
121
|
**kwargs: Additional backend-specific configuration options
|
|
102
122
|
|
|
103
123
|
Returns:
|
|
@@ -113,24 +133,20 @@ class StorageRegistry:
|
|
|
113
133
|
if isinstance(uri_or_alias, Path):
|
|
114
134
|
uri_or_alias = f"file://{uri_or_alias.resolve()}"
|
|
115
135
|
|
|
116
|
-
cache_key = (uri_or_alias,
|
|
136
|
+
cache_key = (uri_or_alias, self._make_hashable(kwargs)) if kwargs else uri_or_alias
|
|
117
137
|
if cache_key in self._instances:
|
|
118
138
|
return self._instances[cache_key]
|
|
119
139
|
scheme = self._get_scheme(uri_or_alias)
|
|
120
|
-
if not scheme and (
|
|
121
|
-
Path(uri_or_alias).exists()
|
|
122
|
-
or Path(uri_or_alias).is_absolute()
|
|
123
|
-
or uri_or_alias.startswith(("~", "."))
|
|
124
|
-
or ":\\" in uri_or_alias
|
|
125
|
-
or "/" in uri_or_alias
|
|
126
|
-
):
|
|
140
|
+
if not scheme and _is_local_uri(uri_or_alias):
|
|
127
141
|
scheme = "file"
|
|
128
142
|
uri_or_alias = f"file://{uri_or_alias}"
|
|
129
143
|
|
|
130
144
|
if scheme:
|
|
131
|
-
instance = self._resolve_from_uri(uri_or_alias, **kwargs)
|
|
145
|
+
instance = self._resolve_from_uri(uri_or_alias, backend_override=backend, **kwargs)
|
|
132
146
|
elif uri_or_alias in self._alias_configs:
|
|
133
147
|
backend_cls, stored_uri, config = self._alias_configs[uri_or_alias]
|
|
148
|
+
if backend:
|
|
149
|
+
backend_cls = self._get_backend_class(backend)
|
|
134
150
|
instance = backend_cls(stored_uri, **{**config, **kwargs})
|
|
135
151
|
else:
|
|
136
152
|
msg = f"Unknown storage alias or invalid URI: '{uri_or_alias}'"
|
|
@@ -138,36 +154,66 @@ class StorageRegistry:
|
|
|
138
154
|
self._instances[cache_key] = instance
|
|
139
155
|
return instance
|
|
140
156
|
|
|
141
|
-
def _resolve_from_uri(
|
|
142
|
-
|
|
157
|
+
def _resolve_from_uri(
|
|
158
|
+
self, uri: str, *, backend_override: Optional[str] = None, **kwargs: Any
|
|
159
|
+
) -> ObjectStoreProtocol:
|
|
160
|
+
"""Resolve backend from URI with optional backend override."""
|
|
161
|
+
if backend_override:
|
|
162
|
+
return self._create_backend(backend_override, uri, **kwargs)
|
|
143
163
|
scheme = self._get_scheme(uri)
|
|
164
|
+
|
|
165
|
+
# For local files, prefer LocalStore first
|
|
166
|
+
if scheme in {None, "file"}:
|
|
167
|
+
return self._create_backend("local", uri, **kwargs)
|
|
168
|
+
|
|
169
|
+
# Try ObStore first if available and appropriate
|
|
144
170
|
if scheme not in FSSPEC_ONLY_SCHEMES and OBSTORE_INSTALLED:
|
|
145
171
|
try:
|
|
146
172
|
return self._create_backend("obstore", uri, **kwargs)
|
|
147
173
|
except (ValueError, ImportError, NotImplementedError):
|
|
148
174
|
pass
|
|
175
|
+
|
|
176
|
+
# Try FSSpec if available
|
|
149
177
|
if FSSPEC_INSTALLED:
|
|
150
178
|
try:
|
|
151
179
|
return self._create_backend("fsspec", uri, **kwargs)
|
|
152
180
|
except (ValueError, ImportError, NotImplementedError):
|
|
153
181
|
pass
|
|
154
|
-
|
|
155
|
-
|
|
182
|
+
|
|
183
|
+
# For cloud schemes without backends, provide helpful error
|
|
184
|
+
msg = f"No backend available for URI scheme '{scheme}'. Install obstore or fsspec for cloud storage support."
|
|
185
|
+
raise MissingDependencyError(msg)
|
|
156
186
|
|
|
157
187
|
def _determine_backend_class(self, uri: str) -> type[ObjectStoreProtocol]:
|
|
158
188
|
"""Determine the backend class for a URI based on availability."""
|
|
159
189
|
scheme = self._get_scheme(uri)
|
|
190
|
+
|
|
191
|
+
# For local files, always use LocalStore
|
|
192
|
+
if scheme in {None, "file"}:
|
|
193
|
+
return self._get_backend_class("local")
|
|
194
|
+
|
|
195
|
+
# FSSpec-only schemes require FSSpec
|
|
160
196
|
if scheme in FSSPEC_ONLY_SCHEMES and FSSPEC_INSTALLED:
|
|
161
197
|
return self._get_backend_class("fsspec")
|
|
198
|
+
|
|
199
|
+
# Prefer ObStore for cloud storage if available
|
|
162
200
|
if OBSTORE_INSTALLED:
|
|
163
201
|
return self._get_backend_class("obstore")
|
|
202
|
+
|
|
203
|
+
# Fall back to FSSpec if available
|
|
164
204
|
if FSSPEC_INSTALLED:
|
|
165
205
|
return self._get_backend_class("fsspec")
|
|
166
|
-
|
|
206
|
+
|
|
207
|
+
# For cloud schemes without backends, provide helpful error
|
|
208
|
+
msg = f"No backend available for URI scheme '{scheme}'. Install obstore or fsspec for cloud storage support."
|
|
167
209
|
raise MissingDependencyError(msg)
|
|
168
210
|
|
|
169
211
|
def _get_backend_class(self, backend_type: str) -> type[ObjectStoreProtocol]:
|
|
170
212
|
"""Get backend class by type name."""
|
|
213
|
+
if backend_type == "local":
|
|
214
|
+
from sqlspec.storage.backends.local import LocalStore
|
|
215
|
+
|
|
216
|
+
return cast("type[ObjectStoreProtocol]", LocalStore)
|
|
171
217
|
if backend_type == "obstore":
|
|
172
218
|
from sqlspec.storage.backends.obstore import ObStoreBackend
|
|
173
219
|
|
|
@@ -176,7 +222,7 @@ class StorageRegistry:
|
|
|
176
222
|
from sqlspec.storage.backends.fsspec import FSSpecBackend
|
|
177
223
|
|
|
178
224
|
return cast("type[ObjectStoreProtocol]", FSSpecBackend)
|
|
179
|
-
msg = f"Unknown backend type: {backend_type}. Supported types: 'obstore', 'fsspec'"
|
|
225
|
+
msg = f"Unknown backend type: {backend_type}. Supported types: 'local', 'obstore', 'fsspec'"
|
|
180
226
|
raise ValueError(msg)
|
|
181
227
|
|
|
182
228
|
def _create_backend(self, backend_type: str, uri: str, **kwargs: Any) -> ObjectStoreProtocol:
|
|
@@ -220,20 +266,5 @@ class StorageRegistry:
|
|
|
220
266
|
self._alias_configs.clear()
|
|
221
267
|
self._aliases.clear()
|
|
222
268
|
|
|
223
|
-
def get_backend_capabilities(self, uri_or_alias: Union[str, Path]) -> "StorageCapabilities":
|
|
224
|
-
"""Get capabilities for a backend without creating an instance."""
|
|
225
|
-
if isinstance(uri_or_alias, Path):
|
|
226
|
-
uri_or_alias = f"file://{uri_or_alias.resolve()}"
|
|
227
|
-
if "://" in uri_or_alias:
|
|
228
|
-
backend_cls = self._determine_backend_class(uri_or_alias)
|
|
229
|
-
elif uri_or_alias in self._alias_configs:
|
|
230
|
-
backend_cls, _, _ = self._alias_configs[uri_or_alias]
|
|
231
|
-
else:
|
|
232
|
-
msg = f"Unknown storage alias or invalid URI: '{uri_or_alias}'"
|
|
233
|
-
raise ImproperConfigurationError(msg)
|
|
234
|
-
if hasattr(backend_cls, "capabilities"):
|
|
235
|
-
return backend_cls.capabilities
|
|
236
|
-
return StorageCapabilities()
|
|
237
|
-
|
|
238
269
|
|
|
239
270
|
storage_registry = StorageRegistry()
|
sqlspec/utils/sync_tools.py
CHANGED
|
@@ -29,6 +29,13 @@ ParamSpecT = ParamSpec("ParamSpecT")
|
|
|
29
29
|
T = TypeVar("T")
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
class NoValue:
|
|
33
|
+
"""Sentinel class for missing values."""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
NO_VALUE = NoValue()
|
|
37
|
+
|
|
38
|
+
|
|
32
39
|
class CapacityLimiter:
|
|
33
40
|
"""Limits the number of concurrent operations using a semaphore."""
|
|
34
41
|
|
|
@@ -240,11 +247,7 @@ def with_ensure_async_(
|
|
|
240
247
|
return obj
|
|
241
248
|
|
|
242
249
|
|
|
243
|
-
|
|
244
|
-
"""Sentinel class for missing values."""
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
async def get_next(iterable: Any, default: Any = NoValue, *args: Any) -> Any: # pragma: no cover
|
|
250
|
+
async def get_next(iterable: Any, default: Any = NO_VALUE, *args: Any) -> Any: # pragma: no cover
|
|
248
251
|
"""Return the next item from an async iterator.
|
|
249
252
|
|
|
250
253
|
Args:
|
|
@@ -4,12 +4,12 @@ sqlspec/__metadata__.py,sha256=IUw6MCTy1oeUJ1jAVYbuJLkOWbiAWorZ5W-E-SAD9N4,395
|
|
|
4
4
|
sqlspec/_serialization.py,sha256=6U5-smk2h2yl0i6am2prtOLJTdu4NJQdcLlSfSUMaUQ,2590
|
|
5
5
|
sqlspec/_sql.py,sha256=j9WljOgCme4jTfL6NegEWOhK-Rr3JEmhtbneh8ZN1bQ,45221
|
|
6
6
|
sqlspec/_typing.py,sha256=jv-7QHGLrJLfnP86bR-Xcmj3PDoddNZEKDz_vYRBiAU,22684
|
|
7
|
-
sqlspec/base.py,sha256=
|
|
7
|
+
sqlspec/base.py,sha256=koDh1AecwCAkntSqSda6J_cpMOLonXiV6hh3GCCXf_s,25459
|
|
8
8
|
sqlspec/cli.py,sha256=Fe5Wbnrb_fkE9qm4gbBEXx3d0Q7VR-S-1t76ouAx2mg,20120
|
|
9
9
|
sqlspec/config.py,sha256=PQKKLXst_uMvqvTSQib6qMZfJd-g3Kqqlp7XLn9kA8A,21640
|
|
10
10
|
sqlspec/exceptions.py,sha256=zBnzQOfYAgqX04GoaC9Io6ardzinldkEuZ3YtR5vr9U,6071
|
|
11
|
-
sqlspec/loader.py,sha256=
|
|
12
|
-
sqlspec/protocols.py,sha256=
|
|
11
|
+
sqlspec/loader.py,sha256=4Gl4LcdVwEB6-4F-KiCnlI3nzyG3LVOFvRMAQNC64qE,23748
|
|
12
|
+
sqlspec/protocols.py,sha256=jSO2OeZvywqkaIvLRFDkQajJvDlErCICipToUH3Mvoo,12996
|
|
13
13
|
sqlspec/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
sqlspec/typing.py,sha256=yj8D8O-pkfUVZDfVHEgQaB95-5alwgQbp_sqNJOVhvQ,6301
|
|
15
15
|
sqlspec/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -112,13 +112,13 @@ sqlspec/migrations/loaders.py,sha256=wildbpkyHrE--HXspChPOajSHSBUrfG0e6xQ2buze_4
|
|
|
112
112
|
sqlspec/migrations/runner.py,sha256=y6fyZi02n8MseKR8XFWXUEOOYQNG_w_DikHVxH9p20M,10730
|
|
113
113
|
sqlspec/migrations/tracker.py,sha256=hfrZGz8M70SfFniw4aXVtHNg4p8EPFm67vthjfUMUys,6843
|
|
114
114
|
sqlspec/migrations/utils.py,sha256=Ft5mS1GFiRPLhfUTfPU4ZnEgOkXDnmEHjeeWwfZDcv4,3737
|
|
115
|
-
sqlspec/storage/__init__.py,sha256=
|
|
116
|
-
sqlspec/storage/
|
|
117
|
-
sqlspec/storage/
|
|
118
|
-
sqlspec/storage/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
115
|
+
sqlspec/storage/__init__.py,sha256=IX7xLuymGdQKOBQL1sNEA-bzZRJGjncUbQbs6ZToDDE,395
|
|
116
|
+
sqlspec/storage/registry.py,sha256=yJZrLDu1vr86C6En3MlzCPOjUNYkvA5Ow-AKrLEDvpI,10754
|
|
117
|
+
sqlspec/storage/backends/__init__.py,sha256=3oSqwEQ_trU2QoxtUTX-5IFeOvo7WGcESY6gIfcmSaE,24
|
|
119
118
|
sqlspec/storage/backends/base.py,sha256=KS2JRZILoH_R_xsfKtYkqQ5a1r5OOBDSE5KbibTmhGY,5730
|
|
120
|
-
sqlspec/storage/backends/fsspec.py,sha256=
|
|
121
|
-
sqlspec/storage/backends/
|
|
119
|
+
sqlspec/storage/backends/fsspec.py,sha256=5X3QhoaAddzMqkeTHs8M5RINj3mrHcnaIVWb8VhC4lQ,13582
|
|
120
|
+
sqlspec/storage/backends/local.py,sha256=vsFnttNesNYjsY_l-KoH6rld51L3E6mxeODtMJawFPQ,12793
|
|
121
|
+
sqlspec/storage/backends/obstore.py,sha256=4RUZAMCF16h1IQ4dEib-0j8TLnhPf0Jhy2lmRJSe7Kw,20512
|
|
122
122
|
sqlspec/utils/__init__.py,sha256=cNFX26-bLyZTyTfujUitfDkUy1CeG_d-EIr8kZ0z4W8,474
|
|
123
123
|
sqlspec/utils/correlation.py,sha256=2jvkAY3nkU3UxNU_9pbBR6cz3A1Q1cGG9IaWSSOIb1Q,4195
|
|
124
124
|
sqlspec/utils/data_transformation.py,sha256=U37zyxR4f5PxsxKdC7QzcMyJxfqpsXUxgH_ch5l3PbY,3951
|
|
@@ -128,12 +128,12 @@ sqlspec/utils/logging.py,sha256=zAM7rHJ-KsmAj1yjvU9QFoiwf4Q2hKTere2J62FlllI,3664
|
|
|
128
128
|
sqlspec/utils/module_loader.py,sha256=rO4ht-fUSJ3Us7L_7fb_G9bdMCoUSABGUA0pc3ouh9Y,2995
|
|
129
129
|
sqlspec/utils/serializers.py,sha256=GXsTkJbWAhRS7xDMk6WBouZwPeG4sI_brLdMBlIetNg,318
|
|
130
130
|
sqlspec/utils/singleton.py,sha256=-j-s6LS0pP_wTEUYIyK2wSdoeIE_tn7O7B-j7_aODRQ,1252
|
|
131
|
-
sqlspec/utils/sync_tools.py,sha256=
|
|
131
|
+
sqlspec/utils/sync_tools.py,sha256=ONdhmx1Dq0_c6ReRaTlXzz6dVmAwz6CybCvsTUAVu1g,8768
|
|
132
132
|
sqlspec/utils/text.py,sha256=ZqaXCVuUbdj_110pdTYjmAxfV3ZtR7J6EixuNazQLFY,3333
|
|
133
133
|
sqlspec/utils/type_guards.py,sha256=ktXwBQLLqOvk1W2wJcmk3bUprrsegs8nAZ879qDe0AU,32880
|
|
134
|
-
sqlspec-0.
|
|
135
|
-
sqlspec-0.
|
|
136
|
-
sqlspec-0.
|
|
137
|
-
sqlspec-0.
|
|
138
|
-
sqlspec-0.
|
|
139
|
-
sqlspec-0.
|
|
134
|
+
sqlspec-0.22.0.dist-info/METADATA,sha256=DZJrWaO7T5jLPe2GlL6M_MmKveqCb-oU1Awx3CDm6J0,23548
|
|
135
|
+
sqlspec-0.22.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
136
|
+
sqlspec-0.22.0.dist-info/entry_points.txt,sha256=G-ZqY1Nuuw3Iys7nXw23f6ILenk_Lt47VdK2mhJCWHg,53
|
|
137
|
+
sqlspec-0.22.0.dist-info/licenses/LICENSE,sha256=MdujfZ6l5HuLz4mElxlu049itenOR3gnhN1_Nd3nVcM,1078
|
|
138
|
+
sqlspec-0.22.0.dist-info/licenses/NOTICE,sha256=Lyir8ozXWov7CyYS4huVaOCNrtgL17P-bNV-5daLntQ,1634
|
|
139
|
+
sqlspec-0.22.0.dist-info/RECORD,,
|
sqlspec/storage/capabilities.py
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
"""Storage backend capability system.
|
|
2
|
-
|
|
3
|
-
This module provides a centralized way to track and query storage backend capabilities.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from dataclasses import dataclass
|
|
7
|
-
from typing import ClassVar
|
|
8
|
-
|
|
9
|
-
from mypy_extensions import mypyc_attr
|
|
10
|
-
|
|
11
|
-
__all__ = ("HasStorageCapabilities", "StorageCapabilities")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@dataclass
|
|
15
|
-
class StorageCapabilities:
|
|
16
|
-
"""Tracks capabilities of a storage backend."""
|
|
17
|
-
|
|
18
|
-
supports_read: bool = True
|
|
19
|
-
supports_write: bool = True
|
|
20
|
-
supports_delete: bool = True
|
|
21
|
-
supports_list: bool = True
|
|
22
|
-
supports_exists: bool = True
|
|
23
|
-
supports_copy: bool = True
|
|
24
|
-
supports_move: bool = True
|
|
25
|
-
supports_metadata: bool = True
|
|
26
|
-
|
|
27
|
-
supports_arrow: bool = False
|
|
28
|
-
supports_streaming: bool = False
|
|
29
|
-
supports_async: bool = False
|
|
30
|
-
supports_batch_operations: bool = False
|
|
31
|
-
supports_multipart_upload: bool = False
|
|
32
|
-
supports_compression: bool = False
|
|
33
|
-
|
|
34
|
-
supports_s3_select: bool = False
|
|
35
|
-
supports_gcs_compose: bool = False
|
|
36
|
-
supports_azure_snapshots: bool = False
|
|
37
|
-
|
|
38
|
-
is_remote: bool = True
|
|
39
|
-
is_cloud_native: bool = False
|
|
40
|
-
has_low_latency: bool = False
|
|
41
|
-
|
|
42
|
-
@classmethod
|
|
43
|
-
def local_filesystem(cls) -> "StorageCapabilities":
|
|
44
|
-
"""Capabilities for local filesystem backend."""
|
|
45
|
-
return cls(
|
|
46
|
-
is_remote=False, has_low_latency=True, supports_arrow=True, supports_streaming=True, supports_async=True
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
@classmethod
|
|
50
|
-
def s3_compatible(cls) -> "StorageCapabilities":
|
|
51
|
-
"""Capabilities for S3-compatible backends."""
|
|
52
|
-
return cls(
|
|
53
|
-
is_cloud_native=True,
|
|
54
|
-
supports_multipart_upload=True,
|
|
55
|
-
supports_s3_select=True,
|
|
56
|
-
supports_arrow=True,
|
|
57
|
-
supports_streaming=True,
|
|
58
|
-
supports_async=True,
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
@classmethod
|
|
62
|
-
def gcs(cls) -> "StorageCapabilities":
|
|
63
|
-
"""Capabilities for Google Cloud Storage."""
|
|
64
|
-
return cls(
|
|
65
|
-
is_cloud_native=True,
|
|
66
|
-
supports_multipart_upload=True,
|
|
67
|
-
supports_gcs_compose=True,
|
|
68
|
-
supports_arrow=True,
|
|
69
|
-
supports_streaming=True,
|
|
70
|
-
supports_async=True,
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
@classmethod
|
|
74
|
-
def azure_blob(cls) -> "StorageCapabilities":
|
|
75
|
-
"""Capabilities for Azure Blob Storage."""
|
|
76
|
-
return cls(
|
|
77
|
-
is_cloud_native=True,
|
|
78
|
-
supports_multipart_upload=True,
|
|
79
|
-
supports_azure_snapshots=True,
|
|
80
|
-
supports_arrow=True,
|
|
81
|
-
supports_streaming=True,
|
|
82
|
-
supports_async=True,
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
@mypyc_attr(allow_interpreted_subclasses=True)
|
|
87
|
-
class HasStorageCapabilities:
|
|
88
|
-
"""Mixin for storage backends that expose their capabilities."""
|
|
89
|
-
|
|
90
|
-
__slots__ = ()
|
|
91
|
-
|
|
92
|
-
capabilities: ClassVar[StorageCapabilities]
|
|
93
|
-
|
|
94
|
-
@classmethod
|
|
95
|
-
def has_capability(cls, capability: str) -> bool:
|
|
96
|
-
"""Check if backend has a specific capability."""
|
|
97
|
-
return getattr(cls.capabilities, capability, False)
|
|
98
|
-
|
|
99
|
-
@classmethod
|
|
100
|
-
def get_capabilities(cls) -> StorageCapabilities:
|
|
101
|
-
"""Get all capabilities for this backend."""
|
|
102
|
-
return cls.capabilities
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|