Skip to content
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

feat: add an option to use POST for search_issues #1723

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
46 changes: 39 additions & 7 deletions jira/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,7 @@ def _fetch_pages(
maxResults: int = 50,
params: dict[str, Any] = None,
base: str = JIRA_BASE_URL,
use_post: bool = False,
) -> ResultList[ResourceType]:
"""Fetch from a paginated end point.

Expand All @@ -704,6 +705,7 @@ def _fetch_pages(
maxResults (int): Maximum number of items to return. If maxResults evaluates as False, it will try to get all items in batches. (Default:50)
params (Dict[str, Any]): Params to be used in all requests. Should not contain startAt and maxResults, as they will be added for each request created from this function.
base (str): base URL to use for the requests.
use_post (bool): Use POST endpoint instead of GET endpoint.

Returns:
ResultList
Expand All @@ -726,7 +728,9 @@ def _fetch_pages(
elif batch_size := self._get_batch_size(item_type):
page_params["maxResults"] = batch_size

resource = self._get_json(request_path, params=page_params, base=base)
resource = self._get_json(
request_path, params=page_params, base=base, use_post=use_post
)
next_items_page = self._get_items_from_page(item_type, items_key, resource)
items = next_items_page

Expand Down Expand Up @@ -771,7 +775,11 @@ def _fetch_pages(
page_params["startAt"] = start_index
page_params["maxResults"] = page_size
url = self._get_url(request_path)
r = future_session.get(url, params=page_params)
r = (
future_session.post(url, data=json.dumps(page_params))
if use_post
else future_session.get(url, params=page_params)
)
async_fetches.append(r)
for future in async_fetches:
response = future.result()
Expand All @@ -792,8 +800,9 @@ def _fetch_pages(
) # Hack necessary for mock-calls to not change
page_params["startAt"] = page_start
page_params["maxResults"] = page_size

resource = self._get_json(
request_path, params=page_params, base=base
request_path, params=page_params, base=base, use_post=use_post
)
if resource:
next_items_page = self._get_items_from_page(
Expand Down Expand Up @@ -3032,6 +3041,7 @@ def search_issues(
expand: str | None = None,
properties: str | None = None,
json_result: bool = False,
use_post: bool = False,
) -> dict[str, Any] | ResultList[Issue]:
"""Get a :class:`~jira.client.ResultList` of issue Resources matching a JQL search string.

Expand All @@ -3047,6 +3057,7 @@ def search_issues(
expand (Optional[str]): extra information to fetch inside each resource
properties (Optional[str]): extra properties to fetch inside each result
json_result (bool): True to return a JSON response. When set to False a :class:`ResultList` will be returned. (Default: ``False``)
use_post (bool): True to use POST endpoint to fetch issues.

Returns:
Union[Dict,ResultList]: Dict if ``json_result=True``
Expand All @@ -3073,18 +3084,30 @@ def search_issues(
"expand": expand,
"properties": properties,
}
# for the POST version of this endpoint Jira
# complains about unrecognized field "properties"
if use_post:
search_params.pop("properties")
if json_result:
search_params["maxResults"] = maxResults
if not maxResults:
warnings.warn(
"All issues cannot be fetched at once, when json_result parameter is set",
Warning,
)
r_json: dict[str, Any] = self._get_json("search", params=search_params)
r_json: dict[str, Any] = self._get_json(
"search", params=search_params, use_post=use_post
)
return r_json

issues = self._fetch_pages(
Issue, "issues", "search", startAt, maxResults, search_params
Issue,
"issues",
"search",
startAt,
maxResults,
search_params,
use_post=use_post,
)

if untranslate:
Expand Down Expand Up @@ -3839,20 +3862,29 @@ def _get_latest_url(self, path: str, base: str = JIRA_BASE_URL) -> str:
return base.format(**options)

def _get_json(
self, path: str, params: dict[str, Any] = None, base: str = JIRA_BASE_URL
self,
path: str,
params: dict[str, Any] = None,
base: str = JIRA_BASE_URL,
use_post: bool = False,
):
"""Get the json for a given path and params.

Args:
path (str): The subpath required
params (Optional[Dict[str, Any]]): Parameters to filter the json query.
base (Optional[str]): The Base Jira URL, defaults to the instance base.
use_post (bool): Use POST endpoint instead of GET endpoint.

Returns:
Union[Dict[str, Any], List[Dict[str, str]]]
"""
url = self._get_url(path, base)
r = self._session.get(url, params=params)
r = (
self._session.post(url, data=json.dumps(params))
if use_post
else self._session.get(url, params=params)
)
try:
r_json = json_loads(r)
except ValueError as e:
Expand Down
9 changes: 9 additions & 0 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,15 @@ def test_search_issues_expand(self):
self.assertTrue(hasattr(issues[0], "changelog"))
self.assertEqual(issues[0].key, self.issue)

def test_search_issues_use_post(self):
long_jql = " or ".join(f"key={self.issue}" for _ in range(2000))
with pytest.raises(JIRAError):
self.jira.search_issues(long_jql)
issues = self.jira.search_issues(long_jql, use_post=True)
issues = cast(ResultList[Issue], issues)
self.assertEqual(len(issues), 1)
self.assertEqual(issues[0].key, self.issue)


class ServerInfoTests(JiraTestCase):
def test_server_info(self):
Expand Down