arkindex-client 1.0.14__tar.gz → 1.0.16__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/PKG-INFO +2 -2
  2. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/README.rst +1 -1
  3. arkindex-client-1.0.16/VERSION +1 -0
  4. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/arkindex/client.py +44 -3
  5. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/arkindex/pagination.py +4 -3
  6. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/arkindex/transports.py +5 -0
  7. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/arkindex_client.egg-info/PKG-INFO +2 -2
  8. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/arkindex_client.egg-info/requires.txt +1 -0
  9. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/requirements.txt +1 -0
  10. arkindex-client-1.0.14/VERSION +0 -1
  11. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/MANIFEST.in +0 -0
  12. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/arkindex/__init__.py +0 -0
  13. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/arkindex/auth.py +0 -0
  14. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/arkindex/exceptions.py +0 -0
  15. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/arkindex/mock.py +0 -0
  16. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/arkindex_client.egg-info/SOURCES.txt +0 -0
  17. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/arkindex_client.egg-info/dependency_links.txt +0 -0
  18. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/arkindex_client.egg-info/top_level.txt +0 -0
  19. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/setup.cfg +0 -0
  20. {arkindex-client-1.0.14 → arkindex-client-1.0.16}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arkindex-client
3
- Version: 1.0.14
3
+ Version: 1.0.16
4
4
  Summary: API client for the Arkindex project
5
5
  Home-page: https://gitlab.teklia.com/arkindex/api-client
6
6
  Author: Teklia <contact@teklia.com>
@@ -164,7 +164,7 @@ exception's attributes:
164
164
  except ErrorResponse as e:
165
165
  print(e.title) # "400 Bad Request"
166
166
  print(e.status_code) # 400
167
- print(e.result) # Any kind of response body the server might give
167
+ print(e.content) # Any kind of response body the server might give
168
168
 
169
169
  Note that by default, using ``repr()`` or ``str()`` on APIStar exceptions will
170
170
  not give any useful messages; a fix in APIStar is waiting to be merged. In
@@ -142,7 +142,7 @@ exception's attributes:
142
142
  except ErrorResponse as e:
143
143
  print(e.title) # "400 Bad Request"
144
144
  print(e.status_code) # 400
145
- print(e.result) # Any kind of response body the server might give
145
+ print(e.content) # Any kind of response body the server might give
146
146
 
147
147
  Note that by default, using ``repr()`` or ``str()`` on APIStar exceptions will
148
148
  not give any useful messages; a fix in APIStar is waiting to be merged. In
@@ -0,0 +1 @@
1
+ 1.0.16
@@ -11,6 +11,14 @@ from urllib.parse import urljoin, urlsplit, urlunsplit
11
11
  import apistar
12
12
  import requests
13
13
  import yaml
14
+ from apistar.exceptions import ErrorResponse
15
+ from tenacity import (
16
+ before_sleep_log,
17
+ retry,
18
+ retry_if_exception,
19
+ stop_after_attempt,
20
+ wait_exponential,
21
+ )
14
22
 
15
23
  from arkindex.auth import TokenSessionAuthentication
16
24
  from arkindex.exceptions import SchemaError
@@ -27,6 +35,17 @@ SCHEMA_ENDPOINT = "/api/v1/openapi/?format=json"
27
35
  logger = logging.getLogger(__name__)
28
36
 
29
37
 
38
+ def _is_500_error(exc: Exception) -> bool:
39
+ """
40
+ Check if an Arkindex API error is a 50x
41
+ This is used to retry most API calls implemented here
42
+ """
43
+ if not isinstance(exc, ErrorResponse):
44
+ return False
45
+
46
+ return 500 <= exc.status_code < 600
47
+
48
+
30
49
  def options_from_env():
31
50
  """
32
51
  Get API client keyword arguments from environment variables.
@@ -84,6 +103,7 @@ class ArkindexClient(apistar.Client):
84
103
  schema_url=None,
85
104
  csrf_cookie=None,
86
105
  sleep=0,
106
+ verify=True,
87
107
  **kwargs,
88
108
  ):
89
109
  r"""
@@ -103,6 +123,7 @@ class ArkindexClient(apistar.Client):
103
123
  if not schema_url:
104
124
  schema_url = urljoin(base_url, SCHEMA_ENDPOINT)
105
125
 
126
+ self.verify = verify
106
127
  try:
107
128
  split = urlsplit(schema_url)
108
129
  if split.scheme == "file" or not (split.scheme or split.netloc):
@@ -110,7 +131,7 @@ class ArkindexClient(apistar.Client):
110
131
  with open(schema_url) as f:
111
132
  schema = yaml.safe_load(f)
112
133
  else:
113
- resp = requests.get(schema_url)
134
+ resp = requests.get(schema_url, verify=self.verify)
114
135
  resp.raise_for_status()
115
136
  schema = yaml.safe_load(resp.content)
116
137
  except Exception as e:
@@ -173,7 +194,7 @@ class ArkindexClient(apistar.Client):
173
194
  )
174
195
 
175
196
  def init_transport(self, *args, **kwargs):
176
- return ArkindexHTTPTransport(*args, **kwargs)
197
+ return ArkindexHTTPTransport(self.verify, *args, **kwargs)
177
198
 
178
199
  def configure(
179
200
  self,
@@ -243,7 +264,7 @@ class ArkindexClient(apistar.Client):
243
264
  self.transport.session.auth.token = resp["auth_token"]
244
265
  return resp
245
266
 
246
- def request(self, operation_id, *args, **kwargs):
267
+ def single_request(self, operation_id, *args, **kwargs):
247
268
  """
248
269
  Perform an API request.
249
270
  :param args: Arguments passed to the APIStar client.
@@ -272,3 +293,23 @@ class ArkindexClient(apistar.Client):
272
293
  )
273
294
  sleep(self.sleep_duration)
274
295
  return super().request(operation_id, *args, **kwargs)
296
+
297
+ @retry(
298
+ retry=retry_if_exception(_is_500_error),
299
+ wait=wait_exponential(multiplier=2, min=3),
300
+ reraise=True,
301
+ stop=stop_after_attempt(5),
302
+ before_sleep=before_sleep_log(logger, logging.INFO),
303
+ )
304
+ def request(self, operation_id, *args, **kwargs):
305
+ """
306
+ Proxy all Arkindex API requests with a retry mechanism in case of 50X errors.
307
+ The same API call will be retried 5 times, with an exponential sleep time
308
+ going through 3, 4, 8 and 16 seconds of wait between call.
309
+ If the 5th call still gives a 50x, the exception is re-raised and the caller should catch it.
310
+ Log messages are displayed before sleeping (when at least one exception occurred).
311
+
312
+ :param args: Arguments passed to the APIStar client.
313
+ :param kwargs: Keyword arguments passed to the APIStar client.
314
+ """
315
+ return self.single_request(operation_id, *args, **kwargs)
@@ -117,13 +117,14 @@ class ResponsePaginator(Sized, Iterator):
117
117
  if "with_count" in operation_fields:
118
118
  extra_kwargs["with_count"] = "true"
119
119
  else:
120
+ remaining_count = self.pages_count - self.pages_loaded
120
121
  logger.info(
121
122
  f"Loading {self.mode.value} {index} on try {self.retries - retry + 1}/{self.retries}"
122
- f" - remains {self.pages_count - self.pages_loaded} pages to load."
123
+ f" - remains {remaining_count} page{'s' if remaining_count > 1 else ''} to load."
123
124
  )
124
125
 
125
126
  # Fetch the next page
126
- self.data = self.client.request(
127
+ self.data = self.client.single_request(
127
128
  self.operation_id,
128
129
  *self.request_args,
129
130
  **self.request_kwargs,
@@ -147,7 +148,7 @@ class ResponsePaginator(Sized, Iterator):
147
148
  return False
148
149
  self.pages_count = math.ceil(self.count / len(self.results))
149
150
  logger.info(
150
- f"Pagination will load a total of {self.pages_count} pages."
151
+ f"Pagination will load a total of {self.pages_count} page{'s' if self.pages_count > 1 else ''}."
151
152
  )
152
153
  if self.mode == PaginationMode.PageNumber:
153
154
  # Initialize all pages once
@@ -3,7 +3,12 @@ from apistar.client.transports import HTTPTransport
3
3
 
4
4
 
5
5
  class ArkindexHTTPTransport(HTTPTransport):
6
+ def __init__(self, verify=True, *args, **kwargs):
7
+ super().__init__(*args, **kwargs)
8
+ self.verify = verify
9
+
6
10
  def get_request_options(self, *args, **kwargs):
7
11
  options = super().get_request_options(*args, **kwargs)
8
12
  options["timeout"] = (30, 60)
13
+ options["verify"] = self.verify
9
14
  return options
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arkindex-client
3
- Version: 1.0.14
3
+ Version: 1.0.16
4
4
  Summary: API client for the Arkindex project
5
5
  Home-page: https://gitlab.teklia.com/arkindex/api-client
6
6
  Author: Teklia <contact@teklia.com>
@@ -164,7 +164,7 @@ exception's attributes:
164
164
  except ErrorResponse as e:
165
165
  print(e.title) # "400 Bad Request"
166
166
  print(e.status_code) # 400
167
- print(e.result) # Any kind of response body the server might give
167
+ print(e.content) # Any kind of response body the server might give
168
168
 
169
169
  Note that by default, using ``repr()`` or ``str()`` on APIStar exceptions will
170
170
  not give any useful messages; a fix in APIStar is waiting to be merged. In
@@ -1,3 +1,4 @@
1
1
  apistar==0.7.2
2
2
  requests~=2.28
3
+ tenacity==8.2.3
3
4
  typesystem==0.2.5
@@ -1,3 +1,4 @@
1
1
  apistar==0.7.2
2
2
  requests~=2.28
3
+ tenacity==8.2.3
3
4
  typesystem==0.2.5
@@ -1 +0,0 @@
1
- 1.0.14