Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Breaking Changes
~~~~~~~~~~~~~~~~

- All defaults of ``None`` converted to ``globus_sdk.MISSING`` for all payload types in the Search client. (:pr:`1207`)
90 changes: 43 additions & 47 deletions src/globus_sdk/services/search/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from globus_sdk._types import UUIDLike
from globus_sdk.exc.warnings import warn_deprecated
from globus_sdk.scopes import Scope, SearchScopes
from globus_sdk.utils import MISSING, MissingType

from .data import SearchQuery, SearchScrollQuery
from .errors import SearchAPIError
Expand Down Expand Up @@ -234,9 +235,9 @@ def search(
index_id: UUIDLike,
q: str,
*,
offset: int = 0,
limit: int = 10,
advanced: bool = False,
offset: int | MissingType = MISSING,
limit: int | MissingType = MISSING,
advanced: bool | MissingType = MISSING,
query_params: dict[str, t.Any] | None = None,
) -> response.GlobusHTTPResponse:
"""
Expand Down Expand Up @@ -278,17 +279,13 @@ def search(

.. expandtestfixture:: search.search
""" # noqa: E501
if query_params is None:
query_params = {}
query_params.update(
{
"q": q,
"offset": offset,
"limit": limit,
"advanced": advanced,
}
)

query_params = {
"q": q,
"offset": offset,
"limit": limit,
"advanced": advanced,
**(query_params or {}),
}
log.debug(f"SearchClient.search({index_id}, ...)")
return self.get(f"/v1/index/{index_id}/search", query_params=query_params)

Expand All @@ -304,8 +301,8 @@ def post_search(
index_id: UUIDLike,
data: dict[str, t.Any] | SearchQuery,
*,
offset: int | None = None,
limit: int | None = None,
offset: int | MissingType = MISSING,
limit: int | MissingType = MISSING,
) -> response.GlobusHTTPResponse:
"""
Execute a complex Search Query, using a query document to express filters,
Expand Down Expand Up @@ -360,12 +357,11 @@ def post_search(
"""
log.debug(f"SearchClient.post_search({index_id}, ...)")
add_kwargs = {}
if offset is not None:
if not isinstance(offset, MissingType):
add_kwargs["offset"] = offset
if limit is not None:
if not isinstance(limit, MissingType):
add_kwargs["limit"] = limit
if add_kwargs:
data = {**data, **add_kwargs}
data = {**data, **add_kwargs}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to continue to think about this case, but we don't need to solve it right now.

return self.post(f"v1/index/{index_id}/search", data=data)

@paging.has_paginator(paging.MarkerPaginator, items_key="gmeta")
Expand All @@ -374,7 +370,7 @@ def scroll(
index_id: UUIDLike,
data: dict[str, t.Any] | SearchScrollQuery,
*,
marker: str | None = None,
marker: str | MissingType = MISSING,
) -> response.GlobusHTTPResponse:
"""
Scroll all data in a Search index. The paginated version of this API should
Expand Down Expand Up @@ -412,10 +408,9 @@ def scroll(
"""
log.debug(f"SearchClient.scroll({index_id}, ...)")
add_kwargs = {}
if marker is not None:
if not isinstance(marker, MissingType):
add_kwargs["marker"] = marker
if add_kwargs:
data = {**data, **add_kwargs}
data = {**data, **add_kwargs}
return self.post(f"v1/index/{index_id}/scroll", data=data)

