-
Notifications
You must be signed in to change notification settings - Fork 185
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
[Showstopper] Cannot use continuation token in API 7.0 and above (thus limiting number of results) #461
Comments
An idea of how to proceed would be to patch the Something like: class Client(object):
"""Client.
:param str base_url: Service URL
:param Authentication creds: Authenticated credentials.
"""
def __init__(self, base_url=None, creds=None):
...
self.continuation_token_last_request = None
def _send(self, http_method, location_id, version, route_values=None,
query_parameters=None, content=None, media_type='application/json', accept_media_type='application/json',
additional_headers=None):
...
response = self._send_request(request=request, headers=headers, content=content, media_type=media_type)
...
# Patch: Workaround to be able to see the continuation token of the response
self.continuation_token_last_request = self._get_continuation_token(response)
return response And we could use as such: >>> suite_plan_id = 68185
>>> suites = test_plan_client.get_test_suites_for_plan(project, suite_plan_id)
>>> len(suites), test_plan_client.continuation_token_last_request
(200, '339901;0')
>>> while test_plan_client.continuation_token_last_request is not None:
... suites += test_plan_client.get_test_suites_for_plan(project, suite_plan_id, continuation_token=test_plan_client.continuation_token_last_request)
>>> len(suites), test_plan_client.continuation_token_last_request
(214, None) Any better way or idea? Let's note that there is already a method |
FYI... I have done a function to temporarily patch as I described above: """Patching ADO Client to retrieve continuation token
Related to question in following issue:
https://github.com/microsoft/azure-devops-python-api/issues/461
"""
import logging
from typing import Optional, cast
from azure.devops import _models
from azure.devops.client import Client
from azure.devops.client_configuration import ClientConfiguration
from msrest import Deserializer, Serializer
from msrest.service_client import ServiceClient
logger = logging.getLogger("azure.devops.client")
# pylint: disable=super-init-not-called
class ClientPatch(Client):
"""Client.
:param str base_url: Service URL
:param Authentication creds: Authenticated credentials.
"""
def __init__(self, base_url=None, creds=None):
self.config = ClientConfiguration(base_url)
self.config.credentials = creds
self._client = ServiceClient(creds, config=self.config)
_base_client_models = {
k: v for k, v in _models.__dict__.items() if isinstance(v, type)
}
self._base_deserialize = Deserializer(_base_client_models)
self._base_serialize = Serializer(_base_client_models)
self._all_host_types_locations = {}
self._locations = {}
self._suppress_fedauth_redirect = True
self._force_msa_pass_through = True
self.normalized_url = Client._normalize_url(base_url)
self.continuation_token_last_request: Optional[str] = None
def _send(
self,
http_method,
location_id,
version,
route_values=None,
query_parameters=None,
content=None,
media_type="application/json",
accept_media_type="application/json",
additional_headers=None,
):
request = self._create_request_message(
http_method=http_method,
location_id=location_id,
route_values=route_values,
query_parameters=query_parameters,
)
negotiated_version = self._negotiate_request_version(
self._get_resource_location(self.normalized_url, location_id), version
)
negotiated_version = cast(str, negotiated_version)
if version != negotiated_version:
logger.info(
"Negotiated api version from '%s' down to '%s'."
" This means the client is newer than the server.",
version,
negotiated_version,
)
else:
logger.debug("Api version '%s'", negotiated_version)
# Construct headers
headers = {
"Content-Type": media_type + "; charset=utf-8",
"Accept": accept_media_type + ";api-version=" + negotiated_version,
}
if additional_headers is not None:
for key in additional_headers:
headers[key] = str(additional_headers[key])
if self.config.additional_headers is not None:
for key in self.config.additional_headers:
headers[key] = self.config.additional_headers[key]
if self._suppress_fedauth_redirect:
headers["X-TFS-FedAuthRedirect"] = "Suppress"
if self._force_msa_pass_through:
headers["X-VSS-ForceMsaPassThrough"] = "true"
if (
Client._session_header_key in Client._session_data
and Client._session_header_key not in headers
):
headers[Client._session_header_key] = Client._session_data[
Client._session_header_key
]
response = self._send_request(
request=request, headers=headers, content=content, media_type=media_type
)
if Client._session_header_key in response.headers:
Client._session_data[Client._session_header_key] = response.headers[
Client._session_header_key
]
# Patch: Workaround to be able to see the continuation token of the response
self.continuation_token_last_request = self._get_continuation_token(response)
return response
def patch_azure_devops_client():
"""Patch the Azure DevOps client to see the continuation token of the response"""
# pylint: disable=protected-access
Client.__init__ = ClientPatch.__init__ # type: ignore
Client._send = ClientPatch._send # type: ignore Just importing and calling the I'm really curious to know the real way to find the token though... |
Maybe it is related to an old and closed issue: |
The fact that the sample code in the project README does not run due to this issue and there has been no response here from the team does not instill a lot of confidence, does it? |
From one Jeff to another... yes, you are right. And no much more luck on StackOverflow, even though I launched a bounty. |
I just tried updating my team's stack and ran into the same issue. I'm confused how it's been this way for so long. Either we're both missing something, or this has in fact been a problem in v6.0.0 for a long time, but you can bypass it by using 6.0.0b4 and specify the v5.1. But that gets back to sanity checking - has it really been broken for about 4 years since 6.0.0 came out and everyone is collectively just working around it by using the v5.1 API? I'm guessing v6.0.0b4 will work for at least a couple of more years, so we're just planning on checking on this later. |
This functionality was removed after v5.1, but this prohibts getting a full list of builds. See bug report microsoft#461
This functionality was present in v5.1, but removed afterwards. See microsoft#461
This functionality was present in v5.1, but removed afterwards. See microsoft#461
This functionality was present in v5.1, but removed afterwards. See microsoft#461
Worth mentioning that you now have the choose between using Python 3.12 OR having functional pagination as only 7.1.0b4 works on Python 3.12. Would love to see some TLC from Microsoft on this. Contemplating just using the azure cli's devops extension via subprocess.run since this project appears to be more or less broken and unmaintained. |
Hi, in earlier versions of the API (until 6.0.0b4), when making a request on some items (e.g. WorkItems, Test Suites, ...), you had a response object with a
value
and acontinuation_token
that you could use to make a new request and continue parsing.For example, here is the prototype of such function:
So you could do something like:
With more recent versions (in particular 7.0), you now get a list returned (but with the limit of size imposed by the API).
For example, a version of similar function would be:
How to retrieve the continuation token to continue parsing the other results?
The text was updated successfully, but these errors were encountered: