crate 1.0.0.dev1__py3-none-any.whl → 1.0.1__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/__init__.py CHANGED
@@ -23,14 +23,15 @@ from .connection import Connection as connect
23
23
  from .exceptions import Error
24
24
 
25
25
  __all__ = [
26
- connect,
27
- Error,
26
+ "connect",
27
+ "Error",
28
28
  ]
29
29
 
30
30
  # version string read from setup.py using a regex. Take care not to break the
31
31
  # regex!
32
- __version__ = "1.0.0dev1"
32
+ __version__ = "1.0.1"
33
33
 
34
+ # codeql[py/unused-global-variable]
34
35
  apilevel = "2.0"
35
36
  threadsafety = 1
36
37
  paramstyle = "qmark"
crate/client/blob.py CHANGED
@@ -22,8 +22,8 @@
22
22
  import hashlib
23
23
 
24
24
 
25
- class BlobContainer(object):
26
- """ class that represents a blob collection in crate.
25
+ class BlobContainer:
26
+ """class that represents a blob collection in crate.
27
27
 
28
28
  can be used to download, upload and delete blobs
29
29
  """
@@ -34,7 +34,7 @@ class BlobContainer(object):
34
34
 
35
35
  def _compute_digest(self, f):
36
36
  f.seek(0)
37
- m = hashlib.sha1()
37
+ m = hashlib.sha1() # noqa: S324
38
38
  while True:
39
39
  d = f.read(1024 * 32)
40
40
  if not d:
@@ -64,8 +64,9 @@ class BlobContainer(object):
64
64
  else:
65
65
  actual_digest = self._compute_digest(f)
66
66
 
67
- created = self.conn.client.blob_put(self.container_name,
68
- actual_digest, f)
67
+ created = self.conn.client.blob_put(
68
+ self.container_name, actual_digest, f
69
+ )
69
70
  if digest:
70
71
  return created
71
72
  return actual_digest
@@ -78,8 +79,9 @@ class BlobContainer(object):
78
79
  :param chunk_size: the size of the chunks returned on each iteration
79
80
  :return: generator returning chunks of data
80
81
  """
81
- return self.conn.client.blob_get(self.container_name, digest,
82
- chunk_size)
82
+ return self.conn.client.blob_get(
83
+ self.container_name, digest, chunk_size
84
+ )
83
85
 
84
86
  def delete(self, digest):
85
87
  """
@@ -19,37 +19,38 @@
19
19
  # with Crate these terms will supersede the license and you may use the
20
20
  # software solely pursuant to the terms of the relevant commercial agreement.
21
21
 
22
+ from verlib2 import Version
23
+
24
+ from .blob import BlobContainer
22
25
  from .cursor import Cursor
23
- from .exceptions import ProgrammingError, ConnectionError
26
+ from .exceptions import ConnectionError, ProgrammingError
24
27
  from .http import Client
25
- from .blob import BlobContainer
26
- from verlib2 import Version
27
28
 
28
29
 
29
- class Connection(object):
30
-
31
- def __init__(self,
32
- servers=None,
33
- timeout=None,
34
- backoff_factor=0,
35
- client=None,
36
- verify_ssl_cert=True,
37
- ca_cert=None,
38
- error_trace=False,
39
- cert_file=None,
40
- key_file=None,
41
- ssl_relax_minimum_version=False,
42
- username=None,
43
- password=None,
44
- schema=None,
45
- pool_size=None,
46
- socket_keepalive=True,
47
- socket_tcp_keepidle=None,
48
- socket_tcp_keepintvl=None,
49
- socket_tcp_keepcnt=None,
50
- converter=None,
51
- time_zone=None,
52
- ):
30
+ class Connection:
31
+ def __init__(
32
+ self,
33
+ servers=None,
34
+ timeout=None,
35
+ backoff_factor=0,
36
+ client=None,
37
+ verify_ssl_cert=True,
38
+ ca_cert=None,
39
+ error_trace=False,
40
+ cert_file=None,
41
+ key_file=None,
42
+ ssl_relax_minimum_version=False,
43
+ username=None,
44
+ password=None,
45
+ schema=None,
46
+ pool_size=None,
47
+ socket_keepalive=True,
48
+ socket_tcp_keepidle=None,
49
+ socket_tcp_keepintvl=None,
50
+ socket_tcp_keepcnt=None,
51
+ converter=None,
52
+ time_zone=None,
53
+ ):
53
54
  """
