crate 1.0.0__py3-none-any.whl → 1.0.0.dev1__py3-none-any.whl

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.
crate/client/http.py CHANGED
@@ -30,11 +30,11 @@ import re
30
30
  import socket
31
31
  import ssl
32
32
  import threading
33
+ from urllib.parse import urlparse
33
34
  from base64 import b64encode
34
- from datetime import date, datetime, timezone
35
- from decimal import Decimal
36
35
  from time import time
37
- from urllib.parse import urlparse
36
+ from datetime import datetime, date, timezone
37
+ from decimal import Decimal
38
38
  from uuid import UUID
39
39
 
40
40
  import urllib3
@@ -52,41 +52,42 @@ from urllib3.util.retry import Retry
52
52
  from verlib2 import Version
53
53
 
54
54
  from crate.client.exceptions import (
55
- BlobLocationNotFoundException,
56
55
  ConnectionError,
56
+ BlobLocationNotFoundException,
57
57
  DigestNotFoundException,
58
- IntegrityError,
59
58
  ProgrammingError,
59
+ IntegrityError,
60
60
  )
61
61
 
62
+
62
63
  logger = logging.getLogger(__name__)
63
64
 
64
65
 
65
- _HTTP_PAT = pat = re.compile("https?://.+", re.I)
66
- SRV_UNAVAILABLE_STATUSES = {502, 503, 504, 509}
67
- PRESERVE_ACTIVE_SERVER_EXCEPTIONS = {ConnectionResetError, BrokenPipeError}
68
- SSL_ONLY_ARGS = {"ca_certs", "cert_reqs", "cert_file", "key_file"}
66
+ _HTTP_PAT = pat = re.compile('https?://.+', re.I)
67
+ SRV_UNAVAILABLE_STATUSES = set((502, 503, 504, 509))
68
+ PRESERVE_ACTIVE_SERVER_EXCEPTIONS = set((ConnectionResetError, BrokenPipeError))
69
+ SSL_ONLY_ARGS = set(('ca_certs', 'cert_reqs', 'cert_file', 'key_file'))
69
70
 
70
71
 
71
72
  def super_len(o):
72
- if hasattr(o, "__len__"):
73
+ if hasattr(o, '__len__'):
73
74
  return len(o)
74
- if hasattr(o, "len"):
75
+ if hasattr(o, 'len'):
75
76
  return o.len
76
- if hasattr(o, "fileno"):
77
+ if hasattr(o, 'fileno'):
77
78
  try:
78
79
  fileno = o.fileno()
79
80
  except io.UnsupportedOperation:
80
81
  pass
81
82
  else:
82
83
  return os.fstat(fileno).st_size
83
- if hasattr(o, "getvalue"):
84
+ if hasattr(o, 'getvalue'):
84
85
  # e.g. BytesIO, cStringIO.StringI
85
86
  return len(o.getvalue())
86
- return None
87
87
 
88
88
 
89
89
  class CrateJsonEncoder(json.JSONEncoder):
90
+
90
91
  epoch_aware = datetime(1970, 1, 1, tzinfo=timezone.utc)
91
92
  epoch_naive = datetime(1970, 1, 1)
92
93
 
@@ -98,22 +99,21 @@ class CrateJsonEncoder(json.JSONEncoder):
98
99
  delta = o - self.epoch_aware
99
100
  else:
100
101
  delta = o - self.epoch_naive
101
- return int(
102
- delta.microseconds / 1000.0
103
- + (delta.seconds + delta.days * 24 * 3600) * 1000.0
104
- )
102
+ return int(delta.microseconds / 1000.0 +
103
+ (delta.seconds + delta.days * 24 * 3600) * 1000.0)
105
104
  if isinstance(o, date):
106
105
  return calendar.timegm(o.timetuple()) * 1000
107
106
  return json.JSONEncoder.default(self, o)
108
107
 
109
108
 
110
- class Server:
109
+ class Server(object):
110
+
111
111
  def __init__(self, server, **pool_kw):
112
112
  socket_options = _get_socket_opts(
113
- pool_kw.pop("socket_keepalive", False),
114
- pool_kw.pop("socket_tcp_keepidle", None),
115
- pool_kw.pop("socket_tcp_keepintvl", None),
116
- pool_kw.pop("socket_tcp_keepcnt", None),
113
+ pool_kw.pop('socket_keepalive', False),
114
+ pool_kw.pop('socket_tcp_keepidle', None),
115
+ pool_kw.pop('socket_tcp_keepintvl', None),
116
+ pool_kw.pop('socket_tcp_keepcnt', None),
117
117
  )
118
118
  self.pool = connection_from_url(
119
119
  server,
@@ -121,57 +121,53 @@ class Server:
121
121
  **pool_kw,
122
122
  )
123
123
 
124
- def request(
125
- self,
126
- method,
127
- path,
128
- data=None,
129
- stream=False,
130
- headers=None,
131
- username=None,
132
- password=None,
133
- schema=None,
134
- backoff_factor=0,
135
- **kwargs,
136
- ):
124
+ def request(self,
125
+ method,
126
+ path,
127
+ data=None,
128
+ stream=False,
129
+ headers=None,
130
+ username=None,
131
+ password=None,
132
+ schema=None,
133
+ backoff_factor=0,
134
+ **kwargs):
137
135
  """Send a request
138
136
 
139
137
  Always set the Content-Length and the Content-Type header.
140
138
  """
141
139
  if headers is None:
142
140
  headers = {}
143
- if "Content-Length" not in headers:
141
+ if 'Content-Length' not in headers:
144
142
  length = super_len(data)
145
143
  if length is not None:
146
- headers["Content-Length"] = length
144
+ headers['Content-Length'] = length
147
145
 
148
146
  # Authentication credentials
149
147
  if username is not None:
150
- if "Authorization" not in headers and username is not None:
151
- credentials = username + ":"
148
+ if 'Authorization' not in headers and username is not None:
149
+ credentials = username + ':'
152
150
  if password is not None:
153
151
  credentials += password
154
- headers["Authorization"] = "Basic %s" % b64encode(
155
- credentials.encode("utf-8")
156
- ).decode("utf-8")
152
+ headers['Authorization'] = 'Basic %s' % b64encode(credentials.encode('utf-8')).decode('utf-8')
157
153
  # For backwards compatibility with Crate <= 2.2
158
- if "X-User" not in headers:
159
- headers["X-User"] = username
154
+ if 'X-User' not in headers:
155
+ headers['X-User'] = username
160
156
 
161
157
  if schema is not None:
162
- headers["Default-Schema"] = schema
163
- headers["Accept"] = "application/json"
164
- headers["Content-Type"] = "application/json"
165
- kwargs["assert_same_host"] = False
166
- kwargs["redirect"] = False
167
- kwargs["retries"] = Retry(read=0, backoff_factor=backoff_factor)
158
+ headers['Default-Schema'] = schema
159
+ headers['Accept'] = 'application/json'
160
+ headers['Content-Type'] = 'application/json'
161
+ kwargs['assert_same_host'] = False
162
+ kwargs['redirect'] = False
163
+ kwargs['retries'] = Retry(read=0, backoff_factor=backoff_factor)
168
164
  return self.pool.urlopen(
169
165
  method,
170
166
  path,
171
167
  body=data,
172
168
  preload_content=not stream,
173
169
  headers=headers,
174
- **kwargs,
170
+ **kwargs
175
171
  )
176
172
 
177
173
  def close(self):
@@ -180,27 +176,24 @@ class Server:
180
176
 
181
177
  def _json_from_response(response):
182
178
  try:
183
- return json.loads(response.data.decode("utf-8"))
184
- except ValueError as ex:
179
+ return json.loads(response.data.decode('utf-8'))
180
+ except ValueError:
185
181
  raise ProgrammingError(
186
- "Invalid server response of content-type '{}':\n{}".format(
187
- response.headers.get("content-type", "unknown"),
188
- response.data.decode("utf-8"),
189
- )
190
- ) from ex
182
+ "Invalid server response of content-type '{}':\n{}"
183
+ .format(response.headers.get("content-type", "unknown"), response.data.decode('utf-8')))
191
184
 
192
185
 
193
186
  def _blob_path(table, digest):
194
- return "/_blobs/{table}/{digest}".format(table=table, digest=digest)
187
+ return '/_blobs/{table}/{digest}'.format(table=table, digest=digest)
195
188
 
196
189
 
197
190
  def _ex_to_message(ex):
198
- return getattr(ex, "message", None) or str(ex) or repr(ex)
191
+ return getattr(ex, 'message', None) or str(ex) or repr(ex)
199
192
 
200
193
 
201
194
  def _raise_for_status(response):
202
195
  """
203
- Raise `IntegrityError` exceptions for `DuplicateKeyException` errors.
196
+ Properly raise `IntegrityError` exceptions for CrateDB's `DuplicateKeyException` errors.
204
197
  """
205
198
  try:
206
199
  return _raise_for_status_real(response)
@@ -211,33 +204,29 @@ def _raise_for_status(response):
211
204
 
212
205
 
213
206
  def _raise_for_status_real(response):
214
- """make sure that only crate.exceptions are raised that are defined in
215
- the DB-API specification"""
216
- message = ""
207
+ """ make sure that only crate.exceptions are raised that are defined in
208
+ the DB-API specification """
209
+ message = ''
217
210
  if 400 <= response.status < 500:
218
- message = "%s Client Error: %s" % (response.status, response.reason)
211
+ message = '%s Client Error: %s' % (response.status, response.reason)
219
212
  elif 500 <= response.status < 600:
220
- message = "%s Server Error: %s" % (response.status, response.reason)
213
+ message = '%s Server Error: %s' % (response.status, response.reason)
221
214
  else:
222
215
  return
223
216
  if response.status == 503:
224
217
  raise ConnectionError(message)
225
218
  if response.headers.get("content-type", "").startswith("application/json"):
226
- data = json.loads(response.data.decode("utf-8"))
227
- error = data.get("error", {})
228
- error_trace = data.get("error_trace", None)
219
+ data = json.loads(response.data.decode('utf-8'))
220
+ error = data.get('error', {})
221
+ error_trace = data.get('error_trace', None)
229
222
  if "results" in data:
230
- errors = [
231
- res["error_message"]
232
- for res in data["results"]
233
- if res.get("error_message")
234
- ]
223
+ errors = [res["error_message"] for res in data["results"]
224
+ if res.get("error_message")]
235
225
  if errors:
236
226
  raise ProgrammingError("\n".join(errors))
237
227
  if isinstance(error, dict):
238
- raise ProgrammingError(
239
- error.get("message", ""), error_trace=error_trace
240
- )
228
+ raise ProgrammingError(error.get('message', ''),
229
+ error_trace=error_trace)
241
230
  raise ProgrammingError(error, error_trace=error_trace)
242
231
  raise ProgrammingError(message)
243
232
 
@@ -258,9 +247,9 @@ def _server_url(server):
258
247
  http://demo.crate.io
259
248
  """
260
249
  if not _HTTP_PAT.match(server):
261
- server = "http://%s" % server
250
+ server = 'http://%s' % server
262
251
  parsed = urlparse(server)
263
- url = "%s://%s" % (parsed.scheme, parsed.netloc)
252
+ url = '%s://%s' % (parsed.scheme, parsed.netloc)
264
253
  return url
265
254
 
266
255
 
@@ -270,36 +259,30 @@ def _to_server_list(servers):
270
259
  return [_server_url(s) for s in servers]
271
260
 
272
261
 
273
- def _pool_kw_args(
274
- verify_ssl_cert,
275
- ca_cert,
276
- client_cert,
277
- client_key,
278
- timeout=None,
279
- pool_size=None,
280
- ):
281
- ca_cert = ca_cert or os.environ.get("REQUESTS_CA_BUNDLE", None)
262
+ def _pool_kw_args(verify_ssl_cert, ca_cert, client_cert, client_key,
263
+ timeout=None, pool_size=None):
264
+ ca_cert = ca_cert or os.environ.get('REQUESTS_CA_BUNDLE', None)
282
265
  if ca_cert and not os.path.exists(ca_cert):
283
266
  # Sanity check
284
267
  raise IOError('CA bundle file "{}" does not exist.'.format(ca_cert))
285
268
 
286
269
  kw = {
287
- "ca_certs": ca_cert,
288
- "cert_reqs": ssl.CERT_REQUIRED if verify_ssl_cert else ssl.CERT_NONE,
289
- "cert_file": client_cert,
290
- "key_file": client_key,
270
+ 'ca_certs': ca_cert,
271
+ 'cert_reqs': ssl.CERT_REQUIRED if verify_ssl_cert else ssl.CERT_NONE,
272
+ 'cert_file': client_cert,
273
+ 'key_file': client_key,
291
274
  }
292
275
  if timeout is not None:
293
276
  if isinstance(timeout, str):
294
277
  timeout = float(timeout)
295
- kw["timeout"] = timeout
278
+ kw['timeout'] = timeout
296
279
  if pool_size is not None:
297
- kw["maxsize"] = int(pool_size)
280
+ kw['maxsize'] = int(pool_size)
298
281
  return kw
299
282
 
300
283
 
301
284
  def _remove_certs_for_non_https(server, kwargs):
302
- if server.lower().startswith("https"):
285
+ if server.lower().startswith('https'):
303
286
  return kwargs
304
287
  used_ssl_args = SSL_ONLY_ARGS & set(kwargs.keys())
305
288
  if used_ssl_args:
@@ -317,7 +300,6 @@ def _update_pool_kwargs_for_ssl_minimum_version(server, kwargs):
317
300
  """
318
301
  if Version(urllib3.__version__) >= Version("2"):
319
302
  from urllib3.util import parse_url
320
-
321
303
  scheme, _, host, port, *_ = parse_url(server)
322
304
  if scheme == "https":
323
305
  kwargs["ssl_minimum_version"] = ssl.TLSVersion.MINIMUM_SUPPORTED
@@ -325,21 +307,24 @@ def _update_pool_kwargs_for_ssl_minimum_version(server, kwargs):
325
307
 
326
308
  def _create_sql_payload(stmt, args, bulk_args):
327
309
  if not isinstance(stmt, str):
328
- raise ValueError("stmt is not a string")
310
+ raise ValueError('stmt is not a string')
329
311
  if args and bulk_args:
330
- raise ValueError("Cannot provide both: args and bulk_args")
312
+ raise ValueError('Cannot provide both: args and bulk_args')
331
313
 
332
- data = {"stmt": stmt}
314
+ data = {
315
+ 'stmt': stmt
316
+ }
333
317
  if args:
334
- data["args"] = args
318
+ data['args'] = args
335
319
  if bulk_args:
336
- data["bulk_args"] = bulk_args
320
+ data['bulk_args'] = bulk_args
337
321
  return json.dumps(data, cls=CrateJsonEncoder)
338
322
 
339
323
 
340
- def _get_socket_opts(
341
- keepalive=True, tcp_keepidle=None, tcp_keepintvl=None, tcp_keepcnt=None
342
- ):
324
+ def _get_socket_opts(keepalive=True,
325
+ tcp_keepidle=None,
326
+ tcp_keepintvl=None,
327
+ tcp_keepcnt=None):
343
328
  """
344
329
  Return an optional list of socket options for urllib3's HTTPConnection
345
330
  constructor.
@@ -352,23 +337,23 @@ def _get_socket_opts(
352
337
 
353
338
  # hasattr check because some options depend on system capabilities
354
339
  # see https://docs.python.org/3/library/socket.html#socket.SOMAXCONN
355
- if hasattr(socket, "TCP_KEEPIDLE") and tcp_keepidle is not None:
340
+ if hasattr(socket, 'TCP_KEEPIDLE') and tcp_keepidle is not None:
356
341
  opts.append((socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, tcp_keepidle))
357
- if hasattr(socket, "TCP_KEEPINTVL") and tcp_keepintvl is not None:
342
+ if hasattr(socket, 'TCP_KEEPINTVL') and tcp_keepintvl is not None:
358
343
  opts.append((socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, tcp_keepintvl))
359
- if hasattr(socket, "TCP_KEEPCNT") and tcp_keepcnt is not None:
344
+ if hasattr(socket, 'TCP_KEEPCNT') and tcp_keepcnt is not None:
360
345
  opts.append((socket.IPPROTO_TCP, socket.TCP_KEEPCNT, tcp_keepcnt))
361
346
 
362
347
  # additionally use urllib3's default socket options
363
- return list(HTTPConnection.default_socket_options) + opts
348
+ return HTTPConnection.default_socket_options + opts
364
349
 
365
350
 
366
- class Client:
351
+ class Client(object):
367
352
  """
