pystac-ext-view 1.0.0rc0__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,163 @@
1
+ *.pyc
2
+ *.egg-info
3
+ *.eggs
4
+ .DS_Store
5
+ data
6
+ config.json
7
+ stdout*
8
+ /integration*
9
+ .idea
10
+ .vscode
11
+ .actrc
12
+
13
+
14
+ # Sphinx documentation
15
+ .ipynb_checkpoints/
16
+
17
+ docs/tutorials/pystac-example*
18
+ docs/tutorials/spacenet-stac/
19
+ docs/tutorials/spacenet-cog-stac/
20
+ docs/tutorials/data/
21
+ docs/quickstart_stac/
22
+
23
+ # Byte-compiled / optimized / DLL files
24
+ __pycache__/
25
+ *.py[cod]
26
+ *$py.class
27
+
28
+ # C extensions
29
+ *.so
30
+
31
+ # Distribution / packaging
32
+ .Python
33
+ build/
34
+ develop-eggs/
35
+ dist/
36
+ downloads/
37
+ eggs/
38
+ .eggs/
39
+ lib/
40
+ lib64/
41
+ parts/
42
+ sdist/
43
+ var/
44
+ wheels/
45
+ share/python-wheels/
46
+ *.egg-info/
47
+ .installed.cfg
48
+ *.egg
49
+ MANIFEST
50
+
51
+ # PyInstaller
52
+ # Usually these files are written by a python script from a template
53
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
54
+ *.manifest
55
+ *.spec
56
+
57
+ # Installer logs
58
+ pip-log.txt
59
+ pip-delete-this-directory.txt
60
+
61
+ # Unit test / coverage reports
62
+ htmlcov/
63
+ .tox/
64
+ .nox/
65
+ .coverage
66
+ .coverage.*
67
+ .cache
68
+ nosetests.xml
69
+ coverage.xml
70
+ *.cover
71
+ *.py,cover
72
+ .hypothesis/
73
+ .pytest_cache/
74
+ cover/
75
+
76
+ # Translations
77
+ *.mo
78
+ *.pot
79
+
80
+ # Django stuff:
81
+ *.log
82
+ local_settings.py
83
+ db.sqlite3
84
+ db.sqlite3-journal
85
+
86
+ # Flask stuff:
87
+ instance/
88
+ .webassets-cache
89
+
90
+ # Scrapy stuff:
91
+ .scrapy
92
+
93
+ # Sphinx documentation
94
+ docs/_build/
95
+
96
+ # PyBuilder
97
+ .pybuilder/
98
+ target/
99
+
100
+ # Jupyter Notebook
101
+ .ipynb_checkpoints
102
+
103
+ # IPython
104
+ profile_default/
105
+ ipython_config.py
106
+
107
+ # pyenv
108
+ # For a library or package, you might want to ignore these files since the code is
109
+ # intended to run in multiple environments; otherwise, check them in:
110
+ # .python-version
111
+
112
+ # pipenv
113
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
114
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
115
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
116
+ # install all needed dependencies.
117
+ # Pipfile.lock
118
+
119
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
120
+ __pypackages__/
121
+
122
+ # Celery stuff
123
+ celerybeat-schedule
124
+ celerybeat.pid
125
+
126
+ # SageMath parsed files
127
+ *.sage.py
128
+
129
+ # Environments
130
+ .env
131
+ .venv
132
+ env/
133
+ venv/
134
+ ENV/
135
+ env.bak/
136
+ venv.bak/
137
+
138
+ # Spyder project settings
139
+ .spyderproject
140
+ .spyproject
141
+
142
+ # Rope project settings
143
+ .ropeproject
144
+
145
+ # mkdocs documentation
146
+ /site
147
+
148
+ # mypy
149
+ .mypy_cache/
150
+ .dmypy.json
151
+ dmypy.json
152
+
153
+ # Pyre type checker
154
+ .pyre/
155
+
156
+ # pytype static type analyzer
157
+ .pytype/
158
+
159
+ # Cython debug symbols
160
+ cython_debug/
161
+
162
+ # asv environments
163
+ .asv
@@ -0,0 +1,37 @@
1
+ Metadata-Version: 2.4
2
+ Name: pystac-ext-view
3
+ Version: 1.0.0rc0
4
+ Summary: View 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,view
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-view
26
+
27
+ [PySTAC](https://pypi.org/project/pystac/) extension package for the [View Geometry Extension](https://github.com/stac-extensions/view).
28
+ This extension provides fields for describing the angle of observation for geospatial data, including off-nadir angle, incidence angle, azimuth, and sun geometry.
29
+
30
+ ## Supported versions
31
+
32
+ - [v1.0.0](https://stac-extensions.github.io/view/v1.0.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.0.0.post1`.
@@ -0,0 +1,13 @@
1
+ # pystac-ext-view
2
+
3
+ [PySTAC](https://pypi.org/project/pystac/) extension package for the [View Geometry Extension](https://github.com/stac-extensions/view).
4
+ This extension provides fields for describing the angle of observation for geospatial data, including off-nadir angle, incidence angle, azimuth, and sun geometry.
5
+
6
+ ## Supported versions
7
+
8
+ - [v1.0.0](https://stac-extensions.github.io/view/v1.0.0/schema.json)
9
+
10
+ ## Versioning
11
+
12
+ This package's version corresponds to the version of the extension specification it targets.
13
+ 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.0.0.post1`.
@@ -0,0 +1,36 @@
1
+ [project]
2
+ name = "pystac-ext-view"
3
+ description = "View extension for PySTAC"
4
+ readme = "README.md"
5
+ version = "1.0.0-rc.0"
6
+ authors = []
7
+ maintainers = []
8
+ keywords = ["pystac", "imagery", "raster", "catalog", "STAC", "view"]
9
+ license = { text = "Apache-2.0" }
10
+ classifiers = [
11
+ "Development Status :: 5 - Production/Stable",
12
+ "Intended Audience :: Developers",
13
+ "License :: OSI Approved :: Apache Software License",
14
+ "Natural Language :: English",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.10",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
+ "Programming Language :: Python :: 3.13",
20
+ ]
21
+ requires-python = ">=3.10"
22
+ dependencies = ["pystac-core"]
23
+
24
+ [project.urls]
25
+ Documentation = "https://pystac.readthedocs.io"
26
+ Repository = "https://github.com/stac-utils/pystac"
27
+ Issues = "https://github.com/stac-utils/pystac/issues"
28
+ Changelog = "https://github.com/stac-utils/pystac/blob/main/CHANGELOG.md"
29
+ Discussions = "https://github.com/radiantearth/stac-spec/discussions/categories/stac-software"
30
+
31
+ [build-system]
32
+ requires = ["hatchling"]
33
+ build-backend = "hatchling.build"
34
+
35
+ [tool.hatch.build.targets.wheel]
36
+ packages = ["pystac"]
File without changes
@@ -0,0 +1,314 @@
1
+ """Implement the :stac-ext:`View Geometry Extension <view>`."""
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 (
10
+ ExtensionManagementMixin,
11
+ PropertiesExtension,
12
+ SummariesExtension,
13
+ )
14
+ from pystac.extensions.hooks import ExtensionHooks
15
+ from pystac.summaries import RangeSummary
16
+
17
+ #: Generalized version of :class:`~pystac.Item`, :class:`~pystac.Asset`
18
+ #: or :class:`~pystac.ItemAssetDefinition`
19
+ T = TypeVar("T", pystac.Item, pystac.Asset, pystac.ItemAssetDefinition)
20
+
21
+ SCHEMA_URI: str = "https://stac-extensions.github.io/view/v1.0.0/schema.json"
22
+ PREFIX: str = "view:"
23
+
24
+ OFF_NADIR_PROP: str = PREFIX + "off_nadir"
25
+ INCIDENCE_ANGLE_PROP: str = PREFIX + "incidence_angle"
26
+ AZIMUTH_PROP: str = PREFIX + "azimuth"
27
+ SUN_AZIMUTH_PROP: str = PREFIX + "sun_azimuth"
28
+ SUN_ELEVATION_PROP: str = PREFIX + "sun_elevation"
29
+
30
+
31
+ class ViewExtension(
32
+ Generic[T],
33
+ PropertiesExtension,
34
+ ExtensionManagementMixin[pystac.Item | pystac.Collection],
35
+ ):
36
+ """An abstract class that can be used to extend the properties of an
37
+ :class:`~pystac.Item` with properties from the :stac-ext:`View Geometry
38
+ Extension <view>`. This class is generic over the type of STAC Object to be
39
+ extended (e.g. :class:`~pystac.Item`, :class:`~pystac.Asset`).
40
+
41
+ To create a concrete instance of :class:`ViewExtension`, use the
42
+ :meth:`ViewExtension.ext` method. For example:
43
+
44
+ .. code-block:: python
45
+
46
+ >>> item: pystac.Item = ...
47
+ >>> view_ext = ViewExtension.ext(item)
48
+ """
49
+
50
+ name: Literal["view"] = "view"
51
+
52
+ def apply(
53
+ self,
54
+ off_nadir: float | None = None,
55
+ incidence_angle: float | None = None,
56
+ azimuth: float | None = None,
57
+ sun_azimuth: float | None = None,
58
+ sun_elevation: float | None = None,
59
+ ) -> None:
60
+ """Applies View Geometry extension properties to the extended
61
+ :class:`~pystac.Item`.
62
+
63
+ Args:
64
+ off_nadir : The angle from the sensor between nadir (straight down)
65
+ and the scene center. Measured in degrees (0-90).
66
+ incidence_angle : The incidence angle is the angle between the
67
+ vertical (normal) to the intercepting surface and the line of sight
68
+ back to the satellite at the scene center. Measured in degrees (0-90).
69
+ azimuth : Viewing azimuth angle. The angle measured from the
70
+ sub-satellite point (point on the ground below the platform) between
71
+ the scene center and true north. Measured clockwise from north in
72
+ degrees (0-360).
73
+ sun_azimuth : Sun azimuth angle. From the scene center point on the
74
+ ground, this is the angle between truth north and the sun. Measured
75
+ clockwise in degrees (0-360).
76
+ sun_elevation : Sun elevation angle. The angle from the tangent of
77
+ the scene center point to the sun. Measured from the horizon in
78
+ degrees (0-90).
79
+ """
80
+ self.off_nadir = off_nadir
81
+ self.incidence_angle = incidence_angle
82
+ self.azimuth = azimuth
83
+ self.sun_azimuth = sun_azimuth
84
+ self.sun_elevation = sun_elevation
85
+
86
+ @property
87
+ def off_nadir(self) -> float | None:
88
+ """Get or sets the angle from the sensor between nadir (straight down)
89
+ and the scene center. Measured in degrees (0-90).
90
+ """
91
+ return self._get_property(OFF_NADIR_PROP, float)
92
+
93
+ @off_nadir.setter
94
+ def off_nadir(self, v: float | None) -> None:
95
+ self._set_property(OFF_NADIR_PROP, v)
96
+
97
+ @property
98
+ def incidence_angle(self) -> float | None:
99
+ """Get or sets the incidence angle is the angle between the vertical (normal)
100
+ to the intercepting surface and the line of sight back to the satellite at
101
+ the scene center. Measured in degrees (0-90).
102
+ """
103
+ return self._get_property(INCIDENCE_ANGLE_PROP, float)
104
+
105
+ @incidence_angle.setter
106
+ def incidence_angle(self, v: float | None) -> None:
107
+ self._set_property(INCIDENCE_ANGLE_PROP, v)
108
+
109
+ @property
110
+ def azimuth(self) -> float | None:
111
+ """Get or sets the viewing azimuth angle.
112
+
113
+ The angle measured from the sub-satellite
114
+ point (point on the ground below the platform) between the scene center and true
115
+ north. Measured clockwise from north in degrees (0-360).
116
+ """
117
+ return self._get_property(AZIMUTH_PROP, float)
118
+
119
+ @azimuth.setter
120
+ def azimuth(self, v: float | None) -> None:
121
+ self._set_property(AZIMUTH_PROP, v)
122
+
123
+ @property
124
+ def sun_azimuth(self) -> float | None:
125
+ """Get or sets the sun azimuth angle.
126
+
127
+ From the scene center point on the ground, this
128
+ is the angle between truth north and the sun. Measured clockwise in
129
+ degrees (0-360).
130
+ """
131
+ return self._get_property(SUN_AZIMUTH_PROP, float)
132
+
133
+ @sun_azimuth.setter
134
+ def sun_azimuth(self, v: float | None) -> None:
135
+ self._set_property(SUN_AZIMUTH_PROP, v)
136
+
137
+ @property
138
+ def sun_elevation(self) -> float | None:
139
+ """Get or sets the sun elevation angle. The angle from the tangent of the scene
140
+ center point to the sun. Measured from the horizon in degrees (0-90).
141
+ """
142
+ return self._get_property(SUN_ELEVATION_PROP, float)
143
+
144
+ @sun_elevation.setter
145
+ def sun_elevation(self, v: float | None) -> None:
146
+ self._set_property(SUN_ELEVATION_PROP, v)
147
+
148
+ @classmethod
149
+ def get_schema_uri(cls) -> str:
150
+ return SCHEMA_URI
151
+
152
+ @classmethod
153
+ def ext(cls, obj: T, add_if_missing: bool = False) -> ViewExtension[T]:
154
+ """Extends the given STAC Object with properties from the :stac-ext:`View
155
+ Geometry Extension <scientific>`.
156
+
157
+ This extension can be applied to instances of :class:`~pystac.Item` or
158
+ :class:`~pystac.Asset`.
159
+
160
+ Raises:
161
+
162
+ pystac.ExtensionTypeError : If an invalid object type is passed.
163
+ """
164
+ if isinstance(obj, pystac.Item):
165
+ cls.ensure_has_extension(obj, add_if_missing)
166
+ return cast(ViewExtension[T], ItemViewExtension(obj))
167
+ elif isinstance(obj, pystac.Asset):
168
+ cls.ensure_owner_has_extension(obj, add_if_missing)
169
+ return cast(ViewExtension[T], AssetViewExtension(obj))
170
+ elif isinstance(obj, pystac.ItemAssetDefinition):
171
+ cls.ensure_owner_has_extension(obj, add_if_missing)
172
+ return cast(ViewExtension[T], ItemAssetsViewExtension(obj))
173
+ else:
174
+ raise pystac.ExtensionTypeError(cls._ext_error_message(obj))
175
+
176
+ @classmethod
177
+ def summaries(
178
+ cls, obj: pystac.Collection, add_if_missing: bool = False
179
+ ) -> SummariesViewExtension:
180
+ """Returns the extended summaries object for the given collection."""
181
+ cls.ensure_has_extension(obj, add_if_missing)
182
+ return SummariesViewExtension(obj)
183
+
184
+
185
+ class ItemViewExtension(ViewExtension[pystac.Item]):
186
+ """A concrete implementation of :class:`ViewExtension` on an :class:`~pystac.Item`
187
+ that extends the properties of the Item to include properties defined in the
188
+ :stac-ext:`View Geometry Extension <view>`.
189
+
190
+ This class should generally not be instantiated directly. Instead, call
191
+ :meth:`ViewExtension.ext` on an :class:`~pystac.Item` to extend it.
192
+ """
193
+
194
+ item: pystac.Item
195
+ """The :class:`~pystac.Item` being extended."""
196
+
197
+ properties: dict[str, Any]
198
+ """The :class:`~pystac.Item` properties, including extension properties."""
199
+
200
+ def __init__(self, item: pystac.Item):
201
+ self.item = item
202
+ self.properties = item.properties
203
+
204
+ def __repr__(self) -> str:
205
+ return f"<ItemViewExtension Item id={self.item.id}>"
206
+
207
+
208
+ class AssetViewExtension(ViewExtension[pystac.Asset]):
209
+ """A concrete implementation of :class:`ViewExtension` on an :class:`~pystac.Asset`
210
+ that extends the Asset fields to include properties defined in the
211
+ :stac-ext:`View Geometry Extension <view>`.
212
+
213
+ This class should generally not be instantiated directly. Instead, call
214
+ :meth:`ViewExtension.ext` on an :class:`~pystac.Asset` to extend it.
215
+ """
216
+
217
+ asset_href: str
218
+ """The ``href`` value of the :class:`~pystac.Asset` being extended."""
219
+
220
+ properties: dict[str, Any]
221
+ """The :class:`~pystac.Asset` fields, including extension properties."""
222
+
223
+ additional_read_properties: Iterable[dict[str, Any]] | None = None
224
+ """If present, this will be a list containing 1 dictionary representing the
225
+ properties of the owning :class:`~pystac.Item`."""
226
+
227
+ def __init__(self, asset: pystac.Asset):
228
+ self.asset_href = asset.href
229
+ self.properties = asset.extra_fields
230
+ if asset.owner and isinstance(asset.owner, pystac.Item):
231
+ self.additional_read_properties = [asset.owner.properties]
232
+
233
+ def __repr__(self) -> str:
234
+ return f"<AssetViewExtension Asset href={self.asset_href}>"
235
+
236
+
237
+ class ItemAssetsViewExtension(ViewExtension[pystac.ItemAssetDefinition]):
238
+ properties: dict[str, Any]
239
+ asset_defn: pystac.ItemAssetDefinition
240
+
241
+ def __init__(self, item_asset: pystac.ItemAssetDefinition):
242
+ self.asset_defn = item_asset
243
+ self.properties = item_asset.properties
244
+
245
+
246
+ class SummariesViewExtension(SummariesExtension):
247
+ """A concrete implementation of :class:`~pystac.extensions.base.SummariesExtension`
248
+ that extends the ``summaries`` field of a :class:`~pystac.Collection` to include
249
+ properties defined in the :stac-ext:`View Object Extension <view>`.
250
+ """
251
+
252
+ @property
253
+ def off_nadir(self) -> RangeSummary[float] | None:
254
+ """Get or sets the summary of :attr:`ViewExtension.off_nadir` values for
255
+ this Collection.
256
+ """
257
+ return self.summaries.get_range(OFF_NADIR_PROP)
258
+
259
+ @off_nadir.setter
260
+ def off_nadir(self, v: RangeSummary[float] | None) -> None:
261
+ self._set_summary(OFF_NADIR_PROP, v)
262
+
263
+ @property
264
+ def incidence_angle(self) -> RangeSummary[float] | None:
265
+ """Get or sets the summary of :attr:`ViewExtension.incidence_angle` values
266
+ for this Collection.
267
+ """
268
+ return self.summaries.get_range(INCIDENCE_ANGLE_PROP)
269
+
270
+ @incidence_angle.setter
271
+ def incidence_angle(self, v: RangeSummary[float] | None) -> None:
272
+ self._set_summary(INCIDENCE_ANGLE_PROP, v)
273
+
274
+ @property
275
+ def azimuth(self) -> RangeSummary[float] | None:
276
+ """Get or sets the summary of :attr:`ViewExtension.azimuth` values
277
+ for this Collection.
278
+ """
279
+ return self.summaries.get_range(AZIMUTH_PROP)
280
+
281
+ @azimuth.setter
282
+ def azimuth(self, v: RangeSummary[float] | None) -> None:
283
+ self._set_summary(AZIMUTH_PROP, v)
284
+
285
+ @property
286
+ def sun_azimuth(self) -> RangeSummary[float] | None:
287
+ """Get or sets the summary of :attr:`ViewExtension.sun_azimuth` values
288
+ for this Collection.
289
+ """
290
+ return self.summaries.get_range(SUN_AZIMUTH_PROP)
291
+
292
+ @sun_azimuth.setter
293
+ def sun_azimuth(self, v: RangeSummary[float] | None) -> None:
294
+ self._set_summary(SUN_AZIMUTH_PROP, v)
295
+
296
+ @property
297
+ def sun_elevation(self) -> RangeSummary[float] | None:
298
+ """Get or sets the summary of :attr:`ViewExtension.sun_elevation` values
299
+ for this Collection.
300
+ """
301
+ return self.summaries.get_range(SUN_ELEVATION_PROP)
302
+
303
+ @sun_elevation.setter
304
+ def sun_elevation(self, v: RangeSummary[float] | None) -> None:
305
+ self._set_summary(SUN_ELEVATION_PROP, v)
306
+
307
+
308
+ class ViewExtensionHooks(ExtensionHooks):
309
+ schema_uri = SCHEMA_URI
310
+ prev_extension_ids = {"view"}
311
+ stac_object_types = {pystac.STACObjectType.ITEM}
312
+
313
+
314
+ VIEW_EXTENSION_HOOKS: ExtensionHooks = ViewExtensionHooks()