54
55
  :param servers:
55
56
  either a string in the form of '<hostname>:<port>'
@@ -118,12 +119,16 @@ class Connection(object):
118
119
  - ``zoneinfo.ZoneInfo("Australia/Sydney")``
119
120
  - ``+0530`` (UTC offset in string format)
120
121
 
122
+ The driver always returns timezone-"aware" `datetime` objects,
123
+ with their `tzinfo` attribute set.
124
+
121
125
  When `time_zone` is `None`, the returned `datetime` objects are
122
- "naive", without any `tzinfo`, converted using ``datetime.utcfromtimestamp(...)``.
126
+ using Coordinated Universal Time (UTC), because CrateDB is storing
127
+ timestamp values in this format.
123
128
 
124
- When `time_zone` is given, the returned `datetime` objects are "aware",
125
- with `tzinfo` set, converted using ``datetime.fromtimestamp(..., tz=...)``.
126
- """
129
+ When `time_zone` is given, the timestamp values will be transparently
130
+ converted from UTC to use the given time zone.
131
+ """ # noqa: E501
127
132
 
128
133
  self._converter = converter
129
134
  self.time_zone = time_zone
@@ -131,24 +136,25 @@ class Connection(object):
131
136
  if client:
132
137
  self.client = client
133
138
  else:
134
- self.client = Client(servers,
135
- timeout=timeout,
136
- backoff_factor=backoff_factor,
137
- verify_ssl_cert=verify_ssl_cert,
138
- ca_cert=ca_cert,
139
- error_trace=error_trace,
140
- cert_file=cert_file,
141
- key_file=key_file,
142
- ssl_relax_minimum_version=ssl_relax_minimum_version,
143
- username=username,
144
- password=password,
145
- schema=schema,
146
- pool_size=pool_size,
147
- socket_keepalive=socket_keepalive,
148
- socket_tcp_keepidle=socket_tcp_keepidle,
149
- socket_tcp_keepintvl=socket_tcp_keepintvl,
150
- socket_tcp_keepcnt=socket_tcp_keepcnt,
151
- )
139
+ self.client = Client(
140
+ servers,
141
+ timeout=timeout,
142
+ backoff_factor=backoff_factor,
143
+ verify_ssl_cert=verify_ssl_cert,
144
+ ca_cert=ca_cert,
145
+ error_trace=error_trace,
146
+ cert_file=cert_file,
147
+ key_file=key_file,
148
+ ssl_relax_minimum_version=ssl_relax_minimum_version,
149
+ username=username,
150
+ password=password,
151
+ schema=schema,
152
+ pool_size=pool_size,
153
+ socket_keepalive=socket_keepalive,
154
+ socket_tcp_keepidle=socket_tcp_keepidle,
155
+ socket_tcp_keepintvl=socket_tcp_keepintvl,
156
+ socket_tcp_keepcnt=socket_tcp_keepcnt,
157
+ )
152
158
  self.lowest_server_version = self._lowest_server_version()
153
159
  self._closed = False
154
160
 
@@ -182,7 +188,7 @@ class Connection(object):
182
188
  raise ProgrammingError("Connection closed")
183
189
 
184
190
  def get_blob_container(self, container_name):
185
- """ Retrieve a BlobContainer for `container_name`
191
+ """Retrieve a BlobContainer for `container_name`
186
192
 