368
353
  Crate connection client using CrateDB's HTTP API.
369
354
  """
370
355
 
371
- SQL_PATH = "/_sql?types=true"
356
+ SQL_PATH = '/_sql?types=true'
372
357
  """Crate URI path for issuing SQL statements."""
373
358
 
374
359
  retry_interval = 30
@@ -377,26 +362,25 @@ class Client:
377
362
  default_server = "http://127.0.0.1:4200"
378
363
  """Default server to use if no servers are given on instantiation."""
379
364
 
380
- def __init__(
381
- self,
382
- servers=None,
383
- timeout=None,
384
- backoff_factor=0,
385
- verify_ssl_cert=True,
386
- ca_cert=None,
387
- error_trace=False,
388
- cert_file=None,
389
- key_file=None,
390
- ssl_relax_minimum_version=False,
391
- username=None,
392
- password=None,
393
- schema=None,
394
- pool_size=None,
395
- socket_keepalive=True,
396
- socket_tcp_keepidle=None,
397
- socket_tcp_keepintvl=None,
398
- socket_tcp_keepcnt=None,
399
- ):
365
+ def __init__(self,
366
+ servers=None,
367
+ timeout=None,
368
+ backoff_factor=0,
369
+ verify_ssl_cert=True,
370
+ ca_cert=None,
371
+ error_trace=False,
372
+ cert_file=None,
373
+ key_file=None,
374
+ ssl_relax_minimum_version=False,
375
+ username=None,
376
+ password=None,
377
+ schema=None,
378
+ pool_size=None,
379
+ socket_keepalive=True,
380
+ socket_tcp_keepidle=None,
381
+ socket_tcp_keepintvl=None,
382
+ socket_tcp_keepcnt=None,
383
+ ):
400
384
  if not servers:
401
385
  servers = [self.default_server]
402
386
  else:
@@ -412,30 +396,22 @@ class Client:
412
396
  if url.password is not None:
413
397
  password = url.password
414
398
  except Exception as ex:
415
- logger.warning(
416
- "Unable to decode credentials from database "
417
- "URI, so connecting to CrateDB without "
418
- "authentication: {ex}".format(ex=ex)
419
- )
399
+ logger.warning("Unable to decode credentials from database "
400
+ "URI, so connecting to CrateDB without "
401
+ "authentication: {ex}"
402
+ .format(ex=ex))
420
403
 
421
404
  self._active_servers = servers
422
405
  self._inactive_servers = []
423
406
  pool_kw = _pool_kw_args(
424
- verify_ssl_cert,
425
- ca_cert,
426
- cert_file,
427
- key_file,
428
- timeout,
429
- pool_size,
430
- )
431
- pool_kw.update(
432
- {
433
- "socket_keepalive": socket_keepalive,
434
- "socket_tcp_keepidle": socket_tcp_keepidle,
435
- "socket_tcp_keepintvl": socket_tcp_keepintvl,
436
- "socket_tcp_keepcnt": socket_tcp_keepcnt,
437
- }
407
+ verify_ssl_cert, ca_cert, cert_file, key_file, timeout, pool_size,
438
408
  )
409
+ pool_kw.update({
410
+ 'socket_keepalive': socket_keepalive,
411
+ 'socket_tcp_keepidle': socket_tcp_keepidle,
412
+ 'socket_tcp_keepintvl': socket_tcp_keepintvl,
413
+ 'socket_tcp_keepcnt': socket_tcp_keepcnt,
414
+ })
439
415
  self.ssl_relax_minimum_version = ssl_relax_minimum_version
440
416
  self.backoff_factor = backoff_factor
441
417
  self.server_pool = {}
@@ -449,7 +425,7 @@ class Client:
449
425
 
450
426
  self.path = self.SQL_PATH
451
427
  if error_trace:
452
- self.path += "&error_trace=true"
428
+ self.path += '&error_trace=true'
453
429
 
454
430
  def close(self):
455
431
  for server in self.server_pool.values():
@@ -457,9 +433,8 @@ class Client:
457
433
 
458
434
  def _create_server(self, server, **pool_kw):
459
435
  kwargs = _remove_certs_for_non_https(server, pool_kw)
460
- # After updating to urllib3 v2, optionally retain support
461
- # for TLS 1.0 and TLS 1.1, in order to support connectivity
462
- # to older versions of CrateDB.
436
+ # After updating to urllib3 v2, optionally retain support for TLS 1.0 and TLS 1.1,
437
+ # in order to support connectivity to older versions of CrateDB.
463
438
  if self.ssl_relax_minimum_version:
464
439
  _update_pool_kwargs_for_ssl_minimum_version(server, kwargs)
465
440
  self.server_pool[server] = Server(server, **kwargs)
@@ -476,26 +451,28 @@ class Client:
476
451
  return None
477
452
 
478
453
  data = _create_sql_payload(stmt, parameters, bulk_parameters)
479
- logger.debug("Sending request to %s with payload: %s", self.path, data)
480
- content = self._json_request("POST", self.path, data=data)
454
+ logger.debug(
455
+ 'Sending request to %s with payload: %s', self.path, data)
456
+ content = self._json_request('POST', self.path, data=data)
481
457
  logger.debug("JSON response for stmt(%s): %s", stmt, content)
482
458
 
483
459
  return content
484
460
 
485
461
  def server_infos(self, server):
486
- response = self._request("GET", "/", server=server)
462
+ response = self._request('GET', '/', server=server)
487
463
  _raise_for_status(response)
488
464
  content = _json_from_response(response)
489
465
  node_name = content.get("name")
490
- node_version = content.get("version", {}).get("number", "0.0.0")
466
+ node_version = content.get('version', {}).get('number', '0.0.0')
491
467
  return server, node_name, node_version
492
468
 
493
- def blob_put(self, table, digest, data) -> bool:
469
+ def blob_put(self, table, digest, data):
494
470
  """
