| 88 | |
| 89 | |
| 90 | class LaunchDarklyClient: |
| 91 | def __init__(self, token: str) -> None: |
| 92 | client_session = Session() |
| 93 | client_session.headers.update( |
| 94 | { |
| 95 | "Authorization": token, |
| 96 | "LD-API-Version": LAUNCH_DARKLY_API_VERSION, |
| 97 | } |
| 98 | ) |
| 99 | self.client_session = client_session |
| 100 | |
| 101 | @launch_darkly_backoff |
| 102 | def _get_json_response( |
| 103 | self, |
| 104 | endpoint: str, |
| 105 | params: Optional[dict[str, Any]] = None, |
| 106 | ) -> T: # type: ignore[type-var] |
| 107 | full_url = f"{LAUNCH_DARKLY_API_BASE_URL}{endpoint}" |
| 108 | response = self.client_session.get(full_url, params=params) |
| 109 | response.raise_for_status() |
| 110 | return response.json() # type: ignore[no-any-return] |
| 111 | |
| 112 | def _iter_paginated_items( |
| 113 | self, |
| 114 | collection_endpoint: str, |
| 115 | additional_params: Optional[dict[str, Any]] = None, |
| 116 | use_legacy_offset_pagination: bool = False, |
| 117 | ) -> Iterator[T]: |
| 118 | """ |
| 119 | Iterator over paginated items in the given collection endpoint. |
| 120 | |
| 121 | :param collection_endpoint: endpoint to get the collection of items |
| 122 | :param additional_params: Additional parameters to include in the request |
| 123 | :param use_legacy_offset_pagination: Whether to use offset based pagination if `next` links do not |
| 124 | exist in the response. Some endpoints do not have `next` links and require offset based pagination. |
| 125 | :return: Iterator over the items in the collection |
| 126 | """ |
| 127 | params = {"limit": LAUNCH_DARKLY_API_ITEM_COUNT_LIMIT_PER_PAGE} |
| 128 | offset = 0 |
| 129 | if additional_params: |
| 130 | params.update(additional_params) |
| 131 | |
| 132 | response_json: dict[str, Any] = self._get_json_response( |
| 133 | endpoint=collection_endpoint, |
| 134 | params=params, |
| 135 | ) |
| 136 | while True: |
| 137 | items = response_json.get("items") or [] |
| 138 | yield from items |
| 139 | links: Optional[dict[str, ld_types.Link]] = response_json.get("_links") |
| 140 | if ( |
| 141 | links |
| 142 | and (next_link := links.get("next")) |
| 143 | and (next_endpoint := next_link.get("href")) |
| 144 | ): |
| 145 | # Don't specify params here because links.next.href includes the |
| 146 | # original limit and calculates offsets accordingly. |
| 147 | response_json = self._get_json_response( |
no outgoing calls
searching dependent graphs…