ds-resource-plugin-py-lib 0.1.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.
Files changed (37) hide show
  1. ds_resource_plugin_py_lib/__init__.py +28 -0
  2. ds_resource_plugin_py_lib/common/__init__.py +15 -0
  3. ds_resource_plugin_py_lib/common/resource/__init__.py +17 -0
  4. ds_resource_plugin_py_lib/common/resource/client.py +265 -0
  5. ds_resource_plugin_py_lib/common/resource/dataset/__init__.py +25 -0
  6. ds_resource_plugin_py_lib/common/resource/dataset/base.py +322 -0
  7. ds_resource_plugin_py_lib/common/resource/dataset/decorators.py +73 -0
  8. ds_resource_plugin_py_lib/common/resource/dataset/enums.py +36 -0
  9. ds_resource_plugin_py_lib/common/resource/dataset/errors.py +181 -0
  10. ds_resource_plugin_py_lib/common/resource/dataset/result.py +64 -0
  11. ds_resource_plugin_py_lib/common/resource/dataset/storage_format.py +80 -0
  12. ds_resource_plugin_py_lib/common/resource/errors.py +53 -0
  13. ds_resource_plugin_py_lib/common/resource/linked_service/__init__.py +18 -0
  14. ds_resource_plugin_py_lib/common/resource/linked_service/base.py +186 -0
  15. ds_resource_plugin_py_lib/common/resource/linked_service/enums.py +19 -0
  16. ds_resource_plugin_py_lib/common/resource/linked_service/errors.py +103 -0
  17. ds_resource_plugin_py_lib/common/serde/__init__.py +15 -0
  18. ds_resource_plugin_py_lib/common/serde/binary.py +129 -0
  19. ds_resource_plugin_py_lib/common/serde/deserialize/__init__.py +18 -0
  20. ds_resource_plugin_py_lib/common/serde/deserialize/awswrangler.py +142 -0
  21. ds_resource_plugin_py_lib/common/serde/deserialize/base.py +31 -0
  22. ds_resource_plugin_py_lib/common/serde/deserialize/pandas.py +107 -0
  23. ds_resource_plugin_py_lib/common/serde/serialize/__init__.py +18 -0
  24. ds_resource_plugin_py_lib/common/serde/serialize/awswrangler.py +115 -0
  25. ds_resource_plugin_py_lib/common/serde/serialize/base.py +27 -0
  26. ds_resource_plugin_py_lib/common/serde/serialize/pandas.py +102 -0
  27. ds_resource_plugin_py_lib/libs/__init__.py +14 -0
  28. ds_resource_plugin_py_lib/libs/utils/__init__.py +14 -0
  29. ds_resource_plugin_py_lib/libs/utils/import_string.py +50 -0
  30. ds_resource_plugin_py_lib/libs/utils/json_default.py +66 -0
  31. ds_resource_plugin_py_lib/libs/utils/sanitize.py +35 -0
  32. ds_resource_plugin_py_lib/py.typed +0 -0
  33. ds_resource_plugin_py_lib-0.1.0.dist-info/METADATA +140 -0
  34. ds_resource_plugin_py_lib-0.1.0.dist-info/RECORD +37 -0
  35. ds_resource_plugin_py_lib-0.1.0.dist-info/WHEEL +5 -0
  36. ds_resource_plugin_py_lib-0.1.0.dist-info/licenses/LICENSE-APACHE +201 -0
  37. ds_resource_plugin_py_lib-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,28 @@
