Compare commits

...

2 Commits

Author SHA1 Message Date
Rodrigo Rodrigues
6d8e810bb0
Merge ca3dd7c813 into c5916a3b66 2026-01-16 17:10:18 +00:00
Rodrigo Rodrigues
ca3dd7c813 CP-2451 Add paginator iterator helper 2026-01-16 17:09:05 +00:00
3 changed files with 92 additions and 0 deletions

View File

@ -1,3 +1,18 @@
# thousandeyes-sdk-core # thousandeyes-sdk-core
This package provides core functionality for interacting with the ThousandEyes API and should be installed before using any of the published SDKs. This package provides core functionality for interacting with the ThousandEyes API and should be installed before using any of the published SDKs.
Usage example for iterating paginated responses:
```python
from thousandeyes_sdk.core import PaginatorIterator
from thousandeyes_sdk.usage.api.usage_api import UsageApi
usage_api = UsageApi()
for page in PaginatorIterator(
usage_api.get_enterprise_agents_units_usage,
start_date="2024-01-01T00:00:00Z",
end_date="2024-01-31T23:59:59Z",
):
print(page)
```

View File

@ -18,5 +18,6 @@ from . import exceptions
from .api_client import ApiClient from .api_client import ApiClient
from .api_response import ApiResponse from .api_response import ApiResponse
from .configuration import Configuration from .configuration import Configuration
from .iterable import PaginatorIterator
import os.path import os.path

View File

@ -0,0 +1,76 @@
# Copyright 2024 Cisco Systems, Inc. and its affiliates
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
from typing import Any, Callable, Iterator, Mapping, Optional
from urllib.parse import parse_qs, urlparse
class PaginatorIterator:
"""Iterate over paginated responses for a method that accepts a cursor."""
def __init__(
self,
method: Callable[..., Any],
*,
cursor_param: str = "cursor",
**params: Any,
) -> None:
self._method = method
self._cursor_param = cursor_param
self._params = dict(params)
def __iter__(self) -> Iterator[Any]:
params = dict(self._params)
last_cursor = params.get(self._cursor_param)
while True:
response = self._method(**params)
yield response
next_cursor = self._next_cursor_from_response(response)
if not next_cursor or next_cursor == last_cursor:
break
params[self._cursor_param] = next_cursor
last_cursor = next_cursor
def _next_cursor_from_response(self, response: Any) -> Optional[str]:
data = getattr(response, "data", response)
links = getattr(data, "links", None)
if links is None:
links = getattr(data, "_links", None)
if links is None and isinstance(data, Mapping):
links = data.get("_links") or data.get("links")
if links is None:
return None
next_link = getattr(links, "next", None)
if next_link is None and isinstance(links, Mapping):
next_link = links.get("next")
if next_link is None:
return None
if isinstance(next_link, str):
href = next_link
elif isinstance(next_link, Mapping):
href = next_link.get("href")
else:
href = getattr(next_link, "href", None)
if not href:
return None
parsed = urlparse(href)
query_params = parse_qs(parsed.query)
cursor_values = query_params.get(self._cursor_param)
if cursor_values:
return cursor_values[0]
return href