pystac-ext-table 1.2.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.
File without changes
@@ -0,0 +1,324 @@
1
+ """Implements the :stac-ext:`Table Extension <table>`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterable
6
+ from typing import Any, Generic, Literal, TypeVar, cast
7
+
8
+ import pystac
9
+ from pystac.extensions.base import ExtensionManagementMixin, PropertiesExtension
10
+ from pystac.extensions.hooks import ExtensionHooks
11
+ from pystac.utils import get_required
12
+
13
+ #: Generalized version of :class:`~pystac.Collection`, :class:`~pystac.Item`,
14
+ #: :class:`~pystac.Asset` or :class:`~pystac.ItemAssetDefinition`
15
+ T = TypeVar(
16
+ "T", pystac.Collection, pystac.Item, pystac.Asset, pystac.ItemAssetDefinition
17
+ )
18
+
19
+ SCHEMA_URI = "https://stac-extensions.github.io/table/v1.2.0/schema.json"
20
+
21
+ PREFIX: str = "table:"
22
+ COLUMNS_PROP = PREFIX + "columns"
23
+ PRIMARY_GEOMETRY_PROP = PREFIX + "primary_geometry"
24
+ ROW_COUNT_PROP = PREFIX + "row_count"
25
+ STORAGE_OPTIONS_PROP = PREFIX + "storage_options"
26
+ TABLES_PROP = PREFIX + "tables"
27
+
28
+ # Column properties
29
+ COL_NAME_PROP = "name"
30
+ COL_DESCRIPTION_PROP = "description"
31
+ COL_TYPE_PROP = "type"
32
+
33
+ # Table properties
34
+ TBL_NAME_PROP = "name"
35
+ TBL_DESCRIPTION_PROP = "description"
36
+
37
+
38
+ class Column:
39
+ """Object representing a column of a table."""
40
+
41
+ properties: dict[str, Any]
42
+
43
+ def __init__(self, properties: dict[str, Any]):
44
+ self.properties = properties
45
+
46
+ @property
47
+ def name(self) -> str:
48
+ """The column name"""
49
+ return cast(
50
+ str,
51
+ get_required(
52
+ self.properties.get(COL_NAME_PROP), "table:column", COL_NAME_PROP
53
+ ),
54
+ )
55
+
56
+ @name.setter
57
+ def name(self, v: str) -> None:
58
+ self.properties[COL_NAME_PROP] = v
59
+
60
+ @property
61
+ def description(self) -> str | None:
62
+ """Detailed multi-line description to explain the column. `CommonMark 0.29
63
+ <http://commonmark.org/>`__ syntax MAY be used for rich text representation."""
64
+ return self.properties.get(COL_DESCRIPTION_PROP)
65
+
66
+ @description.setter
67
+ def description(self, v: str | None) -> None:
68
+ if v is None:
69
+ self.properties.pop(COL_DESCRIPTION_PROP, None)
70
+ else:
71
+ self.properties[COL_DESCRIPTION_PROP] = v
72
+
73
+ @property
74
+ def col_type(self) -> str | None:
75
+ """Data type of the column. If using a file format with a type system (like
76
+ Parquet), we recommend you use those types"""
77
+ return self.properties.get(COL_TYPE_PROP)
78
+
79
+ @col_type.setter
80
+ def col_type(self, v: str | None) -> None:
81
+ if v is None:
82
+ self.properties.pop(COL_TYPE_PROP, None)
83
+ else:
84
+ self.properties[COL_TYPE_PROP] = v
85
+
86
+ def to_dict(self) -> dict[str, Any]:
87
+ """Returns a dictionary representing this ``Column``."""
88
+ return self.properties
89
+
90
+
91
+ class Table:
92
+ """Object containing a high-level summary about a table"""
93
+
94
+ properties: dict[str, Any]
95
+
96
+ def __init__(self, properties: dict[str, Any]):
97
+ self.properties = properties
98
+
99
+ @property
100
+ def name(self) -> str:
101
+ """The table name"""
102
+ return cast(
103
+ str, get_required(self.properties.get(TBL_NAME_PROP), self, TBL_NAME_PROP)
104
+ )
105
+
106
+ @name.setter
107
+ def name(self, v: str) -> None:
108
+ self.properties[COL_NAME_PROP] = v
109
+
110
+ @property
111
+ def description(self) -> str | None:
112
+ """Detailed multi-line description to explain the table. `CommonMark 0.29
113
+ <http://commonmark.org/>`__ syntax MAY be used for rich text representation."""
114
+ return self.properties.get(COL_DESCRIPTION_PROP)
115
+
116
+ @description.setter
117
+ def description(self, v: str | None) -> None:
118
+ if v is None:
119
+ self.properties.pop(COL_DESCRIPTION_PROP, None)
120
+ else:
121
+ self.properties[COL_DESCRIPTION_PROP] = v
122
+
123
+ def to_dict(self) -> dict[str, Any]:
124
+ """Returns a dictionary representing this ``Table``."""
125
+ return self.properties
126
+
127
+
128
+ class TableExtension(
129
+ Generic[T],
130
+ PropertiesExtension,
131
+ ExtensionManagementMixin[pystac.Item | pystac.Collection],
132
+ ):
133
+ """An abstract class that can be used to extend the properties of a
134
+ :class:`~pystac.Collection`, :class:`~pystac.Item`, or :class:`~pystac.Asset` with
135
+ properties from the :stac-ext:`Datacube Extension <datacube>`. This class is
136
+ generic over the type of STAC Object to be extended (e.g. :class:`~pystac.Item`,
137
+ :class:`~pystac.Asset`).
138
+
139
+ To create a concrete instance of :class:`TableExtension`, use the
140
+ :meth:`TableExtension.ext` method. For example:
141
+
142
+ .. code-block:: python
143
+
144
+ >>> item: pystac.Item = ...
145
+ >>> tbl_ext = TableExtension.ext(item)
146
+
147
+ """
148
+
149
+ name: Literal["table"] = "table"
150
+
151
+ @classmethod
152
+ def get_schema_uri(cls) -> str:
153
+ return SCHEMA_URI
154
+
155
+ @classmethod
156
+ def ext(cls, obj: T, add_if_missing: bool = False) -> TableExtension[T]:
157
+ """Extend the given STAC Object with properties from the
158
+ :stac-ext:`Table Extension <table>`.
159
+
160
+ This extension can be applied to instances of :class:`~pystac.Collection`,
161
+ :class:`~pystac.Item` or :class:`~pystac.Asset`.
162
+
163
+ Raises:
164
+ pystac.ExtensionTypeError : If an invalid object type is passed.
165
+ """
166
+ if isinstance(obj, pystac.Collection):
167
+ cls.ensure_has_extension(obj, add_if_missing)
168
+ return cast(TableExtension[T], CollectionTableExtension(obj))
169
+ if isinstance(obj, pystac.Item):
170
+ cls.ensure_has_extension(obj, add_if_missing)
171
+ return cast(TableExtension[T], ItemTableExtension(obj))
172
+ if isinstance(obj, pystac.Asset):
173
+ cls.ensure_owner_has_extension(obj, add_if_missing)
174
+ return cast(TableExtension[T], AssetTableExtension(obj))
175
+ elif isinstance(obj, pystac.ItemAssetDefinition):
176
+ cls.ensure_owner_has_extension(obj, add_if_missing)
177
+ return cast(TableExtension[T], ItemAssetsTableExtension(obj))
178
+ else:
179
+ raise pystac.ExtensionTypeError(cls._ext_error_message(obj))
180
+
181
+ @property
182
+ def columns(self) -> list[Column] | None:
183
+ """A list of :class:`Column` objects describing each column"""
184
+ v = self.properties.get(COLUMNS_PROP)
185
+ if v is None:
186
+ return None
187
+ return [Column(x) for x in v]
188
+
189
+ @columns.setter
190
+ def columns(self, v: list[Column] | None) -> None:
191
+ self._set_property(COLUMNS_PROP, v)
192
+
193
+ @property
194
+ def primary_geometry(self) -> str | None:
195
+ """The primary geometry column name"""
196
+ return self._get_property(PRIMARY_GEOMETRY_PROP, str)
197
+
198
+ @primary_geometry.setter
199
+ def primary_geometry(self, v: str | None) -> None:
200
+ if v is None:
201
+ self.properties.pop(PRIMARY_GEOMETRY_PROP, None)
202
+ else:
203
+ self.properties[PRIMARY_GEOMETRY_PROP] = v
204
+
205
+ @property
206
+ def row_count(self) -> int | None:
207
+ """The number of rows in the dataset"""
208
+ return self._get_property(ROW_COUNT_PROP, int)
209
+
210
+ @row_count.setter
211
+ def row_count(self, v: int | None) -> None:
212
+ if v is None:
213
+ self.properties.pop(ROW_COUNT_PROP, None)
214
+ else:
215
+ self.properties[ROW_COUNT_PROP] = v
216
+
217
+
218
+ class CollectionTableExtension(TableExtension[pystac.Collection]):
219
+ """A concrete implementation of :class:`TableExtension` on a
220
+ :class:`~pystac.Collection` that extends the properties of the Item to include
221
+ properties defined in the :stac-ext:`Table Extension <table>`.
222
+
223
+ This class should generally not be instantiated directly. Instead, call
224
+ :meth:`TableExtension.ext` on an :class:`~pystac.Collection` to extend it.
225
+ """
226
+
227
+ collection: pystac.Collection
228
+ properties: dict[str, Any]
229
+
230
+ def __init__(self, collection: pystac.Collection):
231
+ self.collection = collection
232
+ self.properties = collection.extra_fields
233
+
234
+ @property
235
+ def tables(self) -> dict[str, Table]:
236
+ """A mapping of table names to table objects"""
237
+ return get_required(self.properties.get(TABLES_PROP), self, TABLES_PROP)
238
+
239
+ @tables.setter
240
+ def tables(self, v: dict[str, Table]) -> None:
241
+ self.properties[TABLES_PROP] = v
242
+
243
+ def __repr__(self) -> str:
244
+ return f"<CollectionTableExtension Item id={self.collection.id}>"
245
+
246
+
247
+ class ItemTableExtension(TableExtension[pystac.Item]):
248
+ """A concrete implementation of :class:`TableExtension` on an
249
+ :class:`~pystac.Item` that extends the properties of the Item to include properties
250
+ defined in the :stac-ext:`Table Extension <table>`.
251
+
252
+ This class should generally not be instantiated directly. Instead, call
253
+ :meth:`TableExtension.ext` on an :class:`~pystac.Item` to extend it.
254
+ """
255
+
256
+ item: pystac.Item
257
+ properties: dict[str, Any]
258
+
259
+ def __init__(self, item: pystac.Item):
260
+ self.item = item
261
+ self.properties = item.properties
262
+
263
+ def __repr__(self) -> str:
264
+ return f"<ItemTableExtension Item id={self.item.id}>"
265
+
266
+
267
+ class AssetTableExtension(TableExtension[pystac.Asset]):
268
+ """A concrete implementation of :class:`TableExtension` on an
269
+ :class:`~pystac.Asset` that extends the Asset fields to include properties defined
270
+ in the :stac-ext:`Table Extension <table>`.
271
+
272
+ This class should generally not be instantiated directly. Instead, call
273
+ :meth:`TableExtension.ext` on an :class:`~pystac.Asset` to extend it.
274
+ """
275
+
276
+ asset_href: str
277
+ properties: dict[str, Any]
278
+ additional_read_properties: Iterable[dict[str, Any]] | None
279
+
280
+ def __init__(self, asset: pystac.Asset):
281
+ self.asset_href = asset.href
282
+ self.properties = asset.extra_fields
283
+ if asset.owner and isinstance(asset.owner, pystac.Item):
284
+ self.additional_read_properties = [asset.owner.properties]
285
+ else:
286
+ self.additional_read_properties = None
287
+
288
+ @property
289
+ def storage_options(self) -> dict[str, Any] | None:
290
+ """Additional keywords for opening the dataset"""
291
+ return self.properties.get(STORAGE_OPTIONS_PROP)
292
+
293
+ @storage_options.setter
294
+ def storage_options(self, v: dict[str, Any] | None) -> Any:
295
+ if v is None:
296
+ self.properties.pop(STORAGE_OPTIONS_PROP, None)
297
+ else:
298
+ self.properties[STORAGE_OPTIONS_PROP] = v
299
+
300
+ def __repr__(self) -> str:
301
+ return f"<AssetTableExtension Item id={self.asset_href}>"
302
+
303
+
304
+ class ItemAssetsTableExtension(TableExtension[pystac.ItemAssetDefinition]):
305
+ properties: dict[str, Any]
306
+ asset_defn: pystac.ItemAssetDefinition
307
+
308
+ def __init__(self, item_asset: pystac.ItemAssetDefinition):
309
+ self.asset_defn = item_asset
310
+ self.properties = item_asset.properties
311
+
312
+
313
+ class TableExtensinoHooks(ExtensionHooks):
314
+ schema_uri: str = SCHEMA_URI
315
+ prev_extension_ids = {
316
+ "table",
317
+ "https://stac-extensions.github.io/table/v1.0.0/schema.json",
318
+ "https://stac-extensions.github.io/table/v1.0.1/schema.json",
319
+ "https://stac-extensions.github.io/table/v1.1.0/schema.json",
320
+ }
321
+ stac_object_types = {pystac.STACObjectType.COLLECTION, pystac.STACObjectType.ITEM}
322
+
323
+
324
+ TABLE_EXTENSION_HOOKS: ExtensionHooks = TableExtensinoHooks()
@@ -0,0 +1,37 @@
1
+ Metadata-Version: 2.4
2
+ Name: pystac-ext-table
3
+ Version: 1.2.0
4
+ Summary: Table extension for PySTAC
5
+ Project-URL: Documentation, https://pystac.readthedocs.io
6
+ Project-URL: Repository, https://github.com/stac-utils/pystac
7
+ Project-URL: Issues, https://github.com/stac-utils/pystac/issues
8
+ Project-URL: Changelog, https://github.com/stac-utils/pystac/blob/main/CHANGELOG.md
9
+ Project-URL: Discussions, https://github.com/radiantearth/stac-spec/discussions/categories/stac-software
10
+ License: Apache-2.0
11
+ Keywords: STAC,catalog,imagery,pystac,raster,table
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Natural Language :: English
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: pystac-core
23
+ Description-Content-Type: text/markdown
24
+
25
+ # pystac-ext-table
26
+
27
+ [PySTAC](https://pypi.org/project/pystac/) extension package for the [Table Extension](https://github.com/stac-extensions/table).
28
+ This extension provides fields for describing tabular data assets, including column definitions, row counts, primary/foreign keys, and storage formats.
29
+
30
+ ## Supported versions
31
+
32
+ - [v1.2.0](https://stac-extensions.github.io/table/v1.2.0/schema.json)
33
+
34
+ ## Versioning
35
+
36
+ This package's version corresponds to the version of the extension specification it targets.
37
+ When we release updates to the package code without changing the target extension version, we use [post releases](https://packaging.python.org/en/latest/discussions/versioning/#post-releases), e.g. `1.2.0.post1`.
@@ -0,0 +1,5 @@
1
+ pystac/extensions/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ pystac/extensions/table.py,sha256=MEamMU8cYTUKFvb4Cm7cY5Pqar71kZYWoZGnCqmevaY,11050
3
+ pystac_ext_table-1.2.0.dist-info/METADATA,sha256=hZ29XA34ml8x7eaoOmDF7OVYM1LJv3Idmx5NPKUoqVM,1807
4
+ pystac_ext_table-1.2.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
5
+ pystac_ext_table-1.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any