187
193
  :param container_name: the name of the BLOB container.
188
194
  :returns: a :class:ContainerObject
@@ -199,10 +205,10 @@ class Connection(object):
199
205
  continue
200
206
  if not lowest or version < lowest:
201
207
  lowest = version
202
- return lowest or Version('0.0.0')
208
+ return lowest or Version("0.0.0")
203
209
 
204
210
  def __repr__(self):
205
- return '<Connection {0}>'.format(repr(self.client))
211
+ return "<Connection {0}>".format(repr(self.client))
206
212
 
207
213
  def __enter__(self):
208
214
  return self
crate/client/converter.py CHANGED
@@ -23,9 +23,10 @@ Machinery for converting CrateDB database types to native Python data types.
23
23
 
24
24
  https://crate.io/docs/crate/reference/en/latest/interfaces/http.html#column-types
25
25
  """
26
+
27
+ import datetime as dt
26
28
  import ipaddress
27
29
  from copy import deepcopy
28
- from datetime import datetime
29
30
  from enum import Enum
30
31
  from typing import Any, Callable, Dict, List, Optional, Union
31
32
 
@@ -33,7 +34,9 @@ ConverterFunction = Callable[[Optional[Any]], Optional[Any]]
33
34
  ColTypesDefinition = Union[int, List[Union[int, "ColTypesDefinition"]]]
34
35
 
35
36
 
36
- def _to_ipaddress(value: Optional[str]) -> Optional[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]:
37
+ def _to_ipaddress(
38
+ value: Optional[str],
39
+ ) -> Optional[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]:
37
40
  """
38
41
  https://docs.python.org/3/library/ipaddress.html
39
42
  """
@@ -42,20 +45,20 @@ def _to_ipaddress(value: Optional[str]) -> Optional[Union[ipaddress.IPv4Address,
42
45
  return ipaddress.ip_address(value)
43
46
 
44
47
 
45
- def _to_datetime(value: Optional[float]) -> Optional[datetime]:
48
+ def _to_datetime(value: Optional[float]) -> Optional[dt.datetime]:
46
49
  """
47
50
  https://docs.python.org/3/library/datetime.html
48
51
  """
49
52
  if value is None:
50
53
  return None
51
- return datetime.utcfromtimestamp(value / 1e3)
54
+ return dt.datetime.fromtimestamp(value / 1e3, tz=dt.timezone.utc)
52
55
 
53
56
 
54
57
  def _to_default(value: Optional[Any]) -> Optional[Any]:
55
58
  return value
56
59
 
57
60
 
58
- # Symbolic aliases for the numeric data type identifiers defined by the CrateDB HTTP interface.
61
+ # Data type identifiers defined by the CrateDB HTTP interface.
59
62
  # https://crate.io/docs/crate/reference/en/latest/interfaces/http.html#column-types
60
63
  class DataType(Enum):
61
64
  NULL = 0
@@ -112,7 +115,9 @@ class Converter:
112
115
  return self._mappings.get(DataType(type_), self._default)
113
116
  type_, inner_type = type_
114
117
  if DataType(type_) is not DataType.ARRAY:
115
- raise ValueError(f"Data type {type_} is not implemented as collection type")
118
+ raise ValueError(
119
+ f"Data type {type_} is not implemented as collection type"
120
+ )
116
121
 
117
122
  inner_convert = self.get(inner_type)
118
123
 
@@ -128,11 +133,11 @@ class Converter:
128
133
 
129
134
 
130
135
  class DefaultTypeConverter(Converter):
131
- def __init__(self, more_mappings: Optional[ConverterMapping] = None) -> None:
136
+ def __init__(
137
+ self, more_mappings: Optional[ConverterMapping] = None
138
+ ) -> None:
132
139
  mappings: ConverterMapping = {}
133
140
  mappings.update(deepcopy(_DEFAULT_CONVERTERS))
134
141
  if more_mappings:
135
142
  mappings.update(deepcopy(more_mappings))
136
- super().__init__(
137
- mappings=mappings, default=_to_default
138
- )
143
+ super().__init__(mappings=mappings, default=_to_default)
crate/client/cursor.py CHANGED
@@ -18,21 +18,20 @@
18
18
  # However, if you have executed another commercial license agreement
19
19
  # with Crate these terms will supersede the license and you may use the
20
20
  # software solely pursuant to the terms of the relevant commercial agreement.
21
- from datetime import datetime, timedelta, timezone
22
-
23
- from .converter import DataType
24
- import warnings
25
21
  import typing as t
22
+ import warnings
23
+ from datetime import datetime, timedelta, timezone
26
24
 
27
- from .converter import Converter
25
+ from .converter import Converter, DataType
28
26
  from .exceptions import ProgrammingError
29
27
 
30
28
 
31
- class Cursor(object):
29
+ class Cursor:
32
30
  """
