Skip to content

Type fixes #249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 18, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -30,7 +30,6 @@ repos:
hooks:
- id: mypy
files: ".*\\.py$"
exclude: ^tests/.*$
additional_dependencies:
- pystac
- types-requests
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -6,7 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased] - TBD

None
### Fixed

- Fix type annotation of `Client._stac_io` and avoid implicit re-exports in `pystac_client.__init__.py` [#249](https://github.com/stac-utils/pystac-client/pull/249)

## [v0.4.0] - 2022-06-08

2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
sys.path.insert(0, str(Path(__file__).parent.parent.parent.resolve()))
from pystac_client import __version__ # type: ignore # noqa: E402
from pystac_client import __version__ # noqa: E402

git_branch = (
subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"])
7 changes: 7 additions & 0 deletions pystac_client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
# flake8: noqa
__all__ = [
"Client",
"CollectionClient",
"ConformanceClasses",
"ItemSearch",
"__version__",
]

from pystac_client.client import Client
from pystac_client.collection_client import CollectionClient
6 changes: 4 additions & 2 deletions pystac_client/client.py
Original file line number Diff line number Diff line change
@@ -31,6 +31,8 @@ class Client(pystac.Catalog):
such as searching items (e.g., /search endpoint).
"""

_stac_io: Optional[StacApiIO]

def __repr__(self) -> str:
return "<Client id={}>".format(self.id)

@@ -76,7 +78,7 @@ def open(
and len(search_link.href) > 0
)
):
client._stac_io.set_conformance(None) # type: ignore
client._stac_io.set_conformance(None)

return client

@@ -252,7 +254,7 @@ def search(self, **kwargs: Any) -> ItemSearch:

return ItemSearch(
url=search_href,
stac_io=self._stac_io, # type: ignore
stac_io=self._stac_io,
client=self,
**kwargs,
)
2 changes: 2 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -8,6 +8,8 @@ requests-mock~=1.9.3
Sphinx~=3.5.1

mypy~=0.961
types-requests~=2.27.31
types-python-dateutil~=2.8.18
flake8~=4.0.1
black~=22.3.0
codespell~=2.1.0
2 changes: 1 addition & 1 deletion scripts/lint
Original file line number Diff line number Diff line change
@@ -20,6 +20,6 @@ if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
pre-commit run codespell --all-files
pre-commit run doc8 --all-files
pre-commit run flake8 --all-files
# pre-commit run mypy --all-files
pre-commit run mypy --all-files
fi
fi
3 changes: 2 additions & 1 deletion tests/helpers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
from pathlib import Path
from typing import Any

TEST_DATA = Path(__file__).parent / "data"

@@ -10,7 +11,7 @@
}


def read_data_file(file_name: str, mode="r", parse_json=False):
def read_data_file(file_name: str, mode: str = "r", parse_json: bool = False) -> Any:
file_path = TEST_DATA / file_name
with file_path.open(mode=mode) as src:
if parse_json:
6 changes: 3 additions & 3 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -5,8 +5,8 @@


class TestCLI:
@pytest.mark.vcr
def test_item_search(self, script_runner: ScriptRunner):
@pytest.mark.vcr # type: ignore[misc]
def test_item_search(self, script_runner: ScriptRunner) -> None:
args = [
"stac-client",
"search",
@@ -19,7 +19,7 @@ def test_item_search(self, script_runner: ScriptRunner):
result = script_runner.run(*args, print_result=False)
assert result.success

def test_no_arguments(self, script_runner: ScriptRunner):
def test_no_arguments(self, script_runner: ScriptRunner) -> None:
args = ["stac-client"]
result = script_runner.run(*args, print_result=False)
assert not result.success
69 changes: 43 additions & 26 deletions tests/test_client.py
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
import pytest
from dateutil.tz import tzutc
from pystac import MediaType
from requests_mock import Mocker

from pystac_client import Client
from pystac_client.conformance import ConformanceClasses
@@ -17,17 +18,17 @@


class TestAPI:
@pytest.mark.vcr
def test_instance(self):
@pytest.mark.vcr # type: ignore[misc]
def test_instance(self) -> None:
api = Client.open(STAC_URLS["PLANETARY-COMPUTER"])

# An API instance is also a Catalog instance
assert isinstance(api, pystac.Catalog)

assert str(api) == "<Client id=microsoft-pc>"

@pytest.mark.vcr
def test_links(self):
@pytest.mark.vcr # type: ignore[misc]
def test_links(self) -> None:
api = Client.open(STAC_URLS["PLANETARY-COMPUTER"])

# Should be able to get collections via links as with a typical PySTAC Catalog
@@ -37,58 +38,63 @@ def test_links(self):
collections = list(api.get_collections())
assert len(collection_links) == len(collections)

first_collection = (
api.get_single_link("child").resolve_stac_object(root=api).target
)
first_child_link = api.get_single_link("child")
assert first_child_link is not None
first_collection = first_child_link.resolve_stac_object(root=api).target
assert isinstance(first_collection, pystac.Collection)

def test_spec_conformance(self):
def test_spec_conformance(self) -> None:
"""Testing conformance against a ConformanceClass should allow APIs using legacy
URIs to pass."""
client = Client.from_file(str(TEST_DATA / "planetary-computer-root.json"))
assert client._stac_io is not None

# Set conformsTo URIs to conform with STAC API - Core using official URI
client._stac_io._conformance = ["https://api.stacspec.org/v1.0.0-beta.1/core"]

assert client._stac_io.conforms_to(ConformanceClasses.CORE)

@pytest.mark.vcr
def test_no_conformance(self):
@pytest.mark.vcr # type: ignore[misc]
def test_no_conformance(self) -> None:
"""Should raise a NotImplementedError if no conformance info can be found.
Luckily, the test API doesn't publish a "conformance" link so we can just
remove the "conformsTo" attribute to test this."""
client = Client.from_file(str(TEST_DATA / "planetary-computer-root.json"))
assert client._stac_io is not None
client._stac_io._conformance = []
assert client._stac_io is not None

with pytest.raises(NotImplementedError):
client._stac_io.assert_conforms_to(ConformanceClasses.CORE)

with pytest.raises(NotImplementedError):
client._stac_io.assert_conforms_to(ConformanceClasses.ITEM_SEARCH)

@pytest.mark.vcr
def test_no_stac_core_conformance(self):
@pytest.mark.vcr # type: ignore[misc]
def test_no_stac_core_conformance(self) -> None:
"""Should raise a NotImplementedError if the API does not conform to the
STAC API - Core spec."""
client = Client.from_file(str(TEST_DATA / "planetary-computer-root.json"))
assert client._stac_io is not None
assert client._stac_io._conformance is not None
client._stac_io._conformance = client._stac_io._conformance[1:]

with pytest.raises(NotImplementedError):
client._stac_io.assert_conforms_to(ConformanceClasses.CORE)

assert client._stac_io.conforms_to(ConformanceClasses.ITEM_SEARCH)

@pytest.mark.vcr
def test_from_file(self):
@pytest.mark.vcr # type: ignore[misc]
def test_from_file(self) -> None:
api = Client.from_file(STAC_URLS["PLANETARY-COMPUTER"])

assert api.title == "Microsoft Planetary Computer STAC API"

def test_invalid_url(self):
def test_invalid_url(self) -> None:
with pytest.raises(TypeError):
Client.open()
Client.open() # type: ignore[call-arg]

def test_get_collections_with_conformance(self, requests_mock):
def test_get_collections_with_conformance(self, requests_mock: Mocker) -> None:
"""Checks that the "data" endpoint is used if the API published the
STAC API Collections conformance class."""
pc_root_text = read_data_file("planetary-computer-root.json")
@@ -101,11 +107,13 @@ def test_get_collections_with_conformance(self, requests_mock):
STAC_URLS["PLANETARY-COMPUTER"], status_code=200, text=pc_root_text
)
api = Client.open(STAC_URLS["PLANETARY-COMPUTER"])
assert api._stac_io is not None

assert api._stac_io.conforms_to(ConformanceClasses.COLLECTIONS)

# Get & mock the collections (rel type "data") link
collections_link = api.get_single_link("data")
assert collections_link is not None
requests_mock.get(
collections_link.href,
status_code=200,
@@ -117,7 +125,7 @@ def test_get_collections_with_conformance(self, requests_mock):
assert len(history) == 2
assert history[1].url == collections_link.href

def test_custom_request_parameters(self, requests_mock):
def test_custom_request_parameters(self, requests_mock: Mocker) -> None:
pc_root_text = read_data_file("planetary-computer-root.json")
pc_collection_dict = read_data_file(
"planetary-computer-collection.json", parse_json=True
@@ -133,13 +141,15 @@ def test_custom_request_parameters(self, requests_mock):
api = Client.open(
STAC_URLS["PLANETARY-COMPUTER"], parameters={init_qp_name: init_qp_value}
)
assert api._stac_io is not None

# Ensure that the Client will use the /collections endpoint and not fall back
# to traversing child links.
assert api._stac_io.conforms_to(ConformanceClasses.COLLECTIONS)

# Get the /collections endpoint
collections_link = api.get_single_link("data")
assert collections_link is not None

# Mock the request
requests_mock.get(
@@ -163,7 +173,7 @@ def test_custom_request_parameters(self, requests_mock):
assert actual_qp[init_qp_name][0] == init_qp_value

def test_custom_query_params_get_collections_propagation(
self, requests_mock
self, requests_mock: Mocker
) -> None:
"""Checks that query params passed to the init method are added to requests for
CollectionClients fetched from
@@ -186,6 +196,7 @@ def test_custom_query_params_get_collections_propagation(

# Get the /collections endpoint
collections_link = client.get_single_link("data")
assert collections_link is not None

# Mock the request
requests_mock.get(
@@ -226,14 +237,15 @@ def test_custom_query_params_get_collections_propagation(
assert actual_qp[init_qp_name][0] == init_qp_value

def test_custom_query_params_get_collection_propagation(
self, requests_mock
self, requests_mock: Mocker
) -> None:
"""Checks that query params passed to the init method are added to
requests for CollectionClients fetched from the /collections endpoint."""
pc_root_text = read_data_file("planetary-computer-root.json")
pc_collection_dict = read_data_file(
"planetary-computer-collection.json", parse_json=True
)
assert isinstance(pc_collection_dict, dict)
pc_collection_id = pc_collection_dict["id"]

requests_mock.get(
@@ -249,13 +261,15 @@ def test_custom_query_params_get_collection_propagation(

# Get the /collections endpoint
collections_link = client.get_single_link("data")
assert collections_link is not None
collection_href = collections_link.href + "/" + pc_collection_id

# Mock the request
requests_mock.get(collection_href, status_code=200, json=pc_collection_dict)

# Make the collections request
collection = client.get_collection(pc_collection_id)
assert collection is not None

# Mock the items endpoint
items_link = collection.get_single_link("items")
@@ -285,7 +299,7 @@ def test_custom_query_params_get_collection_propagation(
assert len(actual_qp[init_qp_name]) == 1
assert actual_qp[init_qp_name][0] == init_qp_value

def test_get_collections_without_conformance(self, requests_mock):
def test_get_collections_without_conformance(self, requests_mock: Mocker) -> None:
"""Checks that the "data" endpoint is used if the API published
the Collections conformance class."""
pc_root_dict = read_data_file("planetary-computer-root.json", parse_json=True)
@@ -315,6 +329,7 @@ def test_get_collections_without_conformance(self, requests_mock):
STAC_URLS["PLANETARY-COMPUTER"], status_code=200, json=pc_root_dict
)
api = Client.open(STAC_URLS["PLANETARY-COMPUTER"])
assert api._stac_io is not None

assert not api._stac_io.conforms_to(ConformanceClasses.COLLECTIONS)

@@ -334,22 +349,24 @@ def test_opening_a_collection(self) -> None:


class TestAPISearch:
@pytest.fixture(scope="function")
def api(self):
@pytest.fixture(scope="function") # type: ignore[misc]
def api(self) -> Client:
return Client.from_file(str(TEST_DATA / "planetary-computer-root.json"))

def test_search_conformance_error(self, api):
def test_search_conformance_error(self, api: Client) -> None:
"""Should raise a NotImplementedError if the API doesn't conform
to the Item Search spec. Message should
include information about the spec that was not conformed to."""
# Set the conformance to only STAC API - Core
assert api._stac_io is not None
assert api._stac_io._conformance is not None
api._stac_io._conformance = [api._stac_io._conformance[0]]

with pytest.raises(NotImplementedError) as excinfo:
api.search(limit=10, max_items=10, collections="mr-peebles")
assert str(ConformanceClasses.ITEM_SEARCH) in str(excinfo.value)

def test_no_search_link(self, api):
def test_no_search_link(self, api: Client) -> None:
# Remove the search link
api.remove_links("search")

@@ -373,7 +390,7 @@ def test_no_conforms_to(self) -> None:
api.search(limit=10, max_items=10, collections="naip")
assert "does not support search" in str(excinfo.value)

def test_search(self, api):
def test_search(self, api: Client) -> None:
results = api.search(
bbox=[-73.21, 43.99, -73.12, 44.05],
collections="naip",
14 changes: 8 additions & 6 deletions tests/test_collection_client.py
Original file line number Diff line number Diff line change
@@ -7,26 +7,28 @@


class TestCollectionClient:
@pytest.mark.vcr
def test_instance(self):
@pytest.mark.vcr # type: ignore[misc]
def test_instance(self) -> None:
client = Client.open(STAC_URLS["PLANETARY-COMPUTER"])
collection = client.get_collection("aster-l1t")

assert isinstance(collection, CollectionClient)
assert str(collection) == "<CollectionClient id=aster-l1t>"

@pytest.mark.vcr
def test_get_items(self):
@pytest.mark.vcr # type: ignore[misc]
def test_get_items(self) -> None:
client = Client.open(STAC_URLS["PLANETARY-COMPUTER"])
collection = client.get_collection("aster-l1t")
assert collection is not None
for item in collection.get_items():
assert item.collection_id == collection.id
return

@pytest.mark.vcr
def test_get_item(self):
@pytest.mark.vcr # type: ignore[misc]
def test_get_item(self) -> None:
client = Client.open(STAC_URLS["PLANETARY-COMPUTER"])
collection = client.get_collection("aster-l1t")
assert collection is not None
item = collection.get_item("AST_L1T_00312272006020322_20150518201805")
assert item
assert item.id == "AST_L1T_00312272006020322_20150518201805"
78 changes: 42 additions & 36 deletions tests/test_item_search.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import json
from datetime import datetime, timedelta
from typing import Any, Dict, Iterator

import pystac
import pytest
import requests
from dateutil.tz import gettz, tzutc
from pytest_benchmark.fixture import BenchmarkFixture

from pystac_client import Client
from pystac_client.item_search import ItemSearch
@@ -25,29 +27,31 @@
],
}

ITEM_EXAMPLE = {"collections": "io-lulc", "ids": "60U-2020"}
ITEM_EXAMPLE: Dict[str, Any] = {"collections": "io-lulc", "ids": "60U-2020"}


class TestItemPerformance:
@pytest.fixture(scope="function")
def single_href(self) -> None:
@pytest.fixture(scope="function") # type: ignore[misc]
def single_href(self) -> str:
item_href = "https://planetarycomputer.microsoft.com/api/stac/v1/collections/{collections}/items/{ids}".format(
collections=ITEM_EXAMPLE["collections"], ids=ITEM_EXAMPLE["ids"]
)
return item_href

def test_requests(self, benchmark, single_href):
def test_requests(self, benchmark: BenchmarkFixture, single_href: str) -> None:
response = benchmark(requests.get, single_href)
assert response.status_code == 200

assert response.json()["id"] == ITEM_EXAMPLE["ids"]

def test_single_item(self, benchmark, single_href):
def test_single_item(self, benchmark: BenchmarkFixture, single_href: str) -> None:
item = benchmark(pystac.Item.from_file, single_href)

assert item.id == ITEM_EXAMPLE["ids"]

def test_single_item_search(self, benchmark, single_href):
def test_single_item_search(
self, benchmark: BenchmarkFixture, single_href: str
) -> None:
search = ItemSearch(url=SEARCH_URL, **ITEM_EXAMPLE)

item_collection = benchmark(search.get_all_items)
@@ -57,8 +61,8 @@ def test_single_item_search(self, benchmark, single_href):


class TestItemSearchParams:
@pytest.fixture(scope="function")
def sample_client(self) -> None:
@pytest.fixture(scope="function") # type: ignore[misc]
def sample_client(self) -> Client:
api_content = read_data_file("planetary-computer-root.json", parse_json=True)
return Client.from_dict(api_content)

@@ -79,7 +83,7 @@ def test_string_bbox(self) -> None:

def test_generator_bbox(self) -> None:
# Generator Input
def bboxer():
def bboxer() -> Iterator[float]:
yield from [-104.5, 44.0, -104.0, 45.0]

search = ItemSearch(url=SEARCH_URL, bbox=bboxer())
@@ -257,7 +261,7 @@ def test_list_of_collection_strings(self) -> None:

def test_generator_of_collection_strings(self) -> None:
# Generator of ID strings
def collectioner():
def collectioner() -> Iterator[str]:
yield from ["naip", "landsat8_l1tp"]

search = ItemSearch(url=SEARCH_URL, collections=collectioner())
@@ -297,7 +301,7 @@ def test_list_of_id_strings(self) -> None:

def test_generator_of_id_string(self) -> None:
# Generator of IDs
def ids():
def ids() -> Iterator[str]:
yield from [
"m_3510836_se_12_060_20180508_20190331",
"m_3510840_se_12_060_20180504_20190331",
@@ -411,18 +415,18 @@ def test_sortby(self) -> None:
)

with pytest.raises(Exception):
ItemSearch(url=SEARCH_URL, sortby=1)
ItemSearch(url=SEARCH_URL, sortby=1) # type: ignore[arg-type]

with pytest.raises(Exception):
ItemSearch(url=SEARCH_URL, sortby=[1])
ItemSearch(url=SEARCH_URL, sortby=[1]) # type: ignore[arg-type]

def test_fields(self):
def test_fields(self) -> None:

with pytest.raises(Exception):
ItemSearch(url=SEARCH_URL, fields=1)
ItemSearch(url=SEARCH_URL, fields=1) # type: ignore[arg-type]

with pytest.raises(Exception):
ItemSearch(url=SEARCH_URL, fields=[1])
ItemSearch(url=SEARCH_URL, fields=[1]) # type: ignore[list-item]

search = ItemSearch(url=SEARCH_URL, fields="id,collection,+foo,-bar")
assert search.get_parameters()["fields"] == {
@@ -464,8 +468,8 @@ def test_fields(self):


class TestItemSearch:
@pytest.fixture(scope="function")
def astraea_api(self) -> None:
@pytest.fixture(scope="function") # type: ignore[misc]
def astraea_api(self) -> Client:
api_content = read_data_file("astraea_api.json", parse_json=True)
return Client.from_dict(api_content)

@@ -479,7 +483,7 @@ def test_method(self) -> None:
assert search.method == "GET"

def test_method_params(self) -> None:
params_in = {
params_in: Dict[str, Any] = {
"bbox": (-72, 41, -71, 42),
"ids": (
"idone",
@@ -499,7 +503,7 @@ def test_method_params(self) -> None:
assert all(key in params for key in params_in)
assert all(isinstance(params[key], str) for key in params_in)

@pytest.mark.vcr
@pytest.mark.vcr # type: ignore[misc]
def test_results(self) -> None:
search = ItemSearch(
url=SEARCH_URL,
@@ -511,7 +515,7 @@ def test_results(self) -> None:

assert all(isinstance(item, pystac.Item) for item in results)

@pytest.mark.vcr
@pytest.mark.vcr # type: ignore[misc]
def test_ids_results(self) -> None:
ids = [
"S2B_MSIL2A_20210610T115639_N0212_R066_T33XXG_20210613T185024.SAFE",
@@ -526,7 +530,7 @@ def test_ids_results(self) -> None:
assert len(results) == 1
assert all(item.id in ids for item in results)

@pytest.mark.vcr
@pytest.mark.vcr # type: ignore[misc]
def test_datetime_results(self) -> None:
# Datetime range string
datetime_ = "2019-01-01T00:00:01Z/2019-01-01T00:00:10Z"
@@ -537,13 +541,15 @@ def test_datetime_results(self) -> None:
min_datetime = datetime(2019, 1, 1, 0, 0, 1, tzinfo=tzutc())
max_datetime = datetime(2019, 1, 1, 0, 0, 10, tzinfo=tzutc())
search = ItemSearch(url=SEARCH_URL, datetime=(min_datetime, max_datetime))
results = search.items()
assert all(
min_datetime <= item.datetime <= (max_datetime + timedelta(seconds=1))
for item in results
)
new_results = search.items()

for item in new_results:
assert item.datetime is not None
assert (
min_datetime <= item.datetime <= (max_datetime + timedelta(seconds=1))
)

@pytest.mark.vcr
@pytest.mark.vcr # type: ignore[misc]
def test_intersects_results(self) -> None:
# GeoJSON-like dict
intersects_dict = {
@@ -567,17 +573,17 @@ def test_intersects_results(self) -> None:
# Geo-interface object
class MockGeoObject:
@property
def __geo_interface__(self) -> None:
def __geo_interface__(self) -> Dict[str, Any]:
return intersects_dict

intersects_obj = MockGeoObject()
search = ItemSearch(
url=SEARCH_URL, intersects=intersects_obj, collections="naip"
)
results = search.items()
assert all(isinstance(item, pystac.Item) for item in results)
new_results = search.items()
assert all(isinstance(item, pystac.Item) for item in new_results)

@pytest.mark.vcr
@pytest.mark.vcr # type: ignore[misc]
def test_result_paging(self) -> None:
search = ItemSearch(
url=SEARCH_URL,
@@ -593,7 +599,7 @@ def test_result_paging(self) -> None:
assert pages[1] != pages[2]
assert pages[1].items != pages[2].items

@pytest.mark.vcr
@pytest.mark.vcr # type: ignore[misc]
def test_get_all_items(self) -> None:
search = ItemSearch(
url=SEARCH_URL,
@@ -605,7 +611,7 @@ def test_get_all_items(self) -> None:
item_collection = search.get_all_items()
assert len(item_collection.items) == 20

@pytest.mark.vcr
@pytest.mark.vcr # type: ignore[misc]
def test_items_as_dicts(self) -> None:
search = ItemSearch(
url=SEARCH_URL,
@@ -618,7 +624,7 @@ def test_items_as_dicts(self) -> None:


class TestItemSearchQuery:
@pytest.mark.vcr
@pytest.mark.vcr # type: ignore[misc]
def test_query_shortcut_syntax(self) -> None:
search = ItemSearch(
url=SEARCH_URL,
@@ -640,7 +646,7 @@ def test_query_shortcut_syntax(self) -> None:
assert len(items2) == 1
assert items1[0].id == items2[0].id

@pytest.mark.vcr
@pytest.mark.vcr # type: ignore[misc]
def test_query_json_syntax(self) -> None:

# with a list of json strs (format of CLI argument to ItemSearch)
11 changes: 6 additions & 5 deletions tests/test_stac_api_io.py
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
from urllib.parse import parse_qs, urlsplit

import pytest
from requests_mock.mocker import Mocker

from pystac_client.conformance import ConformanceClasses
from pystac_client.exceptions import APIError
@@ -11,20 +12,20 @@


class TestSTAC_IOOverride:
@pytest.mark.vcr
@pytest.mark.vcr # type: ignore[misc]
def test_request_input(self) -> None:
stac_api_io = StacApiIO()
response = stac_api_io.read_text(STAC_URLS["PLANETARY-COMPUTER"])
assert isinstance(response, str)

@pytest.mark.vcr
@pytest.mark.vcr # type: ignore[misc]
def test_str_input(self) -> None:
stac_api_io = StacApiIO()
response = stac_api_io.read_text(STAC_URLS["PLANETARY-COMPUTER"])

assert isinstance(response, str)

@pytest.mark.vcr
@pytest.mark.vcr # type: ignore[misc]
def test_http_error(self) -> None:
stac_api_io = StacApiIO()
# Attempt to access an authenticated endpoint
@@ -68,7 +69,7 @@ def test_conforms_to(self) -> None:
# Check that this does not raise an exception
assert conformant_io.conforms_to(ConformanceClasses.CORE)

def test_custom_headers(self, requests_mock):
def test_custom_headers(self, requests_mock: Mocker) -> None:
"""Checks that headers passed to the init method are added to requests."""
header_name = "x-my-header"
header_value = "Some Value"
@@ -84,7 +85,7 @@ def test_custom_headers(self, requests_mock):
assert header_name in history[0].headers
assert history[0].headers[header_name] == header_value

def test_custom_query_params(self, requests_mock):
def test_custom_query_params(self, requests_mock: Mocker) -> None:
"""Checks that query params passed to the init method are added to requests."""
init_qp_name = "my-param"
init_qp_value = "something"