Skip to content
Open
Show file tree
Hide file tree
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
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,22 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Changed

- Deprecate methods `Query.get` and `Query.get_all` in favor of the new `Query.results` method. These deprecated methods will likely be removed for the 1.0.0 release. ([#37](https://github.com/nasa/python_cmr/issues/37))
- Deprecate methods `Query.get` and `Query.get_all` in favor of the new
`Query.results` method. These deprecated methods will likely be removed for
the 1.0.0 release. ([#37](https://github.com/nasa/python_cmr/issues/37))
- `Query.parameters` accepts "unchecked" keywords, meaning that it accepts
keywords that do not have a corresponding method by the same name in the
`Query` class (or specific subclass being used).

This allows the caller to supply a parameter that does not have a
corresponding method without raising a `ValueError`. Instead, such a parameter
is passed directly through to the CMR, where it will be checked. If the
parameter is not supported or its value is invalid, the CMR response will
indicate as such.

This avoids the need to wait for the corresponding method to be added, or
having to write cumbersome code to get around the limitation.
([#106](https://github.com/nasa/python_cmr/issues/106))

## [0.13.0]

Expand Down
21 changes: 14 additions & 7 deletions cmr/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from datetime import date, datetime, timezone
from inspect import getmembers, ismethod
from re import search
from typing import Iterator
from typing import Iterable, Iterator

from typing_extensions import (
Any,
Expand Down Expand Up @@ -127,7 +127,7 @@ def get_all(self) -> Sequence[Any]:

:returns: query results as a list
"""

return list(self.get(self.hits()))

def results(self, page_size: int = 2000) -> Iterator[Any]:
Expand Down Expand Up @@ -196,12 +196,19 @@ def parameters(self, **kwargs: Any) -> Self:
methods = dict(getmembers(self, predicate=ismethod))

for key, val in kwargs.items():
# verify the key matches one of our methods
# If the key does not match one of the methods defined in the Query
# class or subclass, simply set the parameter "unchecked" (i.e.,
# set the parameter, but without a method that can do some value
# checking. If the value is invalid, the CMR response will indicate
# the problem).
if key not in methods:
raise ValueError(f"Unknown key {key}")

# call the method
if isinstance(val, tuple):
if isinstance(val, str) or not isinstance(val, Iterable):
# Set single-valued parameter
self.params[key] = val
else:
# Set multi-valued parameter adding `[]` suffix to key
self.params[f"{key}[]"] = tuple(val)
elif isinstance(val, tuple):
methods[key](*val)
else:
methods[key](val)
Expand Down
30 changes: 23 additions & 7 deletions tests/test_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,72 @@


class MockQuery(Query):

def __init__(self) -> None:
super().__init__("/foo")

def _valid_state(self) -> bool:
return True


def test_query_headers_initially_empty():
query = MockQuery("/foo")
query = MockQuery()
assert query.headers == {}


def test_bearer_token_adds_header():
query = MockQuery("/foo")
query = MockQuery()
query.headers["foo"] = "bar"
query.bearer_token("bearertoken")

assert query.headers["foo"] == "bar"


def test_bearer_token_does_not_clobber_other_headers():
query = MockQuery("/foo")
query = MockQuery()
query.bearer_token("bearertoken")

assert query.headers["Authorization"] == "Bearer bearertoken"


def test_bearer_token_replaces_existing_auth_header():
query = MockQuery("/foo")
query = MockQuery()
query.token("token")
query.bearer_token("bearertoken")

assert query.headers["Authorization"] == "Bearer bearertoken"


def test_token_adds_header():
query = MockQuery("/foo")
query = MockQuery()
query.token("token")

assert query.headers["Authorization"] == "token"


def test_token_does_not_clobber_other_headers():
query = MockQuery("/foo")
query = MockQuery()
query.headers["foo"] = "bar"
query.token("token")

assert query.headers["foo"] == "bar"


def test_token_replaces_existing_auth_header():
query = MockQuery("/foo")
query = MockQuery()
query.bearer_token("bearertoken")
query.token("token")

assert query.headers["Authorization"] == "token"


def test_singular_unknown_parameter():
query = MockQuery().parameters(unknown_parameter="foo")

assert query.params["unknown_parameter"] == "foo"


def test_plural_unknown_parameter():
query = MockQuery().parameters(unknown_parameter=["foo", "bar"])

assert query.params["unknown_parameter[]"] == ("foo", "bar")
2 changes: 1 addition & 1 deletion tests/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def test_token(self):
self.assertIn("Authorization", query.headers)
self.assertEqual(query.headers["Authorization"], "123TOKEN")

def bearer_test_token(self):
def test_bearer_token(self):
query = ServiceQuery()

query.bearer_token("123TOKEN")
Expand Down
Loading