#
Expand Down Expand Up @@ -579,9 +574,10 @@ def batch_delete_by_subject(
# convert the provided subjects to a list and use the "safe iter" helper to
# ensure that a single string is *not* treated as an iterable of strings,
# which is usually not intentional
body = {"subjects": list(utils.safe_strseq_iter(subjects))}
if additional_params:
body.update(additional_params)
body = {
"subjects": list(utils.safe_strseq_iter(subjects)),
**(additional_params or {}),
}
return self.post(f"/v1/index/{index_id}/batch_delete_by_subject", data=body)

#
Expand Down Expand Up @@ -621,10 +617,11 @@ def get_subject(
.. extdoclink:: Get By Subject
:ref: search/reference/get_subject/
"""
if query_params is None:
query_params = {}
query_params["subject"] = subject
log.debug(f"SearchClient.get_subject({index_id}, {subject}, ...)")
query_params = {
"subject": subject,
**(query_params or {}),
}
return self.get(f"/v1/index/{index_id}/subject", query_params=query_params)

def delete_subject(
Expand Down Expand Up @@ -664,11 +661,11 @@ def delete_subject(
.. extdoclink:: Delete By Subject
:ref: search/reference/delete_subject/
"""
if query_params is None:
query_params = {}
query_params["subject"] = subject

log.debug(f"SearchClient.delete_subject({index_id}, {subject}, ...)")
query_params = {
"subject": subject,
**(query_params or {}),
}
return self.delete(f"/v1/index/{index_id}/subject", query_params=query_params)

#
Expand All @@ -680,7 +677,7 @@ def get_entry(
index_id: UUIDLike,
subject: str,
*,
entry_id: str | None = None,
entry_id: str | MissingType = MISSING,
query_params: dict[str, t.Any] | None = None,
) -> response.GlobusHTTPResponse:
"""
Expand Down Expand Up @@ -720,17 +717,16 @@ def get_entry(
.. extdoclink:: Get Entry
:ref: search/reference/get_entry/
""" # noqa: E501
if query_params is None:
query_params = {}
query_params["subject"] = subject
if entry_id is not None:
query_params["entry_id"] = entry_id

log.debug(
"SearchClient.get_entry({}, {}, {}, ...)".format(
index_id, subject, entry_id
)
)
query_params = {
"entry_id": entry_id,
"subject": subject,
**(query_params or {}),
}
return self.get(f"/v1/index/{index_id}/entry", query_params=query_params)

def create_entry(
Expand Down Expand Up @@ -849,7 +845,7 @@ def delete_entry(
index_id: UUIDLike,
subject: str,
*,
entry_id: str | None = None,
entry_id: str | MissingType = MISSING,
query_params: dict[str, t.Any] | None = None,
) -> response.GlobusHTTPResponse:
"""
Expand Down Expand Up @@ -889,16 +885,16 @@ def delete_entry(
.. extdoclink:: Delete Entry
:ref: search/reference/delete_entry/
""" # noqa: E501
if query_params is None:
query_params = {}
query_params["subject"] = subject
if entry_id is not None:
query_params["entry_id"] = entry_id
log.debug(
"SearchClient.delete_entry({}, {}, {}, ...)".format(
index_id, subject, entry_id
)
)
query_params = {
"entry_id": entry_id,
"subject": subject,
**(query_params or {}),
}
return self.delete(f"/v1/index/{index_id}/entry", query_params=query_params)

#
Expand Down
107 changes: 52 additions & 55 deletions src/globus_sdk/services/search/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@
import typing as t

from globus_sdk import exc, utils
from globus_sdk.utils import MISSING, MissingType

# workaround for absence of Self type
# for the workaround and some background, see:
# https://github.com/python/mypy/issues/11871
SearchQueryT = t.TypeVar("SearchQueryT", bound="SearchQueryBase")


def _format_histogram_range(
value: tuple[t.Any, t.Any] | MissingType,
) -> dict[str, t.Any] | MissingType:
if isinstance(value, MissingType):
return MISSING
low, high = value
return {"low": low, "high": high}


# an internal class for declaring multiple related types with shared methods
class SearchQueryBase(utils.PayloadWrapper):
"""
Expand Down Expand Up @@ -107,25 +117,21 @@ class SearchQuery(SearchQueryBase):

def __init__(
self,
q: str | None = None,
q: str | MissingType = MISSING,
*,
limit: int | None = None,
offset: int | None = None,
advanced: bool | None = None,
limit: int | MissingType = MISSING,
offset: int | MissingType = MISSING,
advanced: bool | MissingType = MISSING,
additional_fields: dict[str, t.Any] | None = None,
) -> None:
super().__init__()
exc.warn_deprecated("'SearchQuery' is deprecated. Use 'SearchQueryV1' instead.")
if q is not None:
self["q"] = q
if limit is not None:
self["limit"] = limit
if offset is not None:
self["offset"] = offset
if advanced is not None:
self["advanced"] = advanced
if additional_fields is not None:
self.update(additional_fields)

self["q"] = q
self["limit"] = limit
self["offset"] = offset
self["advanced"] = advanced
self.update(additional_fields or {})

def set_offset(self, offset: int) -> SearchQuery:
"""
Expand All @@ -143,9 +149,9 @@ def add_facet(
*,
# pylint: disable=redefined-builtin
type: str = "terms",
size: int | None = None,
date_interval: str | None = None,
histogram_range: tuple[t.Any, t.Any] | None = None,
size: int | MissingType = MISSING,
date_interval: str | MissingType = MISSING,
histogram_range: tuple[t.Any, t.Any] | MissingType = MISSING,
additional_fields: dict[str, t.Any] | None = None,
) -> SearchQuery:
"""
Expand All @@ -164,15 +170,11 @@ def add_facet(
"name": name,
"field_name": field_name,
"type": type,
"size": size,
"date_interval": date_interval,
"histogram_range": _format_histogram_range(histogram_range),
**(additional_fields or {}),
}
if size is not None:
facet["size"] = size
if date_interval is not None:
facet["date_interval"] = date_interval
if histogram_range is not None:
low, high = histogram_range
facet["histogram_range"] = {"low": low, "high": high}
self["facets"].append(facet)
return self

Expand Down Expand Up @@ -204,7 +206,7 @@ def add_sort(
self,
field_name: str,
*,
order: str | None = None,
order: str | MissingType = MISSING,
additional_fields: dict[str, t.Any] | None = None,
) -> SearchQuery:
"""
Expand All @@ -215,9 +217,11 @@ def add_sort(
:param additional_fields: additional data to include in the sort document
"""
self["sort"] = self.get("sort", [])
sort = {"field_name": field_name, **(additional_fields or {})}
if order is not None:
sort["order"] = order
sort = {
"field_name": field_name,
"order": order,
**(additional_fields or {}),
}
self["sort"].append(sort)
return self

Expand Down Expand Up @@ -245,16 +249,16 @@ class SearchQueryV1(utils.PayloadWrapper):
def __init__(
self,
*,
q: str | utils.MissingType = utils.MISSING,
limit: int | utils.MissingType = utils.MISSING,
offset: int | utils.MissingType = utils.MISSING,
advanced: bool | utils.MissingType = utils.MISSING,
filters: list[dict[str, t.Any]] | utils.MissingType = utils.MISSING,
facets: list[dict[str, t.Any]] | utils.MissingType = utils.MISSING,
post_facet_filters: list[dict[str, t.Any]] | utils.MissingType = utils.MISSING,
boosts: list[dict[str, t.Any]] | utils.MissingType = utils.MISSING,
sort: list[dict[str, t.Any]] | utils.MissingType = utils.MISSING,
additional_fields: dict[str, t.Any] | utils.MissingType = utils.MISSING,
q: str | MissingType = MISSING,
limit: int | MissingType = MISSING,
offset: int | MissingType = MISSING,
advanced: bool | MissingType = MISSING,
filters: list[dict[str, t.Any]] | MissingType = MISSING,
facets: list[dict[str, t.Any]] | MissingType = MISSING,
post_facet_filters: list[dict[str, t.Any]] | MissingType = MISSING,
boosts: list[dict[str, t.Any]] | MissingType = MISSING,
sort: list[dict[str, t.Any]] | MissingType = MISSING,
additional_fields: dict[str, t.Any] | None = None,
) -> None:
super().__init__()
self["@version"] = "query#1.0.0"
Expand All @@ -268,9 +272,7 @@ def __init__(
self["post_facet_filters"] = post_facet_filters
self["boosts"] = boosts
self["sort"] = sort

if not isinstance(additional_fields, utils.MissingType):
self.update(additional_fields)
self.update(additional_fields or {})


class SearchScrollQuery(SearchQueryBase):
Expand All @@ -295,24 +297,19 @@ class SearchScrollQuery(SearchQueryBase):

def __init__(
self,
q: str | None = None,
q: str | MissingType = MISSING,
*,
limit: int | None = None,
advanced: bool | None = None,
marker: str | None = None,
limit: int | MissingType = MISSING,
advanced: bool | MissingType = MISSING,
marker: str | MissingType = MISSING,
additional_fields: dict[str, t.Any] | None = None,
) -> None:
super().__init__()
if q is not None:
self["q"] = q
if limit is not None:
self["limit"] = limit
if advanced is not None:
self["advanced"] = advanced
if marker is not None:
self["marker"] = marker
if additional_fields is not None:
self.update(additional_fields)
self["q"] = q
self["limit"] = limit
self["advanced"] = advanced
self["marker"] = marker
self.update(additional_fields or {})

def set_marker(self, marker: str) -> SearchScrollQuery:
"""
Expand Down
Loading