1
+ """
2
+ **File:** ``__init__.py``
3
+ **Region:** ``ds_resource_plugin_py_lib``
4
+
5
+ Description
6
+ -----------
7
+ A Python package from the ds-resource-plugin library.
8
+
9
+ Example
10
+ -------
11
+ .. code-block:: python
12
+
13
+ from ds_resource_plugin_py_lib import __version__
14
+
15
+ print(f"Package version: {__version__}")
16
+ """
17
+
18
+ from importlib.metadata import version
19
+
20
+ from . import common, libs
21
+
22
+ __version__ = version("ds-resource-plugin-py-lib")
23
+
24
+ __all__ = [
25
+ "__version__",
26
+ "common",
27
+ "libs",
28
+ ]
@@ -0,0 +1,15 @@
1
+ """
2
+ **File:** ``__init__.py``
3
+ **Region:** ``ds_resource_plugin_py_lib/common``
4
+
5
+ Description
6
+ -----------
7
+ Common utilities for resources and (de)serialization.
8
+ """
9
+
10
+ from . import resource, serde
11
+
12
+ __all__ = [
13
+ "resource",
14
+ "serde",
15
+ ]
@@ -0,0 +1,17 @@
1
+ """
2
+ **File:** ``__init__.py``
3
+ **Region:** ``ds_resource_plugin_py_lib/common/resource``
4
+
5
+ Description
6
+ -----------
7
+ Public resource APIs: datasets, linked services, and the resource client.
8
+ """
9
+
10
+ from . import dataset, linked_service
11
+ from .client import ResourceClient
12
+
13
+ __all__ = [
14
+ "ResourceClient",
15
+ "dataset",
16
+ "linked_service",
17
+ ]
@@ -0,0 +1,265 @@
1
+ """
2
+ **File:** ``client.py``
3
+ **Region:** ``ds_resource_plugin_py_lib/common/resource``
4
+
5
+ Description
6
+ -----------
7
+ Resource client for discovering and managing datasets and linked services using entry points.
8
+
9
+ Example
10
+ -------
11
+ .. code-block:: python
12
+
13
+ from ds_resource_plugin_py_lib.common.resource.client import ResourceClient
14
+
15
+ client = ResourceClient()
16
+
17
+ # Inspect discovered resources (populated via Python entry points).
18
+ print(client.resources.keys())
19
+ print(client.linked_services.keys())
20
+ print(client.datasets.keys())
21
+
22
+ dataset = client.dataset(config={"type": "dataset.example", "version": "1.0.0"})
23
+ linked_service = client.linked_service(config={"type": "linked_service.example", "version": "1.0.0"})
24
+
25
+ linked_service.connect()
26
+ print(linked_service.connection)
27
+ print(dataset.read())
28
+ """
29
+
30
+ from functools import lru_cache
31
+ from importlib import import_module
32
+ from importlib.metadata import entry_points
33
+ from pathlib import Path
34
+ from typing import Any, cast
35
+
36
+ import yaml
37
+ from ds_common_logger_py_lib import Logger
38
+ from ds_common_serde_py_lib.errors import DeserializationError
39
+
40
+ from ...libs.utils import import_string, sanitize_version
41
+ from ..resource.dataset.base import Dataset, DatasetInfo
42
+ from ..resource.linked_service.base import LinkedService, LinkedServiceInfo
43
+
44
+ logger = Logger.get_logger(__name__, package=True)
45
+
46
+
47
+ class ResourceClient:
48
+ PROTOCOL_GROUP = "ds.protocols"
49
+ PROVIDER_GROUP = "ds.providers"
50
+
51
+ def __init__(self) -> None:
52
+ super().__init__()
53
+ self._resource_dict: dict[str, dict[str, Any]] = {}
54
+ self._linked_services: dict[tuple[str, str], LinkedServiceInfo] = {}
55
+ self._datasets: dict[tuple[str, str], DatasetInfo] = {}
56
+ self._discover_resources(self.PROTOCOL_GROUP)
57
+ self._discover_resources(self.PROVIDER_GROUP)
58
+ logger.debug(f"Loaded {len(self._resource_dict)} resources")
59
+ logger.debug(f"Loaded {len(self._linked_services)} linked services")
60
+ logger.debug(f"Loaded {len(self._datasets)} datasets")
61
+
62
+ @classmethod
63
+ @lru_cache(maxsize=1)
64
+ def get_instance(cls) -> "ResourceClient":
65
+ """Get the singleton instance of ResourceClient."""
66
+ return cls()
67
+
68
+ @property
69
+ def resources(self) -> dict[str, dict[str, Any]]:
70
+ return self._resource_dict
71
+
72
+ @property
73
+ def linked_services(self) -> dict[tuple[str, str], LinkedServiceInfo]:
74
+ return self._linked_services
75
+
76
+ @property
77
+ def datasets(self) -> dict[tuple[str, str], DatasetInfo]:
78
+ return self._datasets
79
+
80
+ def _discover_resources(self, group: str) -> None:
81
+ """
82
+ Discover protocol/provider packages via entry points.
83
+ Each entry point must target a Python package that contains resource.yaml in its root.
84
+ """
85
+ try:
86
+ eps = entry_points(group=group)
87
+ except Exception as exc:
88
+ logger.warning(f"Failed to read entry points for {group}: {exc}")
89
+ return
90
+
91
+ for ep in eps:
92
+ try:
93
+ module = import_module(ep.module)
94
+ module_path = getattr(module, "__file__", None)
95
+ if not module_path:
96
+ logger.warning(f"Entry point {ep.name} has no __file__; skipping.")
97
+ continue
98
+
99
+ real_path = str(Path(module_path).parent.resolve())
100
+ self._scan_resource_directory(real_path)
101
+
102
+ except Exception as exc:
103
+ logger.error(f"Error when loading entry point {ep.name} ({group}): {exc}")
104
+
105
+ def _scan_resource_directory(self, resource_dir: str) -> None:
106
+ """
107
+ Scan a resource directory for resource.yaml.
108
+ Checks root first (new behavior), then subdirectories (old behavior).
109
+ Args:
110
+ resource_dir: Path to the resource directory.
111
+ """
112
+ resource_path = Path(resource_dir)
113
+ if not resource_path.exists():
114
+ logger.debug(f"Resource directory {resource_dir} does not exist")
115
+ return
116
+
117
+ self._load_resource_from_path(str(resource_path))
118
+
119
+ def _load_resource_from_path(self, path: str) -> None:
120
+ """
121
+ Load resource configuration from a directory path.
122
+
123
+ Args:
124
+ path: Path to the resource directory.
125
+ """
126
+ resource_dir = Path(path)
127
+ resource_yaml = resource_dir / "resource.yaml"
128
+ if not resource_yaml.exists():
129
+ logger.debug(f"No resource.yaml found in {path}")
130
+ return
131
+
132
+ try:
133
+ with Path(resource_yaml).open() as f:
134
+ resource_config = yaml.safe_load(f)
135
+ if not resource_config:
136
+ logger.warning(f"Empty resource configuration in {resource_yaml}")
137
+ return
138
+
139
+ resource_name = resource_config.get("name", resource_dir.name)
140
+ self._resource_dict[resource_name] = resource_config
141
+ self._parse_linked_services(resource_config)
142
+ self._parse_datasets(resource_config)
143
+ except Exception as exc:
144
+ logger.error(f"Error loading resource configuration from {resource_yaml}: {exc}")
145
+
146
+ def _parse_linked_services(self, config: dict[str, Any]) -> None:
147
+ """
148
+ Parse linked services from resource configuration.
149
+
150
+ Args:
151
+ config: Resource configuration dictionary.
152
+ """
153
+ linked_services = config.get("linked_service", [])
154
+ for service in linked_services:
155
+ service_name = service.get("name")
156
+ if service_name:
157
+ type = service.get("type")
158
+ version = service.get("version", "1.0.0")
159
+ service_info = LinkedServiceInfo(
160
+ type=type,
161
+ name=service_name,
162
+ class_name=service.get("class_name"),
163
+ version=version,
164
+ description=service.get("description"),
165
+ )
166
+ # Store by composite key (type, version) to support multiple versions
167
+ self._linked_services[service_info.key] = service_info
168
+
169
+ def _parse_datasets(self, config: dict[str, Any]) -> None:
170
+ """
171
+ Parse datasets from resource configuration.
172
+
173
+ Args:
174
+ config: Resource configuration dictionary.
175
+ """
176
+ datasets = config.get("dataset", [])
177
+ for dataset in datasets:
178
+ dataset_name = dataset.get("name")
179
+ if dataset_name:
180
+ type = dataset.get("type")
181
+ version = dataset.get("version", "1.0.0")
182
+ dataset_info = DatasetInfo(
183
+ type=type,
184
+ name=dataset_name,
185
+ class_name=dataset.get("class_name"),
186
+ version=version,
187
+ description=dataset.get("description"),
188
+ )
189
+ self._datasets[dataset_info.key] = dataset_info
190
+
191
+ def _get_dataset_model_cls(self, _type: str, version: str) -> type[Dataset[Any, Any, Any, Any]]:
192
+ """
193
+ Get a dataset model class by type and optionally version.
194
+
195
+ Args:
196
+ _type: str
197
+ version: str
198
+ Returns:
199
+ Type[Dataset]
200
+ """
201
+ cls_name = self.datasets[(_type, version)].class_name
202
+ logger.debug("Dataset Class Name: %s", cls_name)
203
+ return cast("type[Dataset[Any, Any, Any, Any]]", import_string(cls_name))
204
+
205
+ def _get_linked_service_model_cls(self, _type: str, version: str) -> type[LinkedService[Any]]:
206
+ """
207
+ Get a linked service model class by type and version.
208
+
209
+ Args:
210
+ _type: The type of the linked service.
211
+ version: str version of the linked service.
212
+ Returns:
213
+ Type[LinkedService]
214
+ """
215
+ cls_name = self.linked_services[(_type, version)].class_name
216
+ logger.debug("Linked Service Class Name: %s", cls_name)
217
+ return cast("type[LinkedService[Any]]", import_string(cls_name))
218
+
219
+ def linked_service(self, config: dict[str, Any]) -> LinkedService[Any]:
220
+ """
221
+ Get a linked service instance by configuration.
222
+
223
+ Args:
224
+ config: dict containing at least 'type' and 'version'
225
+ Returns:
226
+ LinkedService
227
+ Raises:
228
+ DeserializationError: If the linked service cannot be deserialized.
229
+ """
230
+ try:
231
+ type = config["type"]
232
+ version = sanitize_version(config["version"])
233
+ model_cls = self._get_linked_service_model_cls(type, version)
234
+ linked_service: LinkedService[Any] = model_cls.deserialize(config)
235
+ return linked_service
236
+ except (TypeError, KeyError) as exc:
237
+ logger.error(f"Error deserializing linked service: {exc}")
238
+ raise DeserializationError(
239
+ message=f"Error deserializing linked service: {exc}",
240
+ details={"config": config, "error": str(exc)},
241
+ ) from exc
242
+
243
+ def dataset(self, config: dict[str, Any]) -> Dataset[Any, Any, Any, Any]:
244
+ """
245
+ Get a dataset instance by configuration.
246
+
247
+ Args:
248
+ config: dict containing at least 'type' and 'version'
249
+ Returns:
250
+ Dataset
251
+ Raises:
252
+ DeserializationError: If the dataset cannot be deserialized.
253
+ """
254
+ try:
255
+ type = config["type"]
256
+ version = sanitize_version(config["version"])
257
+ dataset_cls = self._get_dataset_model_cls(type, version)
258
+ dataset: Dataset[Any, Any, Any, Any] = dataset_cls.deserialize(config)
259
+ return dataset
260
+ except (TypeError, KeyError) as exc:
261
+ logger.error(f"Error deserializing dataset: {exc}")
262
+ raise DeserializationError(
263
+ message=f"Error deserializing dataset: {exc}",
264
+ details={"config": config, "error": str(exc)},
265
+ ) from exc
@@ -0,0 +1,25 @@
1
+ """
2
+ **File:** ``__init__.py``
3
+ **Region:** ``ds_resource_plugin_py_lib/common/resource/dataset``
4
+
5
+ Description
6
+ -----------
7
+ Dataset models, typed properties, and storage format helpers.
8
+ """
9
+
10
+ from .base import Dataset, DatasetInfo, DatasetSettings, TabularDataset
11
+ from .enums import DatasetMethod
12
+ from .result import OperationError, OperationInfo
13
+ from .storage_format import DatasetStorageFormat, DatasetStorageFormatType
14
+
15
+ __all__ = [
16
+ "Dataset",
17
+ "DatasetInfo",
18
+ "DatasetMethod",
19
+ "DatasetSettings",
20
+ "DatasetStorageFormat",
21
+ "DatasetStorageFormatType",
22
+ "OperationError",
23
+ "OperationInfo",
24
+ "TabularDataset",
25
+ ]
@@ -0,0 +1,322 @@
1
+ """
2
+ **File:** ``base.py``
3
+ **Region:** ``ds_resource_plugin_py_lib/common/resource/dataset``
4
+
5
+ Description
6
+ -----------
7
+ Base dataset models and typed properties.
8
+ """
9
+
10
+ import io
11
+ import uuid
12
+ from abc import ABC, abstractmethod
13
+ from dataclasses import dataclass, field
14
+ from enum import StrEnum
15
+ from types import TracebackType
16
+ from typing import Any, Generic, NamedTuple, Self, TypeVar
17
+
18
+ import pandas as pd
19
+ from ds_common_serde_py_lib import Serializable
20
+
21
+ from ...resource.linked_service.base import LinkedService
22
+ from ...serde.deserialize.base import DataDeserializer
23
+ from ...serde.serialize.base import DataSerializer
24
+ from .decorators import track_result
25
+ from .enums import DatasetMethod
26
+ from .result import OperationInfo
27
+
28
+
29
+ class DatasetInfo(NamedTuple):
30
+ """
31
+ NamedTuple that represents the dataset information.
32
+ """
33
+
34
+ type: str
35
+ name: str
36
+ class_name: str
37
+ version: str
38
+ description: str | None = None
39
+
40
+ def __str__(self) -> str:
41
+ """
42
+ Return a string representation of the dataset info.
43
+
44
+ Returns:
45
+ A string representation of the dataset info.
46
+ """
47
+ return f"{self.type}:v{self.version}"
48
+
49
+ @property
50
+ def key(self) -> tuple[str, str]:
51
+ """
52
+ Return the composite key (type, version) for dictionary lookups.
53
+
54
+ Returns:
55
+ A tuple containing the type and version.
56
+ """
57
+ return (self.type, self.version)
58
+
59
+
60
+ @dataclass(kw_only=True)
61
+ class DatasetSettings(Serializable):
62
+ """
63
+ The object containing the settings of the dataset.
64
+ """
65
+
66
+ pass
67
+
68
+
69
+ DatasetSettingsType = TypeVar("DatasetSettingsType", bound=DatasetSettings)
70
+ LinkedServiceType = TypeVar("LinkedServiceType", bound=LinkedService[Any])
71
+ SerializerType = TypeVar("SerializerType", bound=DataSerializer)
72
+ DeserializerType = TypeVar("DeserializerType", bound=DataDeserializer)
73
+
74
+
75
+ @dataclass(kw_only=True)
76
+ class Dataset(
77
+ ABC,
78
+ Serializable,
79
+ Generic[LinkedServiceType, DatasetSettingsType, SerializerType, DeserializerType],
80
+ ):
81
+ """
82
+ The ds workflow nested object which identifies data within a data store,
83
+ such as table, files, folders and documents.
84
+
85
+ You probably want to use the subclasses and not this class directly.
86
+ """
87
+
88
+ id: uuid.UUID
89
+ name: str
90
+ description: str | None = None
91
+ version: str
92
+
93
+ settings: DatasetSettingsType
94
+ linked_service: LinkedServiceType
95
+
96
+ serializer: SerializerType | None = None
97
+ deserializer: DeserializerType | None = None
98
+
99
+ input: Any | None = field(default=None, metadata={"serialize": False})
100
+ output: Any | None = field(default=None, metadata={"serialize": False})
101
+
102
+ checkpoint: dict[str, Any] = field(default_factory=dict)
103
+ operation: OperationInfo = field(default_factory=OperationInfo)
104
+
105
+ def __init_subclass__(cls, **kwargs: Any) -> None:
106
+ """
107
+ Initialize the subclass.
108
+
109
+ Args:
110
+ kwargs: The keyword arguments.
111
+
112
+ Returns:
113
+ The subclass.
114
+ """
115
+ super().__init_subclass__(**kwargs)
116
+ for name in DatasetMethod.all_values():
117
+ method = cls.__dict__.get(name)
118
+ if method is not None and not getattr(method, "_tracked", False):
119
+ setattr(cls, name, track_result(method))
120
+
121
+ def __enter__(self) -> Self:
122
+ """
123
+ Context manager enter.
124
+
125
+ Returns:
126
+ The dataset.
127
+ """
128
+ return self
129
+
130
+ def __exit__(
131
+ self,
132
+ exc_type: type[BaseException] | None,
133
+ exc_value: BaseException | None,
134
+ traceback: TracebackType | None,
135
+ ) -> None:
136
+ """
137
+ Context manager exit.
138
+
139
+ Args:
140
+ exc_type: The type of the exception.
141
+ exc_value: The value of the exception.
142
+ traceback: The traceback of the exception.
143
+ """
144
+ self.close()
145
+
146
+ @property
147
+ def supports_checkpoint(self) -> bool:
148
+ """Whether this provider supports incremental loads via ``self.checkpoint``."""
149
+ return False
150
+
151
+ @property
152
+ @abstractmethod
153
+ def type(self) -> StrEnum:
154
+ """
155
+ Get the type of the dataset.
156
+ """
157
+ ...
158
+
159
+ @abstractmethod
160
+ def create(self) -> None:
161
+ """
162
+ Insert all rows in ``self.input`` into the target as a single atomic
163
+ transaction. Must not delete, update, or overwrite existing data.
164
+
165
+ Raises:
166
+ CreateError: If the operation fails.
167
+ NotSupportedError: If the provider does not support create.
168
+
169
+ See Also:
170
+ Full contract: ``docs/DATASET_CONTRACT.md`` -- ``create()``
171
+ """
172
+ ...
173
+
174
+ @abstractmethod
175
+ def read(self) -> None:
176
+ """
177
+ Read data from the source and assign it to ``self.output``.
178
+ Pagination within a single call is handled internally.
179
+ Supports incremental loads via ``self.checkpoint``.
180
+
181
+ Raises:
182
+ ReadError: If the operation fails.
183
+ NotSupportedError: If the provider does not support read.
184
+
185
+ See Also:
186
+ Full contract: ``docs/DATASET_CONTRACT.md`` -- ``read()``
187
+ """
188
+ ...
189
+
190
+ @abstractmethod
191
+ def update(self) -> None:
192
+ """
193
+ Update existing rows in the target matched by identity columns
194
+ defined in ``self.settings``. Atomic. Must not insert new rows.
195
+
196
+ Raises:
197
+ UpdateError: If the operation fails.
198
+ NotSupportedError: If the provider does not support update.
199
+
200
+ See Also:
201
+ Full contract: ``docs/DATASET_CONTRACT.md`` -- ``update()``
202
+ """
203
+ ...
204
+
205
+ @abstractmethod
206
+ def upsert(self) -> None:
207
+ """
208
+ Insert rows that do not exist, update rows that do, matched by
209
+ identity columns defined in ``self.settings``. Atomic.
210
+
211
+ Raises:
212
+ UpsertError: If the operation fails.
213
+ NotSupportedError: If the provider does not support upsert.
214
+
215
+ See Also:
216
+ Full contract: ``docs/DATASET_CONTRACT.md`` -- ``upsert()``
217
+ """
218
+ ...
219
+
220
+ @abstractmethod
221
+ def delete(self) -> None:
222
+ """
223
+ Remove specific rows from the target matched by identity columns
224
+ defined in ``self.settings``. Atomic. Idempotent.
225
+
226
+ Raises:
227
+ DeleteError: If the operation fails.
228
+ NotSupportedError: If the provider does not support delete.
229
+
230
+ See Also:
231
+ Full contract: ``docs/DATASET_CONTRACT.md`` -- ``delete()``
232
+ """
233
+ ...
234
+
235
+ @abstractmethod
236
+ def purge(self) -> None:
237
+ """
238
+ Remove all content from the target. ``self.input`` is not used.
239
+ Atomic. Idempotent.
240
+
241
+ Raises:
242
+ PurgeError: If the operation fails.
243
+ NotSupportedError: If the provider does not support purge.
244
+
245
+ See Also:
246
+ Full contract: ``docs/DATASET_CONTRACT.md`` -- ``purge()``
247
+ """
248
+ ...
249
+
250
+ @abstractmethod
251
+ def list(self) -> None:
252
+ """
253
+ Discover available resources and populate ``self.output`` with a
254
+ DataFrame of resources and their metadata. Idempotent.
255
+
256
+ Raises:
257
+ ListError: If the operation fails.
258
+ NotSupportedError: If the provider does not support listing.
259
+
260
+ See Also:
261
+ Full contract: ``docs/DATASET_CONTRACT.md`` -- ``list()``
262
+ """
263
+ ...
264
+
265
+ @abstractmethod
266
+ def rename(self) -> None:
267
+ """
268
+ Rename the resource in the backend. Atomic. Not idempotent.
269
+
270
+ Raises:
271
+ RenameError: If the operation fails.
272
+ NotSupportedError: If the provider does not support renaming.
273
+
274
+ See Also:
275
+ Full contract: ``docs/DATASET_CONTRACT.md`` -- ``rename()``
276
+ """
277
+ ...
278
+
279
+ @abstractmethod
280
+ def close(self) -> None:
281
+ """
282
+ Release any connections, sessions, or handles held by the linked
283
+ service. Must not raise if already closed. Idempotent.
284
+
285
+ See Also:
286
+ Full contract: ``docs/DATASET_CONTRACT.md`` -- ``close()``
287
+ """
288
+ ...
289
+
290
+
291
+ @dataclass(kw_only=True)
292
+ class BinaryDataset(
293
+ Dataset[LinkedServiceType, DatasetSettingsType, SerializerType, DeserializerType],
294
+ Generic[LinkedServiceType, DatasetSettingsType, SerializerType, DeserializerType],
295
+ ):
296
+ """
297
+ Binary dataset object which identifies data within a data store,
298
+ such as files, folders and documents.
299
+
300
+ The input of the dataset is a binary file.
301
+ The output of the dataset is a binary file.
302
+ """
303
+
304
+ input: io.BytesIO = field(default_factory=io.BytesIO, metadata={"serialize": False})
305
+ output: io.BytesIO = field(default_factory=io.BytesIO, metadata={"serialize": False})
306
+
307
+
308
+ @dataclass(kw_only=True)
309
+ class TabularDataset(
310
+ Dataset[LinkedServiceType, DatasetSettingsType, SerializerType, DeserializerType],
311
+ Generic[LinkedServiceType, DatasetSettingsType, SerializerType, DeserializerType],
312
+ ):
313
+ """
314
+ Tabular dataset object which identifies data within a data store,
315
+ such as table/csv/json/parquet/parquetdataset/ and other documents.
316
+
317
+ The input of the dataset is a pandas DataFrame.
318
+ The output of the dataset is a pandas DataFrame.
319
+ """
320
+
321
+ input: pd.DataFrame = field(default_factory=pd.DataFrame, metadata={"serialize": False})
322
+ output: pd.DataFrame = field(default_factory=pd.DataFrame, metadata={"serialize": False})