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