-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathiterators.py
More file actions
158 lines (128 loc) · 5.05 KB
/
Copy pathiterators.py
File metadata and controls
158 lines (128 loc) · 5.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#
# This file is part of the Ingram Micro CloudBlue Connect Python OpenAPI Client.
#
# Copyright (c) 2025 CloudBlue. All Rights Reserved.
#
from connect.client.utils import get_values, parse_content_range
class aiter:
def __init__(self, values):
self._values = iter(values)
async def __anext__(self):
try:
return next(self._values)
except StopIteration:
raise StopAsyncIteration
class AbstractBaseIterator:
def __init__(self, rs, client, path, query, config, **kwargs):
self._rs = rs
self._results_iterator = None
self._client = client
self._path = path
self._query = query
self._config = config
self._kwargs = kwargs
self._loaded = False
def get_item(self, item):
raise NotImplementedError('get_item must be implemented in subclasses.')
class AbstractIterator(AbstractBaseIterator):
def _load(self):
if not self._loaded:
self._rs._results, self._rs._content_range = self._execute_request()
self._results_iterator = iter(self._rs._results)
self._loaded = True
def __next__(self): # noqa: CCR001
self._load()
if not self._rs._results:
raise StopIteration
try:
item = next(self._results_iterator)
except StopIteration:
if (
self._rs._content_range is None
or self._rs._content_range.last >= self._rs._content_range.count - 1
or (self._rs._slice and self._rs._content_range.last >= self._rs._slice.stop - 1)
):
raise
self._config['params']['offset'] += self._config['params']['limit']
if self._rs._slice:
items_to_fetch = self._rs._slice.stop - self._rs._content_range.last - 1
if items_to_fetch < self._config['params']['limit']:
self._config['params']['limit'] = items_to_fetch
results, cr = self._execute_request()
if not results:
raise
self._rs._content_range = cr
if self._client.resourceset_append:
self._rs._results.extend(results)
else:
self._rs._results = results
self._results_iterator = iter(results)
item = next(self._results_iterator)
return self.get_item(item)
def _execute_request(self):
results = self._client.get(
f'{self._path}?{self._query}',
**self._config,
)
content_range = parse_content_range(
self._client.response.headers.get('Content-Range'),
)
return results, content_range
class AbstractAsyncIterator(AbstractBaseIterator):
async def _load(self):
if not self._loaded:
self._rs._results, self._rs._content_range = await self._execute_request()
self._results_iterator = iter(self._rs._results)
self._loaded = True
async def __anext__(self): # noqa: CCR001
await self._load()
if not self._rs._results:
raise StopAsyncIteration
try:
item = next(self._results_iterator)
except StopIteration:
if (
self._rs._content_range is None
or self._rs._content_range.last >= self._rs._content_range.count - 1
or (self._rs._slice and self._rs._content_range.last >= self._rs._slice.stop - 1)
):
raise StopAsyncIteration
self._config['params']['offset'] += self._config['params']['limit']
if self._rs._slice:
items_to_fetch = self._rs._slice.stop - self._rs._content_range.last - 1
if items_to_fetch < self._config['params']['limit']:
self._config['params']['limit'] = items_to_fetch
results, cr = await self._execute_request()
if not results:
raise StopAsyncIteration
self._rs._content_range = cr
if self._client.resourceset_append:
self._rs._results.extend(results)
else:
self._rs._results = results
self._results_iterator = iter(results)
item = next(self._results_iterator)
return self.get_item(item)
async def _execute_request(self):
results = await self._client.get(
f'{self._path}?{self._query}',
**self._config,
)
content_range = parse_content_range(
self._client.response.headers.get('Content-Range'),
)
return results, content_range
class ResourceMixin:
def get_item(self, item):
return item
class ValueListMixin:
def get_item(self, item):
return get_values(item, self._kwargs['fields'])
class ResourceIterator(ResourceMixin, AbstractIterator):
pass
class ValuesListIterator(ValueListMixin, AbstractIterator):
pass
class AsyncResourceIterator(ResourceMixin, AbstractAsyncIterator):
pass
class AsyncValuesListIterator(ValueListMixin, AbstractAsyncIterator):
pass