33
31
  not thread-safe by intention
34
32
  should not be shared between different threads
35
33
  """
34
+
36
35
  lastrowid = None # currently not supported
37
36
 
38
37
  def __init__(self, connection, converter: Converter, **kwargs):
@@ -40,7 +39,7 @@ class Cursor(object):
40
39
  self.connection = connection
41
40
  self._converter = converter
42
41
  self._closed = False
43
- self._result = None
42
+ self._result: t.Dict[str, t.Any] = {}
44
43
  self.rows = None
45
44
  self._time_zone = None
46
45
  self.time_zone = kwargs.get("time_zone")
@@ -55,8 +54,9 @@ class Cursor(object):
55
54
  if self._closed:
56
55
  raise ProgrammingError("Cursor closed")
57
56
 
58
- self._result = self.connection.client.sql(sql, parameters,
59
- bulk_parameters)
57
+ self._result = self.connection.client.sql(
58
+ sql, parameters, bulk_parameters
59
+ )
60
60
  if "rows" in self._result:
61
61
  if self._converter is None:
62
62
  self.rows = iter(self._result["rows"])
@@ -73,9 +73,9 @@ class Cursor(object):
73
73
  durations = []
74
74
  self.execute(sql, bulk_parameters=seq_of_parameters)
75
75
 
76
- for result in self._result.get('results', []):
77
- if result.get('rowcount') > -1:
78
- row_counts.append(result.get('rowcount'))
76
+ for result in self._result.get("results", []):
77
+ if result.get("rowcount") > -1:
78
+ row_counts.append(result.get("rowcount"))
79
79
  if self.duration > -1:
80
80
  durations.append(self.duration)
81
81
 
@@ -85,7 +85,7 @@ class Cursor(object):
85
85
  "rows": [],
86
86
  "cols": self._result.get("cols", []),
87
87
  "col_types": self._result.get("col_types", []),
88
- "results": self._result.get("results")
88
+ "results": self._result.get("results"),
89
89
  }
90
90
  if self._converter is None:
91
91
  self.rows = iter(self._result["rows"])
@@ -112,7 +112,7 @@ class Cursor(object):
112
112
  This iterator is shared. Advancing this iterator will advance other
113
113
  iterators created from this cursor.
114
114
  """
115
- warnings.warn("DB-API extension cursor.__iter__() used")
115
+ warnings.warn("DB-API extension cursor.__iter__() used", stacklevel=2)
116
116
  return self
117
117
 
118
118
  def fetchmany(self, count=None):
@@ -126,7 +126,7 @@ class Cursor(object):
126
126
  if count == 0:
127
127
  return self.fetchall()
128
128
  result = []
129
- for i in range(count):
129
+ for _ in range(count):
130
130
  try:
131
131
  result.append(self.next())
132
132
  except StopIteration:
@@ -153,7 +153,7 @@ class Cursor(object):
153
153
  Close the cursor now
154
154
  """
155
155
  self._closed = True
156
- self._result = None
156
+ self._result = {}
157
157
 
158
158
  def setinputsizes(self, sizes):
159
159
  """
@@ -174,7 +174,7 @@ class Cursor(object):
174
174
  .execute*() produced (for DQL statements like ``SELECT``) or affected
175
175
  (for DML statements like ``UPDATE`` or ``INSERT``).
176
176
  """
177
- if (self._closed or not self._result or "rows" not in self._result):
177
+ if self._closed or not self._result or "rows" not in self._result:
178
178
  return -1
179
179
  return self._result.get("rowcount", -1)
180
180
 
@@ -185,10 +185,10 @@ class Cursor(object):
185
185
  """
186
186
  if self.rows is None:
187
187
  raise ProgrammingError(
188
- "No result available. " +
189
- "execute() or executemany() must be called first."
188
+ "No result available. "
189
+ + "execute() or executemany() must be called first."
190
190
  )
191
- elif not self._closed:
191
+ if not self._closed:
192
192
  return next(self.rows)
193
193
  else:
194
194
  raise ProgrammingError("Cursor closed")
@@ -201,17 +201,11 @@ class Cursor(object):
201
201
  This read-only attribute is a sequence of 7-item sequences.
202
202
  """
203
203
  if self._closed:
204
- return
204
+ return None
205
205
 
206
206
  description = []
207
207
  for col in self._result["cols"]:
208
- description.append((col,
209
- None,
210
- None,
211
- None,
212
- None,
213
- None,
214
- None))
208
+ description.append((col, None, None, None, None, None, None))
215
209
  return tuple(description)
216
210
 
217
211
  @property
@@ -220,9 +214,7 @@ class Cursor(object):
220
214
  This read-only attribute specifies the server-side duration of a query
221
215
  in milliseconds.
222
216
  """
223
- if self._closed or \
224
- not self._result or \
225
- "duration" not in self._result:
217
+ if self._closed or not self._result or "duration" not in self._result:
226
218
  return -1
227
219
  return self._result.get("duration", 0)
228
220
 
@@ -230,22 +222,21 @@ class Cursor(object):
230
222
  """
231
223
  Iterate rows, apply type converters, and generate converted rows.
232
224
  """
233
- assert "col_types" in self._result and self._result["col_types"], \
234
- "Unable to apply type conversion without `col_types` information"
225
+ if not ("col_types" in self._result and self._result["col_types"]):
226
+ raise ValueError(
227
+ "Unable to apply type conversion "
228
+ "without `col_types` information"
229
+ )
235
230
 
236
- # Resolve `col_types` definition to converter functions. Running the lookup
237
- # redundantly on each row loop iteration would be a huge performance hog.
231
+ # Resolve `col_types` definition to converter functions. Running
232
+ # the lookup redundantly on each row loop iteration would be a
233
+ # huge performance hog.
238
234
  types = self._result["col_types"]
239
- converters = [
240
- self._converter.get(type) for type in types
241
- ]
235
+ converters = [self._converter.get(type_) for type_ in types]
242
236
 
243
237
  # Process result rows with conversion.
244
238
  for row in self._result["rows"]:
245
- yield [
246
- convert(value)
247
- for convert, value in zip(converters, row)
248
- ]
239
+ yield [convert(value) for convert, value in zip(converters, row)]
249
240
 
250
241
  @property
251
242
  def time_zone(self):
@@ -267,11 +258,15 @@ class Cursor(object):
267
258
  - ``zoneinfo.ZoneInfo("Australia/Sydney")``
268
259
  - ``+0530`` (UTC offset in string format)
269
260
 
261
+ The driver always returns timezone-"aware" `datetime` objects,
262
+ with their `tzinfo` attribute set.
263
+
270
264
  When `time_zone` is `None`, the returned `datetime` objects are