495
471
  Stores the contents of the file like @data object in a blob under the
496
472
  given table and digest.
497
473
  """
498
- response = self._request("PUT", _blob_path(table, digest), data=data)
474
+ response = self._request('PUT', _blob_path(table, digest),
475
+ data=data)
499
476
  if response.status == 201:
500
477
  # blob created
501
478
  return True
@@ -505,43 +482,40 @@ class Client:
505
482
  if response.status in (400, 404):
506
483
  raise BlobLocationNotFoundException(table, digest)
507
484
  _raise_for_status(response)
508
- return False
509
485
 
510
- def blob_del(self, table, digest) -> bool:
486
+ def blob_del(self, table, digest):
511
487
  """
512
488
  Deletes the blob with given digest under the given table.
513
489
  """
514
- response = self._request("DELETE", _blob_path(table, digest))
490
+ response = self._request('DELETE', _blob_path(table, digest))
515
491
  if response.status == 204:
516
492
  return True
517
493
  if response.status == 404:
518
494
  return False
519
495
  _raise_for_status(response)
520
- return False
521
496
 
522
497
  def blob_get(self, table, digest, chunk_size=1024 * 128):
523
498
  """
524
499
  Returns a file like object representing the contents of the blob
525
500
  with the given digest.
526
501
  """
527
- response = self._request("GET", _blob_path(table, digest), stream=True)
502
+ response = self._request('GET', _blob_path(table, digest), stream=True)
528
503
  if response.status == 404:
529
504
  raise DigestNotFoundException(table, digest)
530
505
  _raise_for_status(response)
531
506
  return response.stream(amt=chunk_size)
532
507
 
533
- def blob_exists(self, table, digest) -> bool:
508
+ def blob_exists(self, table, digest):
534
509
  """
535
510
  Returns true if the blob with the given digest exists
536
511
  under the given table.
