pydantable-protocol 1.14.0__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.
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: pydantable-protocol
3
+ Version: 1.14.0
4
+ Summary: Execution engine protocols for pydantable (zero runtime dependencies).
5
+ License: MIT
6
+ Classifier: Development Status :: 5 - Production/Stable
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.10
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+
15
+ # pydantable-protocol
16
+
17
+ Zero-dependency execution engine protocols for **pydantable**. See the [repository root README](../README.md) for the full project.
@@ -0,0 +1,3 @@
1
+ # pydantable-protocol
2
+
3
+ Zero-dependency execution engine protocols for **pydantable**. See the [repository root README](../README.md) for the full project.
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pydantable-protocol"
7
+ version = "1.14.0"
8
+ description = "Execution engine protocols for pydantable (zero runtime dependencies)."
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.10"
12
+ classifiers = [
13
+ "Development Status :: 5 - Production/Stable",
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.10",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ ]
20
+ dependencies = []
21
+
22
+ [tool.setuptools]
23
+ package-dir = {"" = "python"}
24
+ include-package-data = true
25
+
26
+ [tool.setuptools.packages.find]
27
+ where = ["python"]
@@ -0,0 +1,28 @@
1
+ """Zero-dependency protocols for pydantable-compatible execution engines."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pydantable_protocol.exceptions import (
6
+ MissingRustExtensionError,
7
+ UnsupportedEngineOperationError,
8
+ )
9
+ from pydantable_protocol.protocols import (
10
+ EngineCapabilities,
11
+ ExecutionEngine,
12
+ PlanExecutor,
13
+ SinkWriter,
14
+ stub_engine_capabilities,
15
+ )
16
+
17
+ __version__ = "1.14.0"
18
+
19
+ __all__ = [
20
+ "EngineCapabilities",
21
+ "ExecutionEngine",
22
+ "MissingRustExtensionError",
23
+ "PlanExecutor",
24
+ "SinkWriter",
25
+ "UnsupportedEngineOperationError",
26
+ "__version__",
27
+ "stub_engine_capabilities",
28
+ ]
@@ -0,0 +1,29 @@
1
+ """Errors shared across pydantable distributions (no pydantable dependency)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ _MISSING_CORE = (
6
+ "The pydantable native extension (pydantable-native) is required for this "
7
+ "operation. Build from source with: maturin develop --manifest-path "
8
+ "pydantable-core/Cargo.toml — or install a published wheel "
9
+ "(pip install pydantable-native or pydantable-meta). See docs/DEVELOPER.md."
10
+ )
11
+
12
+
13
+ class MissingRustExtensionError(NotImplementedError):
14
+ """Raised when the compiled native extension is missing or too old for the API.
15
+
16
+ Subclasses :exc:`NotImplementedError` so broad handlers keep matching.
17
+ Install **pydantable-native** (or **pydantable-meta**) or build from source.
18
+ """
19
+
20
+ def __init__(self, detail: str | None = None) -> None:
21
+ super().__init__(detail if detail is not None else _MISSING_CORE)
22
+
23
+
24
+ class UnsupportedEngineOperationError(ValueError):
25
+ """Raised when an execution engine cannot perform a requested operation.
26
+
27
+ Third-party backends should raise this (or a subclass) so callers can catch
28
+ engine limits without importing ``pydantable``.
29
+ """
@@ -0,0 +1,390 @@
1
+ """Structural protocols and capability flags for pydantable execution engines.
2
+
3
+ These definitions are published in a **zero-dependency** distribution so
4
+ third-party backends (for example a SQL engine package) can implement
5
+ :class:`ExecutionEngine` and type-check against it **without** installing
6
+ ``pydantable``.
7
+
8
+ Unsupported calls should raise
9
+ :class:`~pydantable_protocol.exceptions.UnsupportedEngineOperationError`.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from dataclasses import dataclass
15
+ from typing import TYPE_CHECKING, Any, Literal, Protocol, runtime_checkable
16
+
17
+ if TYPE_CHECKING:
18
+ from collections.abc import Mapping, Sequence
19
+
20
+
21
+ @dataclass(frozen=True, slots=True)
22
+ class EngineCapabilities:
23
+ """Feature flags for an execution engine (native, stub, or future backends)."""
24
+
25
+ backend: Literal["native", "stub", "custom"]
26
+ extension_loaded: bool
27
+ has_execute_plan: bool
28
+ has_async_execute_plan: bool
29
+ has_async_collect_plan_batches: bool
30
+ has_sink_parquet: bool
31
+ has_sink_csv: bool
32
+ has_sink_ipc: bool
33
+ has_sink_ndjson: bool
34
+ has_collect_plan_batches: bool
35
+ has_execute_join: bool
36
+ has_execute_groupby_agg: bool
37
+
38
+
39
+ def stub_engine_capabilities() -> EngineCapabilities:
40
+ """Capabilities for minimal stub / test-double execution engines."""
41
+
42
+ return EngineCapabilities(
43
+ backend="stub",
44
+ extension_loaded=False,
45
+ has_execute_plan=False,
46
+ has_async_execute_plan=False,
47
+ has_async_collect_plan_batches=False,
48
+ has_sink_parquet=False,
49
+ has_sink_csv=False,
50
+ has_sink_ipc=False,
51
+ has_sink_ndjson=False,
52
+ has_collect_plan_batches=False,
53
+ has_execute_join=False,
54
+ has_execute_groupby_agg=False,
55
+ )
56
+
57
+
58
+ @runtime_checkable
59
+ class PlanExecutor(Protocol):
60
+ """Execute a logical plan against root data."""
61
+
62
+ def execute_plan(
63
+ self,
64
+ plan: Any,
65
+ data: Any,
66
+ *,
67
+ as_python_lists: bool = False,
68
+ streaming: bool = False,
69
+ error_context: str | None = None,
70
+ ) -> Any: ...
71
+
72
+ async def async_execute_plan(
73
+ self,
74
+ plan: Any,
75
+ data: Any,
76
+ *,
77
+ as_python_lists: bool = False,
78
+ streaming: bool = False,
79
+ error_context: str | None = None,
80
+ ) -> Any: ...
81
+
82
+ async def async_collect_plan_batches(
83
+ self,
84
+ plan: Any,
85
+ root_data: Any,
86
+ *,
87
+ batch_size: int = 65_536,
88
+ streaming: bool = False,
89
+ ) -> list[Any]: ...
90
+
91
+ def collect_batches(
92
+ self,
93
+ plan: Any,
94
+ root_data: Any,
95
+ *,
96
+ batch_size: int = 65_536,
97
+ streaming: bool = False,
98
+ ) -> list[Any]: ...
99
+
100
+ def execute_join(
101
+ self,
102
+ left_plan: Any,
103
+ left_root_data: Any,
104
+ right_plan: Any,
105
+ right_root_data: Any,
106
+ left_on: Sequence[str],
107
+ right_on: Sequence[str],
108
+ how: str,
109
+ suffix: str,
110
+ *,
111
+ validate: str | None = None,
112
+ coalesce: bool | None = None,
113
+ join_nulls: bool | None = None,
114
+ maintain_order: str | None = None,
115
+ allow_parallel: bool | None = None,
116
+ force_parallel: bool | None = None,
117
+ as_python_lists: bool = False,
118
+ streaming: bool = False,
119
+ ) -> tuple[Any, Any]: ...
120
+
121
+ def execute_groupby_agg(
122
+ self,
123
+ plan: Any,
124
+ root_data: Any,
125
+ by: Sequence[str],
126
+ aggregations: Any,
127
+ *,
128
+ maintain_order: bool = False,
129
+ drop_nulls: bool = True,
130
+ as_python_lists: bool = False,
131
+ streaming: bool = False,
132
+ ) -> tuple[Any, Any]: ...
133
+
134
+ def execute_concat(
135
+ self,
136
+ left_plan: Any,
137
+ left_root_data: Any,
138
+ right_plan: Any,
139
+ right_root_data: Any,
140
+ how: str,
141
+ *,
142
+ as_python_lists: bool = False,
143
+ streaming: bool = False,
144
+ ) -> tuple[Any, Any]: ...
145
+
146
+ def execute_except_all(
147
+ self,
148
+ left_plan: Any,
149
+ left_root_data: Any,
150
+ right_plan: Any,
151
+ right_root_data: Any,
152
+ *,
153
+ as_python_lists: bool = False,
154
+ streaming: bool = False,
155
+ ) -> tuple[Any, Any]: ...
156
+
157
+ def execute_intersect_all(
158
+ self,
159
+ left_plan: Any,
160
+ left_root_data: Any,
161
+ right_plan: Any,
162
+ right_root_data: Any,
163
+ *,
164
+ as_python_lists: bool = False,
165
+ streaming: bool = False,
166
+ ) -> tuple[Any, Any]: ...
167
+
168
+ def execute_melt(
169
+ self,
170
+ plan: Any,
171
+ root_data: Any,
172
+ id_vars: Sequence[str],
173
+ value_vars: Sequence[str] | None,
174
+ variable_name: str,
175
+ value_name: str,
176
+ *,
177
+ as_python_lists: bool = False,
178
+ streaming: bool = False,
179
+ ) -> tuple[Any, Any]: ...
180
+
181
+ def execute_pivot(
182
+ self,
183
+ plan: Any,
184
+ root_data: Any,
185
+ index: Sequence[str],
186
+ columns: str,
187
+ values: Sequence[str],
188
+ aggregate_function: str,
189
+ *,
190
+ pivot_values: Sequence[Any] | None = None,
191
+ sort_columns: bool = False,
192
+ separator: str = "_",
193
+ as_python_lists: bool = False,
194
+ streaming: bool = False,
195
+ ) -> tuple[Any, Any]: ...
196
+
197
+ def execute_explode(
198
+ self,
199
+ plan: Any,
200
+ root_data: Any,
201
+ columns: Sequence[str],
202
+ *,
203
+ streaming: bool = False,
204
+ outer: bool = False,
205
+ ) -> tuple[Any, Any]: ...
206
+
207
+ def execute_posexplode(
208
+ self,
209
+ plan: Any,
210
+ root_data: Any,
211
+ list_column: str,
212
+ pos_name: str,
213
+ value_name: str,
214
+ *,
215
+ streaming: bool = False,
216
+ outer: bool = False,
217
+ ) -> tuple[Any, Any]: ...
218
+
219
+ def execute_unnest(
220
+ self,
221
+ plan: Any,
222
+ root_data: Any,
223
+ columns: Sequence[str],
224
+ *,
225
+ streaming: bool = False,
226
+ ) -> tuple[Any, Any]: ...
227
+
228
+ def execute_rolling_agg(
229
+ self,
230
+ plan: Any,
231
+ root_data: Any,
232
+ on: str,
233
+ column: str,
234
+ window_size: int | str,
235
+ op: str,
236
+ out_name: str,
237
+ by: Sequence[str] | None,
238
+ min_periods: int,
239
+ ) -> tuple[Any, Any]: ...
240
+
241
+ def execute_groupby_dynamic_agg(
242
+ self,
243
+ plan: Any,
244
+ root_data: Any,
245
+ index_column: str,
246
+ every: str,
247
+ period: str | None,
248
+ by: Sequence[str] | None,
249
+ aggregations: Any,
250
+ *,
251
+ as_python_lists: bool = False,
252
+ streaming: bool = False,
253
+ ) -> tuple[Any, Any]: ...
254
+
255
+
256
+ @runtime_checkable
257
+ class SinkWriter(Protocol):
258
+ """Write lazy plan + root to on-disk formats."""
259
+
260
+ def write_parquet(
261
+ self,
262
+ plan: Any,
263
+ root_data: Any,
264
+ path: str,
265
+ *,
266
+ streaming: bool = False,
267
+ write_kwargs: dict[str, Any] | None = None,
268
+ partition_by: list[str] | tuple[str, ...] | None = None,
269
+ mkdir: bool = True,
270
+ ) -> None: ...
271
+
272
+ def write_csv(
273
+ self,
274
+ plan: Any,
275
+ root_data: Any,
276
+ path: str,
277
+ *,
278
+ streaming: bool = False,
279
+ separator: int = ord(","),
280
+ write_kwargs: dict[str, Any] | None = None,
281
+ ) -> None: ...
282
+
283
+ def write_ipc(
284
+ self,
285
+ plan: Any,
286
+ root_data: Any,
287
+ path: str,
288
+ *,
289
+ streaming: bool = False,
290
+ compression: str | None = None,
291
+ write_kwargs: dict[str, Any] | None = None,
292
+ ) -> None: ...
293
+
294
+ def write_ndjson(
295
+ self,
296
+ plan: Any,
297
+ root_data: Any,
298
+ path: str,
299
+ *,
300
+ streaming: bool = False,
301
+ write_kwargs: dict[str, Any] | None = None,
302
+ ) -> None: ...
303
+
304
+
305
+ @runtime_checkable
306
+ class ExecutionEngine(PlanExecutor, SinkWriter, Protocol):
307
+ """Full drop-in engine: logical plan transforms, execution, sinks, capabilities."""
308
+
309
+ @property
310
+ def capabilities(self) -> EngineCapabilities: ...
311
+
312
+ def make_plan(self, field_types: Any) -> Any: ...
313
+
314
+ def has_async_execute_plan(self) -> bool: ...
315
+
316
+ def has_async_collect_plan_batches(self) -> bool: ...
317
+
318
+ def make_literal(self, *, value: Any) -> Any: ...
319
+
320
+ def plan_with_columns(self, plan: Any, columns: dict[str, Any]) -> Any: ...
321
+
322
+ def expr_is_global_agg(self, expr: Any) -> bool: ...
323
+
324
+ def expr_global_default_alias(self, expr: Any) -> Any: ...
325
+
326
+ def plan_global_select(self, plan: Any, items: list[tuple[str, Any]]) -> Any: ...
327
+
328
+ def plan_select(self, plan: Any, projects: list[str]) -> Any: ...
329
+
330
+ def plan_filter(self, plan: Any, condition_expr: Any) -> Any: ...
331
+
332
+ def plan_sort(
333
+ self,
334
+ plan: Any,
335
+ keys: list[str],
336
+ desc: list[bool],
337
+ nulls_last: list[bool],
338
+ maintain_order: bool,
339
+ ) -> Any: ...
340
+
341
+ def plan_unique(
342
+ self,
343
+ plan: Any,
344
+ subset: list[str] | None,
345
+ keep: str,
346
+ maintain_order: bool,
347
+ ) -> Any: ...
348
+
349
+ def plan_duplicate_mask(
350
+ self, plan: Any, subset: list[str] | None, keep: str
351
+ ) -> Any: ...
352
+
353
+ def plan_drop_duplicate_groups(
354
+ self, plan: Any, subset: list[str] | None
355
+ ) -> Any: ...
356
+
357
+ def plan_drop(self, plan: Any, columns: list[str]) -> Any: ...
358
+
359
+ def plan_rename(self, plan: Any, rename_map: Mapping[str, str]) -> Any: ...
360
+
361
+ def plan_slice(self, plan: Any, offset: int, length: int) -> Any: ...
362
+
363
+ def plan_with_row_count(self, plan: Any, name: str, offset: int) -> Any: ...
364
+
365
+ def plan_fill_null(
366
+ self,
367
+ plan: Any,
368
+ subset: list[str] | None,
369
+ value: Any,
370
+ strategy: str | None,
371
+ ) -> Any: ...
372
+
373
+ def plan_drop_nulls(
374
+ self,
375
+ plan: Any,
376
+ subset: list[str] | None,
377
+ how: str,
378
+ threshold: int | None,
379
+ ) -> Any: ...
380
+
381
+ def plan_rolling_agg(
382
+ self,
383
+ plan: Any,
384
+ column: str,
385
+ window_size: int,
386
+ min_periods: int,
387
+ op: str,
388
+ out_name: str,
389
+ partition_by: Sequence[str] | None = None,
390
+ ) -> Any: ...
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: pydantable-protocol
3
+ Version: 1.14.0
4
+ Summary: Execution engine protocols for pydantable (zero runtime dependencies).
5
+ License: MIT
6
+ Classifier: Development Status :: 5 - Production/Stable
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.10
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+
15
+ # pydantable-protocol
16
+
17
+ Zero-dependency execution engine protocols for **pydantable**. See the [repository root README](../README.md) for the full project.
@@ -0,0 +1,10 @@
1
+ README.md
2
+ pyproject.toml
3
+ python/pydantable_protocol/__init__.py
4
+ python/pydantable_protocol/exceptions.py
5
+ python/pydantable_protocol/protocols.py
6
+ python/pydantable_protocol/py.typed
7
+ python/pydantable_protocol.egg-info/PKG-INFO
8
+ python/pydantable_protocol.egg-info/SOURCES.txt
9
+ python/pydantable_protocol.egg-info/dependency_links.txt
10
+ python/pydantable_protocol.egg-info/top_level.txt
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+