Skip to content

Commit 6c4af70

Browse files
jsignellgadomski
andauthored
Configurable warnings (#480)
* Xarray-style options * Refine options and add mechanism to easily respond to events based on options * Fix types * Fix message * Use warnings rather than options * Expect warnings * Add another warning and put back assert_conforms_to * Rollback to passing tests * Apply suggestions from code review Co-authored-by: Pete Gadomski <[email protected]> * Get rid of ignore_conformance * Let users control conformsTo * Fix up tests * Rewrite a cassette * Rewrite a cassette * More tests to demonstrate helper methods * Tests for altering conforms_to via cli * Add cassettes * fix, tests: rewrite some cassettes, filter warning * Put back in `ignore_conformance` * Apply suggestions from code review Co-authored-by: Pete Gadomski <[email protected]> * Make warnings easier to use * Add _supports_collections * Better examples * Don't deprecate stac_io, add warnings for conformance * Make sure stacklevel is always 2 * Try again to record the cassette * Docs and simplify a bit * tests: rewrite cassette * Start working on docs * Respond to PR comments * Finish first pass at docs * Update docs/usage.rst Co-authored-by: Pete Gadomski <[email protected]> * Don't capture warnings in logs * Update changelog --------- Co-authored-by: Pete Gadomski <[email protected]>
1 parent 02db5c3 commit 6c4af70

30 files changed

+2156
-507
lines changed

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1010
### Added
1111

1212
- Timeout option added to `Client.open` [#463](https://github.com/stac-utils/pystac-client/pull/463)
13+
- Support for fetching catalog queryables [#477](https://github.com/stac-utils/pystac-client/pull/477)
14+
- PySTAC Client specific warnings [#480](https://github.com/stac-utils/pystac-client/pull/480)
1315

1416
### Changed
1517

@@ -26,9 +28,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
2628
- Three tests that were false positives due to out-of-date cassettes [#491](https://github.com/stac-utils/pystac-client/pull/491)
2729
- Max items checks when paging [#492](https://github.com/stac-utils/pystac-client/pull/492)
2830

29-
### Added
31+
### Removed
32+
33+
- ``pystac_client.conformance.CONFORMANCE_URIS`` dictionary [#480](https://github.com/stac-utils/pystac-client/pull/480)
3034

31-
- Support for fetching catalog queryables [#477](https://github.com/stac-utils/pystac-client/pull/477)
3235

3336
## [v0.6.1] - 2023-03-14
3437

docs/api.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,11 @@ Exceptions
6767
:members:
6868
:undoc-members:
6969
:show-inheritance:
70+
71+
Warnings
72+
--------
73+
74+
.. automodule:: pystac_client.warnings
75+
:members:
76+
:undoc-members:
77+
:show-inheritance:

docs/quickstart.rst

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ the screen (if supported by the STAC API).
1515

1616
.. code-block:: console
1717
18-
$ stac-client search https://earth-search.aws.element84.com/v0 -c sentinel-s2-l2a-cogs --bbox -72.5 40.5 -72 41 --matched
19-
2179 items matched
18+
$ stac-client search https://earth-search.aws.element84.com/v1 -c sentinel-2-l2a --bbox -72.5 40.5 -72 41 --matched
19+
3141 items matched
2020
2121
If the same URL is to be used over and over, define an environment
2222
variable to be used in the CLI call:
2323

2424
.. code-block:: console
2525
26-
$ export STAC_API_URL=https://earth-search.aws.element84.com/v0
27-
$ stac-client search ${STAC_API_URL} -c sentinel-s2-l2a-cogs --bbox -72.5 40.5 -72 41 --datetime 2020-01-01/2020-01-31 --matched
26+
$ export STAC_API_URL=https://earth-search.aws.element84.com/v1
27+
$ stac-client search ${STAC_API_URL} -c sentinel-2-l2a --bbox -72.5 40.5 -72 41 --datetime 2020-01-01/2020-01-31 --matched
2828
48 items matched
2929
3030
Without the ``--matched`` switch, all items will be fetched, paginating
@@ -38,7 +38,7 @@ another process such as
3838

3939
.. code-block:: console
4040
41-
$ stac-client search ${STAC_API_URL} -c sentinel-s2-l2a-cogs --bbox -72.5 40.5 -72 41 --datetime 2020-01-01/2020-01-31 | stacterm cal --label platform
41+
$ stac-client search ${STAC_API_URL} -c sentinel-2-l2a --bbox -72.5 40.5 -72 41 --datetime 2020-01-01/2020-01-31 | stacterm cal --label platform
4242
4343
.. figure:: images/stacterm-cal.png
4444
:alt:
@@ -48,7 +48,7 @@ output to stdout, but instead will be saved to the specified file.
4848

4949
.. code-block:: console
5050
51-
$ stac-client search ${STAC_API_URL} -c sentinel-s2-l2a-cogs --bbox -72.5 40.5 -72 41 --datetime 2020-01-01/2020-01-31 --save items.json
51+
$ stac-client search ${STAC_API_URL} -c sentinel-2-l2a --bbox -72.5 40.5 -72 41 --datetime 2020-01-01/2020-01-31 --save items.json
5252
5353
If the Catalog supports the `Query
5454
extension <https://github.com/radiantearth/stac-api-spec/tree/master/fragments/query>`__,
@@ -79,12 +79,12 @@ than once to use additional operators.
7979

8080
.. code-block:: console
8181
82-
$ stac-client search ${STAC_API_URL} -c sentinel-s2-l2a-cogs --bbox -72.5 40.5 -72 41 --datetime 2020-01-01/2020-01-31 -q "eo:cloud_cover<10" --matched
82+
$ stac-client search ${STAC_API_URL} -c sentinel-2-l2a --bbox -72.5 40.5 -72 41 --datetime 2020-01-01/2020-01-31 -q "eo:cloud_cover<10" --matched
8383
10 items matched
8484
8585
.. code-block:: console
8686
87-
$ stac-client search ${STAC_API_URL} -c sentinel-s2-l2a-cogs --bbox -72.5 40.5 -72 41 --datetime 2020-01-01/2020-01-31 -q "eo:cloud_cover<10" "eo:cloud_cover>5" --matched
87+
$ stac-client search ${STAC_API_URL} -c sentinel-2-l2a --bbox -72.5 40.5 -72 41 --datetime 2020-01-01/2020-01-31 -q "eo:cloud_cover<10" "eo:cloud_cover>5" --matched
8888
4 items matched
8989
9090
Python
@@ -97,36 +97,31 @@ specific STAC API (use the root URL):
9797
9898
from pystac_client import Client
9999
100-
client = Client.open("https://earth-search.aws.element84.com/v0")
100+
client = Client.open("https://earth-search.aws.element84.com/v1")
101101
102102
Create a search:
103103

104104
.. code-block:: python
105105
106-
my_search = client.search(
106+
search = client.search(
107107
max_items=10,
108-
collections=['sentinel-s2-l2a-cogs'],
109-
bbox=[-72.5,40.5,-72,41])
110-
print(f"{my_search.matched()} items found")
108+
collections=['sentinel-2-l2a'],
109+
bbox=[-72.5,40.5,-72,41]
110+
)
111+
print(f"{search.matched()} items found")
111112
112113
The ``items()`` iterator method can be used to iterate through all resulting items.
113114

114115
.. code-block:: python
115116
116-
for item in my_search.items():
117+
for item in search.items():
117118
print(item.id)
118119
119-
To convert all of Items from a search as a single `PySTAC
120-
ItemCollection <https://pystac.readthedocs.io/en/latest/api/pystac.html#pystac.ItemCollection>`__,
121-
you must first do a limited iteration on the iterator to get a list of Items, and then
122-
create an ItemCollection with that. The ``ItemCollection`` can then be saved as a
123-
GeoJSON FeatureCollection.
124-
125-
Save all found items as a single FeatureCollection:
120+
Use `item_collection()` to convert all Items from a search into a single `PySTAC
121+
ItemCollection <https://pystac.readthedocs.io/en/latest/api/pystac.html#pystac.ItemCollection>`__.
122+
The ``ItemCollection`` can then be saved as a GeoJSON FeatureCollection.
126123

127124
.. code-block:: python
128125
129-
from pystac import ItemCollection
130-
131-
my_itemcollection = ItemCollection(items = list(my_search.items()))
132-
my_itemcollection.save_object('my_itemcollection.json')
126+
item_collection = search.item_collection()
127+
item_collection.save_object('my_itemcollection.json')

docs/tutorials/aoi-coverage.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
"\n",
6767
"# Create a Client and an ItemSearch representing our search\n",
6868
"# No search operations will be performed until we call the items() method\n",
69-
"client = Client.open(URL, ignore_conformance=False)\n",
69+
"client = Client.open(URL)\n",
7070
"item_search = client.search(\n",
7171
" collections=[\"sentinel-2-l2a\"], intersects=intersects_geometry, max_items=100\n",
7272
")"

docs/tutorials/cql2-filter.ipynb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"cells": [
33
{
4+
"attachments": {},
45
"cell_type": "markdown",
56
"id": "e06a27bf",
67
"metadata": {},
@@ -9,7 +10,7 @@
910
"\n",
1011
"This notebook demonstrates the use of pystac-client to use [CQL2 filtering](https://github.com/radiantearth/stac-api-spec/tree/master/fragments/filter). The server needs to support this and advertise conformance as the `https://api.stacspec.org/v1.0.0-rc.1/item-search#filter` class in the `conformsTo` attribute of the root API.\n",
1112
"\n",
12-
"**This should be considered an experimental feature. This notebook uses the Microsoft Planetary Computer API, as it is currently the only public CQL2 implementation. The Planetary Computer API also does not yet advertise the correct conformance class, thus the `ignore_conformance` keyword is specified in the `Client.open` function below.**"
13+
"**This should be considered an experimental feature. This notebook uses the Microsoft Planetary Computer API, as it is currently the only public CQL2 implementation.**"
1314
]
1415
},
1516
{
@@ -61,7 +62,7 @@
6162
"# custom headers\n",
6263
"headers = []\n",
6364
"\n",
64-
"cat = Client.open(URL, headers=headers, ignore_conformance=True)"
65+
"cat = Client.open(URL, headers=headers)"
6566
]
6667
},
6768
{

docs/usage.rst

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -39,37 +39,35 @@ includes convenience methods and attributes for:
3939

4040
* Checking conformance to various specs
4141
* Querying a search endpoint (if the API conforms to the STAC API - Item Search spec)
42+
* Getting jsonschema of queryables from `/queryables` endpoint (if the API conforms
43+
to the STAC API - Filter spec)
4244

4345
The preferred way to interact with any STAC Catalog or API is to create an
4446
:class:`pystac_client.Client` instance with the ``pystac_client.Client.open`` method
45-
on a root Catalog. This calls the :meth:`pystac.STACObject.from_file` except
47+
on a root Catalog. This calls the :meth:`pystac.STACObject.from_file` except it
4648
properly configures conformance and IO for reading from remote servers.
4749

4850
The following code creates an instance by making a call to the Microsoft Planetary
4951
Computer root catalog.
5052

5153
.. code-block:: python
5254
53-
>>> from pystac_client.Client import Client
54-
>>> api = Client.open('https://planetarycomputer.microsoft.com/api/stac/v1')
55-
>>> api.title
56-
'microsoft-pc'
55+
>>> from pystac_client import Client
56+
>>> catalog = Client.open('https://planetarycomputer.microsoft.com/api/stac/v1')
57+
>>> catalog.title
58+
'Microsoft Planetary Computer STAC API'
5759
5860
Some functions, such as ``Client.search`` will throw an error if the provided
5961
Catalog/API does not support the required Conformance Class. In other cases,
6062
such as ``Client.get_collections``, API endpoints will be used if the API
6163
conforms, otherwise it will fall back to default behavior provided by
6264
:class:`pystac.Catalog`.
6365

64-
Users may optionally provide an ``ignore_conformance`` argument when opening,
65-
in which case pystac-client will not check for conformance and will assume
66-
this is a fully featured API. This can cause unusual errors to be thrown if the API
67-
does not in fact conform to the expected behavior.
68-
69-
In addition to the methods and attributes inherited from :class:`pystac.Catalog`,
70-
this class offers more efficient methods (if used with an API) for getting collections
71-
and items, as well as a search capability, utilizing the
72-
:class:`pystac_client.ItemSearch` class.
66+
When a ``Client`` does not conform to a particular Conformance Class, an informative
67+
warning is raised. Similarly when falling back to the :class:`pystac.Catalog`
68+
implementation a warning is raised. You can control the behavior of these warnings
69+
using the standard :py:mod:`warnings` or special context managers :func:`pystac_client.warnings.strict` and
70+
from :func:`pystac_client.warnings.ignore`.
7371

7472
API Conformance
7573
---------------
@@ -83,53 +81,69 @@ A STAC API is a STAC Catalog that is required to advertise its capabilities in a
8381
`conformsTo` field and implements the `STAC API - Core` spec along with other
8482
optional specifications:
8583

86-
* `STAC API - Core <https://github.com/radiantearth/stac-api-spec/tree/master/core>`__
87-
* `STAC API - Item Search <https://github.com/radiantearth/stac-api-spec/tree/master/item-search>`__
88-
* `Fields Extension <https://github.com/radiantearth/stac-api-spec/tree/master/fragments/fields>`__
89-
* `Query Extension <https://github.com/radiantearth/stac-api-spec/tree/master/fragments/query>`__
90-
* `Sort Extension <https://github.com/radiantearth/stac-api-spec/tree/master/fragments/sort>`__
91-
* `Context Extension <https://github.com/radiantearth/stac-api-spec/tree/master/fragments/context>`__
92-
* `Filter Extension <https://github.com/radiantearth/stac-api-spec/tree/master/fragments/filter>`__
93-
* `STAC API - Features <https://github.com/radiantearth/stac-api-spec/tree/master/ogcapi-features>`__ (based on
84+
* `CORE <https://github.com/radiantearth/stac-api-spec/tree/master/core>`__
85+
* `ITEM_SEARCH <https://github.com/radiantearth/stac-api-spec/tree/master/item-search>`__
86+
* `FIELDS <https://github.com/radiantearth/stac-api-spec/tree/master/fragments/fields>`__
87+
* `QUERY <https://github.com/radiantearth/stac-api-spec/tree/master/fragments/query>`__
88+
* `SORT <https://github.com/radiantearth/stac-api-spec/tree/master/fragments/sort>`__
89+
* `CONTEXT <https://github.com/radiantearth/stac-api-spec/tree/master/fragments/context>`__
90+
* `FILTER <https://github.com/radiantearth/stac-api-spec/tree/master/fragments/filter>`__
91+
* `COLLECTIONS <https://github.com/radiantearth/stac-api-spec/tree/master/collections>`__ (based on
92+
the `Features Collection section of OGC APO - Features <http://docs.opengeospatial.org/is/17-069r3/17-069r3.html#_collections_>__`)
93+
* `FEATURES <https://github.com/radiantearth/stac-api-spec/tree/master/ogcapi-features>`__ (based on
9494
`OGC API - Features <https://www.ogc.org/standards/ogcapi-features>`__)
9595

9696
The :meth:`pystac_client.Client.conforms_to` method is used to check conformance
9797
against conformance classes (specs). To check an API for support for a given spec,
98-
pass the `conforms_to` function the :class:`ConformanceClasses` attribute as a
99-
parameter.
98+
pass the `conforms_to` function the name of a :class:`ConformanceClasses`.
10099

101100
.. code-block:: python
102101
103-
>>> from pystac_client import ConformanceClasses
104-
>>> api.conforms_to(ConformanceClasses.STAC_API_ITEM_SEARCH)
102+
>>> catalog.conforms_to("ITEM_SEARCH")
105103
True
106104
105+
If the API does not advertise conformance with a particular spec, but it does support
106+
it you can update `conforms_to` on the client object. For instance in `v0` of earth-search
107+
there are no ``"conformsTo"`` uris set at all. But they can be explicitly set:
108+
109+
.. code-block:: python
110+
111+
>>> catalog = Client.open("https://earth-search.aws.element84.com/v0")
112+
<stdin>:1: NoConformsTo: Server does not advertise any conformance classes.
113+
>>> catalog.conforms_to("ITEM_SEARCH")
114+
False
115+
>>> catalog.add_conforms_to("ITEM_SEARCH")
116+
117+
Note, updating ``"conformsTo"`` does not change what the server supports, it just
118+
changes PySTAC client's understanding of what the server supports.
119+
107120
CollectionClient
108121
++++++++++++++++
109122

110-
STAC APIs may provide a curated list of catalogs and collections via their ``"links"``
111-
attribute. Links with a ``"rel"`` type of ``"child"`` represent catalogs or collections
112-
provided by the API. Since :class:`~pystac_client.Client` instances are also
113-
:class:`pystac.Catalog` instances, we can use the methods defined on that class to
114-
get collections:
123+
STAC APIs may optionally implement a ``/collections`` endpoint as describe in the
124+
`STAC API - Collections spec
125+
<https://github.com/radiantearth/stac-api-spec/tree/master/collections>`__. This endpoint
126+
allows clients to search or inspect items within a particular collection.
115127

116128
.. code-block:: python
117129
118-
>>> child_links = api.get_links('child')
119-
>>> len(child_links)
120-
12
121-
>>> first_child_link = api.get_single_link('child')
122-
>>> first_child_link.resolve_stac_object(api)
123-
>>> first_collection = first_child_link.target
124-
>>> first_collection.title
125-
'Landsat 8 C1 T1'
130+
>>> catalog = Client.open('https://planetarycomputer.microsoft.com/api/stac/v1')
131+
>>> collection = catalog.get_collection("sentinel-2-l2a")
132+
>>> collection.title
133+
'Sentinel-2 Level-2A'
134+
135+
:class:`pystac_client.CollectionClient` overrides :meth:`pystac.Collection.get_items`.
136+
PySTAC will get items by iterating through all children until it gets to an ``item`` link.
137+
PySTAC client will use the API endpoint instead: `/collections/<collection_id>/items`
138+
(as long as `STAC API - Item Search spec
139+
<https://github.com/radiantearth/stac-api-spec/tree/master/item-search>`__ is supported).
140+
141+
.. code-block:: python
126142
127-
CollectionClient overrides the :meth:`pystac.Collection.get_items` method. PySTAC will
128-
get items by iterating through all children until it gets to an `item` link. If the
129-
`CollectionClient` instance contains an `items` link, this will instead iterate through
130-
items using the API endpoint instead: `/collections/<collection_id>/items`. If no such
131-
link is present it will fall back to the PySTAC Collection behavior.
143+
>>> item = next(collection.get_items(), None)
132144
145+
Note that calling list on this iterator will take a really long time since it will be retrieving
146+
every itme for the whole ``"sentinel-2-l2a"`` collection.
133147

134148
ItemSearch
135149
++++++++++
@@ -149,8 +163,8 @@ requests to a service's "search" endpoint. This method returns a
149163
.. code-block:: python
150164
151165
>>> from pystac_client import Client
152-
>>> api = Client.open('https://planetarycomputer.microsoft.com/api/stac/v1')
153-
>>> results = api.search(
166+
>>> catalog = Client.open('https://planetarycomputer.microsoft.com/api/stac/v1')
167+
>>> results = catalog.search(
154168
... max_items=5
155169
... bbox=[-73.21, 43.99, -73.12, 44.05],
156170
... datetime=['2019-01-01T00:00:00Z', '2019-01-02T00:00:00Z'],
@@ -307,7 +321,7 @@ modify the STAC objects returned by the STAC API.
307321
308322
>>> from pystac_client import Client
309323
>>> import planetary_computer, requests
310-
>>> api = Client.open(
324+
>>> catalog = Client.open(
311325
... 'https://planetarycomputer.microsoft.com/api/stac/v1',
312326
... modifier=planetary_computer.sign_inplace,
313327
... )

0 commit comments

Comments
 (0)