537
512
  """
538
- response = self._request("HEAD", _blob_path(table, digest))
513
+ response = self._request('HEAD', _blob_path(table, digest))
539
514
  if response.status == 200:
540
515
  return True
541
516
  elif response.status == 404:
542
517
  return False
543
518
  _raise_for_status(response)
544
- return False
545
519
 
546
520
  def _add_server(self, server):
547
521
  with self._lock:
@@ -563,45 +537,42 @@ class Client:
563
537
  password=self.password,
564
538
  backoff_factor=self.backoff_factor,
565
539
  schema=self.schema,
566
- **kwargs,
540
+ **kwargs
567
541
  )
568
542
  redirect_location = response.get_redirect_location()
569
543
  if redirect_location and 300 <= response.status <= 308:
570
544
  redirect_server = _server_url(redirect_location)
571
545
  self._add_server(redirect_server)
572
546
  return self._request(
573
- method, path, server=redirect_server, **kwargs
574
- )
547
+ method, path, server=redirect_server, **kwargs)
575
548
  if not server and response.status in SRV_UNAVAILABLE_STATUSES:
576
549
  with self._lock:
577
550
  # drop server from active ones
578
551
  self._drop_server(next_server, response.reason)
579
552
  else:
580
553
  return response
581
- except (
582
- MaxRetryError,
583
- ReadTimeoutError,
584
- SSLError,
585
- HTTPError,
586
- ProxyError,
587
- ) as ex:
554
+ except (MaxRetryError,
555
+ ReadTimeoutError,
556
+ SSLError,
557
+ HTTPError,
558
+ ProxyError,) as ex:
588
559
  ex_message = _ex_to_message(ex)
589
560
  if server:
590
561
  raise ConnectionError(
591
562
  "Server not available, exception: %s" % ex_message
592
- ) from ex
563
+ )
593
564
  preserve_server = False
594
565
  if isinstance(ex, ProtocolError):
595
566
  preserve_server = any(
596
567
  t in [type(arg) for arg in ex.args]
597
568
  for t in PRESERVE_ACTIVE_SERVER_EXCEPTIONS
598
569
  )
599
- if not preserve_server:
570
+ if (not preserve_server):
600
571
  with self._lock:
601
572
  # drop server from active ones
602
573
  self._drop_server(next_server, ex_message)
603
574
  except Exception as e:
604
- raise ProgrammingError(_ex_to_message(e)) from e
575
+ raise ProgrammingError(_ex_to_message(e))
605
576
 
606
577
  def _json_request(self, method, path, data):
607
578
  """
@@ -621,7 +592,7 @@ class Client:
621
592
  """
622
593
  with self._lock:
623
594
  inactive_server_count = len(self._inactive_servers)
624
- for _ in range(inactive_server_count):
595
+ for i in range(inactive_server_count):
625
596
  try:
626
597
  ts, server, message = heapq.heappop(self._inactive_servers)
627
598
  except IndexError:
@@ -629,14 +600,12 @@ class Client:
629
600
  else:
630
601
  if (ts + self.retry_interval) > time():
631
602
  # Not yet, put it back
632
- heapq.heappush(
633
- self._inactive_servers, (ts, server, message)
634
- )
603
+ heapq.heappush(self._inactive_servers,
604
+ (ts, server, message))
635
605
  else:
636
606
  self._active_servers.append(server)
637
- logger.warning(
638
- "Restored server %s into active pool", server
639
- )
607
+ logger.warning("Restored server %s into active pool",
608
+ server)
640
609
 
641
610
  # if none is old enough, use oldest
642
611
  if not self._active_servers:
@@ -670,9 +639,8 @@ class Client:
670
639
  # if this is the last server raise exception, otherwise try next
671
640
  if not self._active_servers:
672
641
  raise ConnectionError(
673
- ("No more Servers available, " "exception from last server: %s")
674
- % message
675
- )
642
+ ("No more Servers available, "
643
+ "exception from last server: %s") % message)
676
644
 
677
645
  def _roundrobin(self):
678
646
  """
@@ -681,4 +649,4 @@ class Client:
681
649
  self._active_servers.append(self._active_servers.pop(0))
682
650
 
683
651
  def __repr__(self):
684
- return "<Client {0}>".format(str(self._active_servers))
652
+ return '<Client {0}>'.format(str(self._active_servers))