271
- "naive", without any `tzinfo`, converted using ``datetime.utcfromtimestamp(...)``.
265
+ using Coordinated Universal Time (UTC), because CrateDB is storing
266
+ timestamp values in this format.
272
267
 
273
- When `time_zone` is given, the returned `datetime` objects are "aware",
274
- with `tzinfo` set, converted using ``datetime.fromtimestamp(..., tz=...)``.
268
+ When `time_zone` is given, the timestamp values will be transparently
269
+ converted from UTC to use the given time zone.
275
270
  """
276
271
 
277
272
  # Do nothing when time zone is reset.
@@ -279,18 +274,22 @@ class Cursor(object):
279
274
  self._time_zone = None
280
275
  return
281
276
 
282
- # Requesting datetime-aware `datetime` objects needs the data type converter.
277
+ # Requesting datetime-aware `datetime` objects
278
+ # needs the data type converter.
283
279
  # Implicitly create one, when needed.
284
280
  if self._converter is None:
285
281
  self._converter = Converter()
286
282
 
287
- # When the time zone is given as a string, assume UTC offset format, e.g. `+0530`.
283
+ # When the time zone is given as a string,
284
+ # assume UTC offset format, e.g. `+0530`.
288
285
  if isinstance(tz, str):
289
286
  tz = self._timezone_from_utc_offset(tz)
290
287
 
291
288
  self._time_zone = tz
292
289
 
293
- def _to_datetime_with_tz(value: t.Optional[float]) -> t.Optional[datetime]:
290
+ def _to_datetime_with_tz(
291
+ value: t.Optional[float],
292
+ ) -> t.Optional[datetime]:
294
293
  """
295
294
  Convert CrateDB's `TIMESTAMP` value to a native Python `datetime`
296
295
  object, with timezone-awareness.
@@ -306,12 +305,17 @@ class Cursor(object):
306
305
  @staticmethod
307
306
  def _timezone_from_utc_offset(tz) -> timezone:
308
307
  """
309
- Convert UTC offset in string format (e.g. `+0530`) into `datetime.timezone` object.
308
+ UTC offset in string format (e.g. `+0530`) to `datetime.timezone`.
310
309
  """
311
- assert len(tz) == 5, f"Time zone '{tz}' is given in invalid UTC offset format"
310
+ if len(tz) != 5:
311
+ raise ValueError(
312
+ f"Time zone '{tz}' is given in invalid UTC offset format"
313
+ )
312
314
  try:
313
315
  hours = int(tz[:3])
314
316
  minutes = int(tz[0] + tz[3:])
315
317
  return timezone(timedelta(hours=hours, minutes=minutes), name=tz)
316
318
  except Exception as ex:
317
- raise ValueError(f"Time zone '{tz}' is given in invalid UTC offset format: {ex}")
319
+ raise ValueError(
320
+ f"Time zone '{tz}' is given in invalid UTC offset format: {ex}"
321
+ ) from ex
@@ -21,7 +21,6 @@
21
21
 
22
22
 
23
23
  class Error(Exception):
24
-
25
24
  def __init__(self, msg=None, error_trace=None):
26
25
  # for compatibility reasons we want to keep the exception message
27
26
  # attribute because clients may depend on it
@@ -36,7 +35,8 @@ class Error(Exception):
36
35
  return "\n".join([super().__str__(), str(self.error_trace)])
37
36
 
38
37
 
39
- class Warning(Exception):
38
+ # A001 Variable `Warning` is shadowing a Python builtin
39
+ class Warning(Exception): # noqa: A001
40
40
  pass
41
41
 
42
42
 
@@ -74,7 +74,9 @@ class NotSupportedError(DatabaseError):
74
74
 
75
75
  # exceptions not in db api
76
76
 
77
- class ConnectionError(OperationalError):
77
+
78
+ # A001 Variable `ConnectionError` is shadowing a Python builtin
79
+ class ConnectionError(OperationalError): # noqa: A001
78
80
  pass
79
81
 
80
82