pystac-ext-scientific 1.0.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.
- pystac_ext_scientific-1.0.0/.gitignore +163 -0
- pystac_ext_scientific-1.0.0/PKG-INFO +37 -0
- pystac_ext_scientific-1.0.0/README.md +13 -0
- pystac_ext_scientific-1.0.0/pyproject.toml +36 -0
- pystac_ext_scientific-1.0.0/pystac/extensions/py.typed +0 -0
- pystac_ext_scientific-1.0.0/pystac/extensions/scientific.py +360 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_citation.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_collection_citation.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_collection_doi.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_collection_publications.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_collection_publications_one.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_collection_remove_all_publications_one.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_collection_remove_all_publications_with_none.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_collection_remove_all_publications_with_some.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_collection_remove_publication_forward.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_collection_remove_publication_one.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_collection_remove_publication_reverse.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_doi.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_publications.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_publications_one.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_remove_all_publications_one.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_remove_all_publications_with_none.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_remove_all_publications_with_some.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_remove_publication_forward.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_remove_publication_one.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/cassettes/test_scientific/test_remove_publication_reverse.yaml +88 -0
- pystac_ext_scientific-1.0.0/tests/data-files/collection.json +63 -0
- pystac_ext_scientific-1.0.0/tests/data-files/item.json +80 -0
- pystac_ext_scientific-1.0.0/tests/test_scientific.py +514 -0
|
@@ -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-scientific
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Scientific 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,scientific
|
|
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-scientific
|
|
26
|
+
|
|
27
|
+
[PySTAC](https://pypi.org/project/pystac/) extension package for the [Scientific Citation Extension](https://github.com/stac-extensions/scientific).
|
|
28
|
+
This extension provides fields for linking STAC items and collections to scientific publications, including DOIs and bibliographic citations.
|
|
29
|
+
|
|
30
|
+
## Supported versions
|
|
31
|
+
|
|
32
|
+
- [v1.0.0](https://stac-extensions.github.io/scientific/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-scientific
|
|
2
|
+
|
|
3
|
+
[PySTAC](https://pypi.org/project/pystac/) extension package for the [Scientific Citation Extension](https://github.com/stac-extensions/scientific).
|
|
4
|
+
This extension provides fields for linking STAC items and collections to scientific publications, including DOIs and bibliographic citations.
|
|
5
|
+
|
|
6
|
+
## Supported versions
|
|
7
|
+
|
|
8
|
+
- [v1.0.0](https://stac-extensions.github.io/scientific/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-scientific"
|
|
3
|
+
description = "Scientific extension for PySTAC"
|
|
4
|
+
readme = "README.md"
|
|
5
|
+
version = "1.0.0"
|
|
6
|
+
authors = []
|
|
7
|
+
maintainers = []
|
|
8
|
+
keywords = ["pystac", "imagery", "raster", "catalog", "STAC", "scientific"]
|
|
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,360 @@
|
|
|
1
|
+
"""Implements the :stac-ext:`Scientific Citation Extension <scientific>`.
|
|
2
|
+
|
|
3
|
+
For a description of Digital Object Identifiers (DOIs), see the DOI Handbook:
|
|
4
|
+
|
|
5
|
+
https://doi.org/10.1000/182
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, Generic, Literal, TypeVar, cast
|
|
11
|
+
|
|
12
|
+
import pystac
|
|
13
|
+
from pystac.extensions.base import (
|
|
14
|
+
ExtensionManagementMixin,
|
|
15
|
+
PropertiesExtension,
|
|
16
|
+
SummariesExtension,
|
|
17
|
+
)
|
|
18
|
+
from pystac.extensions.hooks import ExtensionHooks
|
|
19
|
+
from pystac.utils import StringEnum, map_opt
|
|
20
|
+
|
|
21
|
+
#: Generalized version of :class:`~pystac.Collection` or :class:`~pystac.Item`
|
|
22
|
+
T = TypeVar("T", pystac.Collection, pystac.Item)
|
|
23
|
+
|
|
24
|
+
SCHEMA_URI: str = "https://stac-extensions.github.io/scientific/v1.0.0/schema.json"
|
|
25
|
+
PREFIX: str = "sci:"
|
|
26
|
+
|
|
27
|
+
# Field names
|
|
28
|
+
DOI_PROP: str = PREFIX + "doi"
|
|
29
|
+
CITATION_PROP: str = PREFIX + "citation"
|
|
30
|
+
PUBLICATIONS_PROP: str = PREFIX + "publications"
|
|
31
|
+
|
|
32
|
+
DOI_URL_BASE = "https://doi.org/"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# Link rel type.
|
|
36
|
+
class ScientificRelType(StringEnum):
|
|
37
|
+
"""A list of rel types defined in the Scientific Citation Extension.
|
|
38
|
+
|
|
39
|
+
See the :stac-ext:`Scientific Citation Extension Relation types
|
|
40
|
+
<scientific#relation-types>` documentation for details.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
CITE_AS = "cite-as"
|
|
44
|
+
"""Used to indicate a link to the publication referenced by the ``sci:doi``
|
|
45
|
+
field."""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def doi_to_url(doi: str) -> str:
|
|
49
|
+
"""Converts a DOI to the corresponding URL."""
|
|
50
|
+
from urllib import parse
|
|
51
|
+
|
|
52
|
+
return DOI_URL_BASE + parse.quote(doi)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class Publication:
|
|
56
|
+
"""Helper for Publication entries."""
|
|
57
|
+
|
|
58
|
+
citation: str | None
|
|
59
|
+
doi: str | None
|
|
60
|
+
|
|
61
|
+
def __init__(self, doi: str | None, citation: str | None) -> None:
|
|
62
|
+
self.doi = doi
|
|
63
|
+
self.citation = citation
|
|
64
|
+
|
|
65
|
+
def __eq__(self, other: Any) -> bool:
|
|
66
|
+
if not isinstance(other, Publication):
|
|
67
|
+
return NotImplemented
|
|
68
|
+
|
|
69
|
+
return self.doi == other.doi and self.citation == other.citation
|
|
70
|
+
|
|
71
|
+
def __repr__(self) -> str:
|
|
72
|
+
return f"<Publication doi={self.doi} target={self.citation}>"
|
|
73
|
+
|
|
74
|
+
def to_dict(self) -> dict[str, str | None]:
|
|
75
|
+
import copy
|
|
76
|
+
|
|
77
|
+
return copy.deepcopy({"doi": self.doi, "citation": self.citation})
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def from_dict(d: dict[str, str]) -> Publication:
|
|
81
|
+
return Publication(d.get("doi"), d.get("citation"))
|
|
82
|
+
|
|
83
|
+
def get_link(self) -> pystac.Link | None:
|
|
84
|
+
"""Gets a :class:`~pystac.Link` for the DOI for this publication. If
|
|
85
|
+
:attr:`Publication.doi` is ``None``, this method will also return ``None``."""
|
|
86
|
+
if self.doi is None:
|
|
87
|
+
return None
|
|
88
|
+
return pystac.Link(ScientificRelType.CITE_AS, doi_to_url(self.doi))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def remove_link(links: list[pystac.Link], doi: str | None) -> None:
|
|
92
|
+
if doi is None:
|
|
93
|
+
return
|
|
94
|
+
url = doi_to_url(doi)
|
|
95
|
+
for i, a_link in enumerate(links):
|
|
96
|
+
if a_link.rel != ScientificRelType.CITE_AS:
|
|
97
|
+
continue
|
|
98
|
+
if a_link.target == url:
|
|
99
|
+
del links[i]
|
|
100
|
+
break
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class ScientificExtension(
|
|
104
|
+
Generic[T],
|
|
105
|
+
PropertiesExtension,
|
|
106
|
+
ExtensionManagementMixin[pystac.Item | pystac.Collection],
|
|
107
|
+
):
|
|
108
|
+
"""An abstract class that can be used to extend the properties of an
|
|
109
|
+
:class:`~pystac.Item` or a :class:`pystac.Collection` with properties from the
|
|
110
|
+
:stac-ext:`Scientific Citation Extension <scientific>`. This class is generic over
|
|
111
|
+
the type of STAC Object to be extended (e.g. :class:`~pystac.Item`,
|
|
112
|
+
:class:`~pystac.Collection`).
|
|
113
|
+
|
|
114
|
+
To create a concrete instance of :class:`ScientificExtension`, use the
|
|
115
|
+
:meth:`ScientificExtension.ext` method. For example:
|
|
116
|
+
|
|
117
|
+
.. code-block:: python
|
|
118
|
+
|
|
119
|
+
>>> item: pystac.Item = ...
|
|
120
|
+
>>> sci_ext = ScientificExtension.ext(item)
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
name: Literal["sci"] = "sci"
|
|
124
|
+
obj: pystac.STACObject
|
|
125
|
+
|
|
126
|
+
def __init__(self, obj: pystac.STACObject) -> None:
|
|
127
|
+
self.obj = obj
|
|
128
|
+
|
|
129
|
+
def apply(
|
|
130
|
+
self,
|
|
131
|
+
doi: str | None = None,
|
|
132
|
+
citation: str | None = None,
|
|
133
|
+
publications: list[Publication] | None = None,
|
|
134
|
+
) -> None:
|
|
135
|
+
"""Applies scientific extension properties to the extended
|
|
136
|
+
:class:`~pystac.Item`.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
doi : Optional DOI string for the item. Must not be a DOI link.
|
|
140
|
+
citation : Optional human-readable reference.
|
|
141
|
+
publications : Optional list of relevant publications
|
|
142
|
+
referencing and describing the data.
|
|
143
|
+
"""
|
|
144
|
+
self.doi = doi
|
|
145
|
+
self.citation = citation
|
|
146
|
+
self.publications = publications
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def doi(self) -> str | None:
|
|
150
|
+
"""Get or sets the DOI for the item.
|
|
151
|
+
|
|
152
|
+
This MUST NOT be a DOIs link. For all DOI names respective DOI links SHOULD be
|
|
153
|
+
added to the links section.
|
|
154
|
+
"""
|
|
155
|
+
return self._get_property(DOI_PROP, str)
|
|
156
|
+
|
|
157
|
+
@doi.setter
|
|
158
|
+
def doi(self, v: str | None) -> None:
|
|
159
|
+
if DOI_PROP in self.properties:
|
|
160
|
+
if v == self.properties[DOI_PROP]:
|
|
161
|
+
return
|
|
162
|
+
remove_link(self.obj.links, self.properties[DOI_PROP])
|
|
163
|
+
|
|
164
|
+
if v is not None:
|
|
165
|
+
self.properties[DOI_PROP] = v
|
|
166
|
+
url = doi_to_url(v)
|
|
167
|
+
self.obj.add_link(pystac.Link(ScientificRelType.CITE_AS, url))
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def citation(self) -> str | None:
|
|
171
|
+
"""Get or sets the recommended human-readable reference (citation) to be used by
|
|
172
|
+
publications citing the data.
|
|
173
|
+
|
|
174
|
+
No specific citation style is suggested, but the citation should contain all
|
|
175
|
+
information required to find the publication distinctively.
|
|
176
|
+
"""
|
|
177
|
+
return self._get_property(CITATION_PROP, str)
|
|
178
|
+
|
|
179
|
+
@citation.setter
|
|
180
|
+
def citation(self, v: str | None) -> None:
|
|
181
|
+
self._set_property(CITATION_PROP, v)
|
|
182
|
+
|
|
183
|
+
@property
|
|
184
|
+
def publications(self) -> list[Publication] | None:
|
|
185
|
+
"""Get or sets the list of relevant publications referencing and describing the
|
|
186
|
+
data."""
|
|
187
|
+
return map_opt(
|
|
188
|
+
lambda pubs: [Publication.from_dict(pub) for pub in pubs],
|
|
189
|
+
self._get_property(PUBLICATIONS_PROP, list[dict[str, Any]]),
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
@publications.setter
|
|
193
|
+
def publications(self, v: list[Publication] | None) -> None:
|
|
194
|
+
self._set_property(
|
|
195
|
+
PUBLICATIONS_PROP, map_opt(lambda pubs: [pub.to_dict() for pub in pubs], v)
|
|
196
|
+
)
|
|
197
|
+
if v is not None:
|
|
198
|
+
for pub in v:
|
|
199
|
+
pub_link = pub.get_link()
|
|
200
|
+
if pub_link is not None:
|
|
201
|
+
self.obj.add_link(pub_link)
|
|
202
|
+
|
|
203
|
+
# None for publication will clear all.
|
|
204
|
+
def remove_publication(self, publication: Publication | None = None) -> None:
|
|
205
|
+
"""Removes the given :class:`Publication` from the extended
|
|
206
|
+
:class:`~pystac.Item`. If the ``publication`` argument is ``None``, all
|
|
207
|
+
publications will be removed from the :class:`~pystac.Item`."""
|
|
208
|
+
if PUBLICATIONS_PROP not in self.properties:
|
|
209
|
+
return
|
|
210
|
+
|
|
211
|
+
if not publication:
|
|
212
|
+
pubs = self.publications
|
|
213
|
+
if pubs is not None:
|
|
214
|
+
for one_pub in pubs:
|
|
215
|
+
remove_link(self.obj.links, one_pub.doi)
|
|
216
|
+
|
|
217
|
+
del self.properties[PUBLICATIONS_PROP]
|
|
218
|
+
return
|
|
219
|
+
|
|
220
|
+
# One publication and link to remove
|
|
221
|
+
remove_link(self.obj.links, publication.doi)
|
|
222
|
+
to_remove = publication.to_dict()
|
|
223
|
+
self.properties[PUBLICATIONS_PROP].remove(to_remove)
|
|
224
|
+
|
|
225
|
+
if not self.properties[PUBLICATIONS_PROP]:
|
|
226
|
+
del self.properties[PUBLICATIONS_PROP]
|
|
227
|
+
|
|
228
|
+
@classmethod
|
|
229
|
+
def get_schema_uri(cls) -> str:
|
|
230
|
+
return SCHEMA_URI
|
|
231
|
+
|
|
232
|
+
@classmethod
|
|
233
|
+
def ext(cls, obj: T, add_if_missing: bool = False) -> ScientificExtension[T]:
|
|
234
|
+
"""Extends the given STAC Object with properties from the :stac-ext:`Scientific
|
|
235
|
+
Extension <scientific>`.
|
|
236
|
+
|
|
237
|
+
This extension can be applied to instances of :class:`~pystac.Item` or
|
|
238
|
+
:class:`~pystac.Collection`.
|
|
239
|
+
|
|
240
|
+
Raises:
|
|
241
|
+
|
|
242
|
+
pystac.ExtensionTypeError : If an invalid object type is passed.
|
|
243
|
+
"""
|
|
244
|
+
if isinstance(obj, pystac.Collection):
|
|
245
|
+
cls.ensure_has_extension(obj, add_if_missing)
|
|
246
|
+
return cast(ScientificExtension[T], CollectionScientificExtension(obj))
|
|
247
|
+
if isinstance(obj, pystac.Item):
|
|
248
|
+
cls.ensure_has_extension(obj, add_if_missing)
|
|
249
|
+
return cast(ScientificExtension[T], ItemScientificExtension(obj))
|
|
250
|
+
else:
|
|
251
|
+
raise pystac.ExtensionTypeError(cls._ext_error_message(obj))
|
|
252
|
+
|
|
253
|
+
@classmethod
|
|
254
|
+
def summaries(
|
|
255
|
+
cls, obj: pystac.Collection, add_if_missing: bool = False
|
|
256
|
+
) -> SummariesScientificExtension:
|
|
257
|
+
"""Returns the extended summaries object for the given collection."""
|
|
258
|
+
cls.ensure_has_extension(obj, add_if_missing)
|
|
259
|
+
return SummariesScientificExtension(obj)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class CollectionScientificExtension(ScientificExtension[pystac.Collection]):
|
|
263
|
+
"""A concrete implementation of :class:`ScientificExtension` on an
|
|
264
|
+
:class:`~pystac.Collection` that extends the properties of the Item to include
|
|
265
|
+
properties defined in the :stac-ext:`Scientific Citation Extension <scientific>`.
|
|
266
|
+
|
|
267
|
+
This class should generally not be instantiated directly. Instead, call
|
|
268
|
+
:meth:`ScientificExtension.ext` on an :class:`~pystac.Collection` to extend it.
|
|
269
|
+
"""
|
|
270
|
+
|
|
271
|
+
collection: pystac.Collection
|
|
272
|
+
"""The :class:`~pystac.Collection` being extended."""
|
|
273
|
+
|
|
274
|
+
properties: dict[str, Any]
|
|
275
|
+
"""The :class:`~pystac.Collection` properties, including extension properties."""
|
|
276
|
+
|
|
277
|
+
links: list[pystac.Link]
|
|
278
|
+
"""The list of :class:`~pystac.Link` objects associated with the
|
|
279
|
+
:class:`~pystac.Collection` being extended, including links added by this extension.
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
def __init__(self, collection: pystac.Collection):
|
|
283
|
+
self.collection = collection
|
|
284
|
+
self.properties = collection.extra_fields
|
|
285
|
+
self.links = collection.links
|
|
286
|
+
super().__init__(self.collection)
|
|
287
|
+
|
|
288
|
+
def __repr__(self) -> str:
|
|
289
|
+
return "<CollectionScientificExtension Collection id={}>".format(
|
|
290
|
+
self.collection.id
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class ItemScientificExtension(ScientificExtension[pystac.Item]):
|
|
295
|
+
"""A concrete implementation of :class:`ScientificExtension` on an
|
|
296
|
+
:class:`~pystac.Item` that extends the properties of the Item to include
|
|
297
|
+
properties defined in the :stac-ext:`Scientific Citation Extension
|
|
298
|
+
<scientific>`.
|
|
299
|
+
|
|
300
|
+
This class should generally not be instantiated directly. Instead, call
|
|
301
|
+
:meth:`ScientificExtension.ext` on an :class:`~pystac.Item` to extend it.
|
|
302
|
+
"""
|
|
303
|
+
|
|
304
|
+
item: pystac.Item
|
|
305
|
+
"""The :class:`~pystac.Item` being extended."""
|
|
306
|
+
|
|
307
|
+
properties: dict[str, Any]
|
|
308
|
+
"""The :class:`~pystac.Item` properties, including extension properties."""
|
|
309
|
+
|
|
310
|
+
links: list[pystac.Link]
|
|
311
|
+
"""The list of :class:`~pystac.Link` objects associated with the
|
|
312
|
+
:class:`~pystac.Item` being extended, including links added by this extension.
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
def __init__(self, item: pystac.Item):
|
|
316
|
+
self.item = item
|
|
317
|
+
self.properties = item.properties
|
|
318
|
+
self.links = item.links
|
|
319
|
+
super().__init__(self.item)
|
|
320
|
+
|
|
321
|
+
def __repr__(self) -> str:
|
|
322
|
+
return f"<ItemScientificExtension Item id={self.item.id}>"
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class SummariesScientificExtension(SummariesExtension):
|
|
326
|
+
"""A concrete implementation of :class:`~pystac.extensions.base.SummariesExtension`
|
|
327
|
+
that extends the ``summaries`` field of a :class:`~pystac.Collection` to include
|
|
328
|
+
properties defined in the :stac-ext:`Scientific Citation Extension <scientific>`.
|
|
329
|
+
"""
|
|
330
|
+
|
|
331
|
+
@property
|
|
332
|
+
def citation(self) -> list[str] | None:
|
|
333
|
+
"""Get or sets the summary of :attr:`ScientificExtension.citation` values
|
|
334
|
+
for this Collection.
|
|
335
|
+
"""
|
|
336
|
+
return self.summaries.get_list(CITATION_PROP)
|
|
337
|
+
|
|
338
|
+
@citation.setter
|
|
339
|
+
def citation(self, v: list[str] | None) -> None:
|
|
340
|
+
self._set_summary(CITATION_PROP, v)
|
|
341
|
+
|
|
342
|
+
@property
|
|
343
|
+
def doi(self) -> list[str] | None:
|
|
344
|
+
"""Get or sets the summary of :attr:`ScientificExtension.citation` values
|
|
345
|
+
for this Collection.
|
|
346
|
+
"""
|
|
347
|
+
return self.summaries.get_list(DOI_PROP)
|
|
348
|
+
|
|
349
|
+
@doi.setter
|
|
350
|
+
def doi(self, v: list[str] | None) -> None:
|
|
351
|
+
self._set_summary(DOI_PROP, v)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class ScientificExtensionHooks(ExtensionHooks):
|
|
355
|
+
schema_uri: str = SCHEMA_URI
|
|
356
|
+
prev_extension_ids = {"scientific"}
|
|
357
|
+
stac_object_types = {pystac.STACObjectType.COLLECTION, pystac.STACObjectType.ITEM}
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
SCIENTIFIC_EXTENSION_HOOKS: ExtensionHooks = ScientificExtensionHooks()
|