clickhouse-driver 0.2.8__cp312-cp312-win32.whl → 0.2.9__cp312-cp312-win32.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.
@@ -3,7 +3,7 @@ from .client import Client
3
3
  from .dbapi import connect
4
4
 
5
5
 
6
- VERSION = (0, 2, 8)
6
+ VERSION = (0, 2, 9)
7
7
  __version__ = '.'.join(str(x) for x in VERSION)
8
8
 
9
9
  __all__ = ['Client', 'connect']
@@ -1,10 +1,9 @@
1
1
  import re
2
- import ssl
3
2
  from collections import deque
4
3
  from contextlib import contextmanager
5
4
  from time import time
6
5
  import types
7
- from urllib.parse import urlparse, parse_qs, unquote
6
+ from urllib.parse import urlparse
8
7
 
9
8
  from . import errors, defines
10
9
  from .block import ColumnOrientedBlock, RowOrientedBlock
@@ -15,7 +14,7 @@ from .result import (
15
14
  IterQueryResult, ProgressQueryResult, QueryResult, QueryInfo
16
15
  )
17
16
  from .util.escape import escape_params
18
- from .util.helpers import column_chunks, chunks, asbool
17
+ from .util.helpers import column_chunks, chunks, parse_url
19
18
 
20
19
 
21
20
  class Client(object):
@@ -312,6 +311,7 @@ class Client(object):
312
311
  def disconnect_on_error(self, query, settings):
313
312
  try:
314
313
  self.establish_connection(settings)
314
+ self.connection.server_info.session_timezone = None
315
315
 
316
316
  yield
317
317
 
@@ -746,9 +746,13 @@ class Client(object):
746
746
  elif packet.type == ServerPacketTypes.EXCEPTION:
747
747
  raise packet.exception
748
748
 
749
+ elif packet.type == ServerPacketTypes.TIMEZONE_UPDATE:
750
+ pass
751
+
749
752
  else:
750
753
  message = self.connection.unexpected_packet_message(
751
- 'ProfileEvents, Progress, Log or Exception', packet.type
754
+ 'ProfileEvents, Progress, Log, Exception or '
755
+ 'TimezoneUpdate', packet.type
752
756
  )
753
757
  raise errors.UnexpectedPacketFromServerError(message)
754
758
 
@@ -796,101 +800,13 @@ class Client(object):
796
800
  clickhouses://[user:password]@localhost:9440/default
797
801
 
798
802
  Three URL schemes are supported:
799
- clickhouse:// creates a normal TCP socket connection
800
- clickhouses:// creates a SSL wrapped TCP socket connection
803
+
804
+ * clickhouse:// creates a normal TCP socket connection
805
+ * clickhouses:// creates a SSL wrapped TCP socket connection
801
806
 
802
807
  Any additional querystring arguments will be passed along to
803
808
  the Connection class's initializer.
804
809
  """
805
- url = urlparse(url)
806
-
807
- settings = {}
808
- kwargs = {}
809
-
810
- host = url.hostname
811
-
812
- if url.port is not None:
813
- kwargs['port'] = url.port
814
-
815
- path = url.path.replace('/', '', 1)
816
- if path:
817
- kwargs['database'] = path
818
-
819
- if url.username is not None:
820
- kwargs['user'] = unquote(url.username)
821
-
822
- if url.password is not None:
823
- kwargs['password'] = unquote(url.password)
824
-
825
- if url.scheme == 'clickhouses':
826
- kwargs['secure'] = True
827
-
828
- compression_algs = {'lz4', 'lz4hc', 'zstd'}
829
- timeouts = {
830
- 'connect_timeout',
831
- 'send_receive_timeout',
832
- 'sync_request_timeout'
833
- }
834
-
835
- for name, value in parse_qs(url.query).items():
836
- if not value or not len(value):
837
- continue
838
-
839
- value = value[0]
840
-
841
- if name == 'compression':
842
- value = value.lower()
843
- if value in compression_algs:
844
- kwargs[name] = value
845
- else:
846
- kwargs[name] = asbool(value)
847
-
848
- elif name == 'secure':
849
- kwargs[name] = asbool(value)
850
-
851
- elif name == 'use_numpy':
852
- settings[name] = asbool(value)
853
-
854
- elif name == 'round_robin':
855
- kwargs[name] = asbool(value)
856
-
857
- elif name == 'client_name':
858
- kwargs[name] = value
859
-
860
- elif name in timeouts:
861
- kwargs[name] = float(value)
862
-
863
- elif name == 'compress_block_size':
864
- kwargs[name] = int(value)
865
-
866
- elif name == 'settings_is_important':
867
- kwargs[name] = asbool(value)
868
-
869
- elif name == 'tcp_keepalive':
870
- try:
871
- kwargs[name] = asbool(value)
872
- except ValueError:
873
- parts = value.split(',')
874
- kwargs[name] = (
875
- int(parts[0]), int(parts[1]), int(parts[2])
876
- )
877
- elif name == 'client_revision':
878
- kwargs[name] = int(value)
879
-
880
- # ssl
881
- elif name == 'verify':
882
- kwargs[name] = asbool(value)
883
- elif name == 'ssl_version':
884
- kwargs[name] = getattr(ssl, value)
885
- elif name in ['ca_certs', 'ciphers', 'keyfile', 'certfile',
886
- 'server_hostname']:
887
- kwargs[name] = value
888
- elif name == 'alt_hosts':
889
- kwargs['alt_hosts'] = value
890
- else:
891
- settings[name] = value
892
-
893
- if settings:
894
- kwargs['settings'] = settings
810
+ host, kwargs = parse_url(url)
895
811
 
896
812
  return cls(host, **kwargs)
@@ -193,8 +193,9 @@ def create_datetime_column(spec, column_options):
193
193
  else:
194
194
  if not context.settings.get('use_client_time_zone', False):
195
195
  local_timezone = get_localzone_name_compat()
196
- if local_timezone != context.server_info.timezone:
197
- tz_name = context.server_info.timezone
196
+ remote_timezone = context.server_info.get_timezone()
197
+ if local_timezone != remote_timezone:
198
+ tz_name = remote_timezone
198
199
 
199
200
  if tz_name:
200
201
  timezone = get_timezone(tz_name)
@@ -1,20 +1,24 @@
1
1
  from enum import Enum
2
+ from collections import OrderedDict
2
3
 
3
4
  from .. import errors
4
5
  from .intcolumn import IntColumn
5
6
 
7
+ invalid_names_for_python_enum = frozenset(['mro', ''])
8
+
6
9
 
7
10
  class EnumColumn(IntColumn):
8
11
  py_types = (Enum, int, str)
9
12
 
10
- def __init__(self, enum_cls, **kwargs):
11
- self.enum_cls = enum_cls
13
+ def __init__(self, name_by_value, value_by_name, **kwargs):
14
+ self.name_by_value = name_by_value
15
+ self.value_by_name = value_by_name
12
16
  super(EnumColumn, self).__init__(**kwargs)
13
17
 
14
18
  def before_write_items(self, items, nulls_map=None):
15
19
  null_value = self.null_value
16
-
17
- enum_cls = self.enum_cls
20
+ name_by_value = self.name_by_value
21
+ value_by_name = self.value_by_name
18
22
 
19
23
  for i, item in enumerate(items):
20
24
  if nulls_map and nulls_map[i]:
@@ -26,15 +30,15 @@ class EnumColumn(IntColumn):
26
30
  # Check real enum value
27
31
  try:
28
32
  if isinstance(source_value, str):
29
- items[i] = enum_cls[source_value].value
33
+ items[i] = value_by_name[source_value]
30
34
  else:
31
- items[i] = enum_cls(source_value).value
35
+ items[i] = value_by_name[name_by_value[source_value]]
32
36
  except (ValueError, KeyError):
33
37
  choices = ', '.join(
34
- "'{}' = {}".format(x.name.replace("'", r"\'"), x.value)
35
- for x in enum_cls
38
+ "'{}' = {}".format(name.replace("'", r"\'"), value)
39
+ for name, value in value_by_name.items()
36
40
  )
37
- enum_str = '{}({})'.format(enum_cls.__name__, choices)
41
+ enum_str = '{}({})'.format(self.ch_type, choices)
38
42
 
39
43
  raise errors.LogicalError(
40
44
  "Unknown element '{}' for type {}"
@@ -42,13 +46,13 @@ class EnumColumn(IntColumn):
42
46
  )
43
47
 
44
48
  def after_read_items(self, items, nulls_map=None):
45
- enum_cls = self.enum_cls
49
+ name_by_value = self.name_by_value
46
50
 
47
51
  if nulls_map is None:
48
- return tuple(enum_cls(item).name for item in items)
52
+ return tuple(name_by_value[item] for item in items)
49
53
  else:
50
54
  return tuple(
51
- (None if is_null else enum_cls(items[i]).name)
55
+ (None if is_null else name_by_value[items[i]])
52
56
  for i, is_null in enumerate(nulls_map)
53
57
  )
54
58
 
@@ -73,11 +77,13 @@ def create_enum_column(spec, column_options):
73
77
  params = spec[7:-1]
74
78
  cls = Enum16Column
75
79
 
76
- return cls(Enum(cls.ch_type, _parse_options(params)), **column_options)
80
+ name_by_value, value_by_name = _parse_options(params)
81
+
82
+ return cls(name_by_value, value_by_name, **column_options)
77
83
 
78
84
 
79
85
  def _parse_options(option_string):
80
- options = dict()
86
+ name_by_value, value_by_name = {}, OrderedDict()
81
87
  after_name = False
82
88
  escaped = False
83
89
  quote_character = None
@@ -93,7 +99,9 @@ def _parse_options(option_string):
93
99
  if ch in (' ', '='):
94
100
  pass
95
101
  elif ch == ',':
96
- options[name] = int(value)
102
+ value = int(value)
103
+ name_by_value[value] = name
104
+ value_by_name[name] = value
97
105
  after_name = False
98
106
  name = ''
99
107
  value = '' # reset before collecting new option
@@ -114,6 +122,8 @@ def _parse_options(option_string):
114
122
  quote_character = ch
115
123
 
116
124
  if after_name:
117
- options.setdefault(name, int(value)) # append word after last comma
125
+ value = int(value)
126
+ name_by_value[value] = name
127
+ value_by_name[name] = value
118
128
 
119
- return options
129
+ return name_by_value, value_by_name
@@ -33,7 +33,9 @@ class NumpyDateTimeColumnBase(NumpyColumn):
33
33
  ts = items
34
34
  else:
35
35
  timezone = self.timezone if self.timezone else self.local_timezone
36
- ts = pd.to_datetime(items).tz_localize(timezone)
36
+ ts = pd.to_datetime(items)
37
+ if not getattr(ts.dtype, 'tz', None):
38
+ ts = ts.tz_localize(timezone)
37
39
 
38
40
  ts = ts.tz_convert('UTC')
39
41
  return ts.tz_localize(None).to_numpy(self.datetime_dtype)
@@ -133,8 +135,9 @@ def create_numpy_datetime_column(spec, column_options):
133
135
  offset_naive = False
134
136
  else:
135
137
  if not context.settings.get('use_client_time_zone', False):
136
- if local_tz_name != context.server_info.timezone:
137
- tz_name = context.server_info.timezone
138
+ remote_timezone = context.server_info.get_timezone()
139
+ if local_tz_name != remote_timezone:
140
+ tz_name = remote_timezone
138
141
 
139
142
  timezone = get_timezone(tz_name) if tz_name else None
140
143
  local_timezone = get_timezone(local_tz_name) if local_tz_name else None
@@ -37,12 +37,13 @@ def get_inner_columns(spec):
37
37
 
38
38
 
39
39
  def get_inner_columns_with_types(spec):
40
+ spec = spec.strip()
40
41
  brackets = 0
41
42
  prev_comma = 0
42
43
  prev_space = 0
43
44
 
44
45
  columns = []
45
- for i, x in enumerate(spec + ','):
46
+ for i, x in enumerate(spec.strip() + ','):
46
47
  if x == ',':
47
48
  if brackets == 0:
48
49
  columns.append((
@@ -53,11 +53,15 @@ class ServerInfo(object):
53
53
  self.version_patch = version_patch
54
54
  self.revision = revision
55
55
  self.timezone = timezone
56
+ self.session_timezone = None
56
57
  self.display_name = display_name
57
58
  self.used_revision = used_revision
58
59
 
59
60
  super(ServerInfo, self).__init__()
60
61
 
62
+ def get_timezone(self):
63
+ return self.session_timezone or self.timezone
64
+
61
65
  def version_tuple(self):
62
66
  return self.version_major, self.version_minor, self.version_patch
63
67
 
@@ -301,15 +305,14 @@ class Connection(object):
301
305
  def _create_ssl_context(self, ssl_options):
302
306
  purpose = ssl.Purpose.SERVER_AUTH
303
307
 
304
- version = ssl_options.get('ssl_version', ssl.PROTOCOL_TLS)
308
+ version = ssl_options.get('ssl_version', ssl.PROTOCOL_TLS_CLIENT)
305
309
  context = ssl.SSLContext(version)
306
310
  context.check_hostname = self.verify_cert
307
311
 
308
312
  if 'ca_certs' in ssl_options:
309
313
  context.load_verify_locations(ssl_options['ca_certs'])
310
314
  elif ssl_options.get('cert_reqs') != ssl.CERT_NONE:
311
- context.load_default_certs(purpose
312
- )
315
+ context.load_default_certs(purpose)
313
316
  if 'ciphers' in ssl_options:
314
317
  context.set_ciphers(ssl_options['ciphers'])
315
318
 
@@ -613,6 +616,12 @@ class Connection(object):
613
616
  elif packet_type == ServerPacketTypes.PROFILE_EVENTS:
614
617
  packet.block = self.receive_data(may_be_compressed=False)
615
618
 
619
+ elif packet_type == ServerPacketTypes.TIMEZONE_UPDATE:
620
+ timezone = read_binary_str(self.fin)
621
+ if timezone:
622
+ logger.info('Server timezone changed to %s', timezone)
623
+ self.server_info.session_timezone = timezone
624
+
616
625
  else:
617
626
  message = 'Unknown packet {} from server {}'.format(
618
627
  packet_type, self.get_description()
@@ -33,6 +33,9 @@ DBMS_MIN_PROTOCOL_VERSION_WITH_PARAMETERS = 54459
33
33
  DBMS_MIN_PROTOCOL_VERSION_WITH_SERVER_QUERY_TIME_IN_PROGRESS = 54460
34
34
  DBMS_MIN_PROTOCOL_VERSION_WITH_PASSWORD_COMPLEXITY_RULES = 54461
35
35
  DBMS_MIN_REVISION_WITH_INTERSERVER_SECRET_V2 = 54462
36
+ DBMS_MIN_PROTOCOL_VERSION_WITH_TOTAL_BYTES_IN_PROGRESS = 54463
37
+ DBMS_MIN_PROTOCOL_VERSION_WITH_TIMEZONE_UPDATES = 54464
38
+ DBMS_MIN_REVISION_WITH_SYSTEM_KEYWORDS_TABLE = 54468
36
39
 
37
40
  # Timeouts
38
41
  DBMS_DEFAULT_CONNECT_TIMEOUT_SEC = 10
@@ -48,7 +51,7 @@ CLIENT_NAME = 'python-driver'
48
51
  CLIENT_VERSION_MAJOR = 20
49
52
  CLIENT_VERSION_MINOR = 10
50
53
  CLIENT_VERSION_PATCH = 2
51
- CLIENT_REVISION = DBMS_MIN_REVISION_WITH_INTERSERVER_SECRET_V2
54
+ CLIENT_REVISION = DBMS_MIN_REVISION_WITH_SYSTEM_KEYWORDS_TABLE
52
55
 
53
56
  BUFFER_SIZE = 1048576
54
57
 
@@ -1,13 +1,16 @@
1
1
  import numpy as np
2
2
  import pandas as pd
3
+ from pandas.core.arrays import ExtensionArray
3
4
 
4
5
 
5
6
  def column_chunks(columns, n):
6
7
  for column in columns:
7
- if not isinstance(column, (np.ndarray, pd.DatetimeIndex)):
8
+ if not isinstance(
9
+ column, (np.ndarray, pd.DatetimeIndex, ExtensionArray)
10
+ ):
8
11
  raise TypeError(
9
12
  'Unsupported column type: {}. '
10
- 'ndarray/DatetimeIndex is expected.'
13
+ 'ndarray/DatetimeIndex/ExtensionArray is expected.'
11
14
  .format(type(column))
12
15
  )
13
16
 
@@ -6,7 +6,8 @@ class Progress(object):
6
6
  def __init__(self):
7
7
  self.rows = 0
8
8
  self.bytes = 0
9
- self.total_rows = 0
9
+ self.total_rows = 0 # total_rows_to_read
10
+ self.total_bytes = 0 # total_bytes_to_read
10
11
  self.written_rows = 0
11
12
  self.written_bytes = 0
12
13
  self.elapsed_ns = 0
@@ -21,6 +22,10 @@ class Progress(object):
21
22
  if revision >= defines.DBMS_MIN_REVISION_WITH_TOTAL_ROWS_IN_PROGRESS:
22
23
  self.total_rows = read_varint(fin)
23
24
 
25
+ if revision >= defines. \
26
+ DBMS_MIN_PROTOCOL_VERSION_WITH_TOTAL_BYTES_IN_PROGRESS:
27
+ self.total_bytes = read_varint(fin)
28
+
24
29
  if revision >= defines.DBMS_MIN_REVISION_WITH_CLIENT_WRITE_INFO:
25
30
  self.written_rows = read_varint(fin)
26
31
  self.written_bytes = read_varint(fin)
@@ -33,6 +38,7 @@ class Progress(object):
33
38
  self.rows += another_progress.rows
34
39
  self.bytes += another_progress.bytes
35
40
  self.total_rows += another_progress.total_rows
41
+ self.total_bytes += another_progress.total_bytes
36
42
  self.written_rows += another_progress.written_rows
37
43
  self.written_bytes += another_progress.written_bytes
38
44
  self.elapsed_ns += another_progress.elapsed_ns
@@ -29,7 +29,10 @@ class ClientPacketTypes(object):
29
29
 
30
30
  @classmethod
31
31
  def to_str(cls, packet):
32
- return 'Unknown packet' if packet > 5 else cls._types_str[packet]
32
+ try:
33
+ return cls._types_str[packet]
34
+ except IndexError:
35
+ return 'Unknown packet'
33
36
 
34
37
 
35
38
  class ServerPacketTypes(object):
@@ -81,15 +84,28 @@ class ServerPacketTypes(object):
81
84
  # Packet with profile events from server.
82
85
  PROFILE_EVENTS = 14
83
86
 
87
+ MERGE_TREE_ALL_RANGES_ANNOUNCEMENT = 15
88
+
89
+ # Request from a MergeTree replica to a coordinator
90
+ MERGE_TREE_READ_TASK_REQUEST = 16
91
+
92
+ # Receive server's (session-wide) default timezone
93
+ TIMEZONE_UPDATE = 17
94
+
84
95
  _types_str = [
85
96
  'Hello', 'Data', 'Exception', 'Progress', 'Pong', 'EndOfStream',
86
97
  'ProfileInfo', 'Totals', 'Extremes', 'TablesStatusResponse', 'Log',
87
- 'TableColumns', 'PartUUIDs', 'ReadTaskRequest', 'ProfileEvents'
98
+ 'TableColumns', 'PartUUIDs', 'ReadTaskRequest', 'ProfileEvents',
99
+ 'MergeTreeAllRangesAnnouncement', 'MergeTreeReadTaskRequest',
100
+ 'TimezoneUpdate'
88
101
  ]
89
102
 
90
103
  @classmethod
91
104
  def to_str(cls, packet):
92
- return 'Unknown packet' if packet > 14 else cls._types_str[packet]
105
+ try:
106
+ return cls._types_str[packet]
107
+ except IndexError:
108
+ return 'Unknown packet'
93
109
 
94
110
  @classmethod
95
111
  def strings_in_message(cls, packet):
@@ -1,3 +1,5 @@
1
+ import logging
2
+
1
3
  from ..block import ColumnOrientedBlock, BlockInfo
2
4
  from ..columns.service import read_column, write_column
3
5
  from ..reader import read_binary_str, read_binary_uint8
@@ -5,6 +7,8 @@ from ..varint import write_varint, read_varint
5
7
  from ..writer import write_binary_str, write_binary_uint8
6
8
  from .. import defines
7
9
 
10
+ logger = logging.getLogger(__name__)
11
+
8
12
 
9
13
  class BlockOutputStream(object):
10
14
  def __init__(self, fout, context):
@@ -40,6 +44,7 @@ class BlockOutputStream(object):
40
44
  # We write always sparse data without custom serialization.
41
45
  write_binary_uint8(0, self.fout)
42
46
 
47
+ logger.debug('Writing column %s', col_name)
43
48
  write_column(self.context, col_name, col_type, items,
44
49
  self.fout, types_check=block.types_check)
45
50
 
@@ -80,6 +85,7 @@ class BlockInputStream(object):
80
85
  has_custom_serialization = bool(read_binary_uint8(self.fin))
81
86
 
82
87
  if n_rows:
88
+ logger.debug('Reading column %s', column_name)
83
89
  column = read_column(
84
90
  self.context, column_type, n_rows,
85
91
  self.fin, use_numpy=use_numpy,
@@ -21,7 +21,7 @@ escape_chars_map = {
21
21
 
22
22
 
23
23
  def escape_datetime(item, context):
24
- server_tz = timezone(context.server_info.timezone)
24
+ server_tz = timezone(context.server_info.get_timezone())
25
25
 
26
26
  if item.tzinfo is not None:
27
27
  item = item.astimezone(server_tz)
@@ -1,4 +1,6 @@
1
+ import ssl
1
2
  from itertools import islice, tee
3
+ from urllib.parse import urlparse, parse_qs, unquote
2
4
 
3
5
 
4
6
  def chunks(seq, n):
@@ -55,3 +57,115 @@ def asbool(obj):
55
57
  else:
56
58
  raise ValueError('String is not true/false: %r' % obj)
57
59
  return bool(obj)
60
+
61
+
62
+ def parse_url(url):
63
+ """
64
+ Parses url into host and kwargs suitable for further Client construction.
65
+ Return host and kwargs.
66
+
67
+ For example::
68
+
69
+ clickhouse://[user:password]@localhost:9000/default
70
+ clickhouses://[user:password]@localhost:9440/default
71
+
72
+ Three URL schemes are supported:
73
+
74
+ * clickhouse:// creates a normal TCP socket connection
75
+ * clickhouses:// creates a SSL wrapped TCP socket connection
76
+
77
+ Any additional querystring arguments will be passed along to
78
+ the Connection class's initializer.
79
+ """
80
+ url = urlparse(url)
81
+
82
+ settings = {}
83
+ kwargs = {}
84
+
85
+ host = url.hostname
86
+
87
+ if url.port is not None:
88
+ kwargs['port'] = url.port
89
+
90
+ path = url.path.replace('/', '', 1)
91
+ if path:
92
+ kwargs['database'] = path
93
+
94
+ if url.username is not None:
95
+ kwargs['user'] = unquote(url.username)
96
+
97
+ if url.password is not None:
98
+ kwargs['password'] = unquote(url.password)
99
+
100
+ if url.scheme == 'clickhouses':
101
+ kwargs['secure'] = True
102
+
103
+ compression_algs = {'lz4', 'lz4hc', 'zstd'}
104
+ timeouts = {
105
+ 'connect_timeout',
106
+ 'send_receive_timeout',
107
+ 'sync_request_timeout'
108
+ }
109
+
110
+ for name, value in parse_qs(url.query).items():
111
+ if not value or not len(value):
112
+ continue
113
+
114
+ value = value[0]
115
+
116
+ if name == 'compression':
117
+ value = value.lower()
118
+ if value in compression_algs:
119
+ kwargs[name] = value
120
+ else:
121
+ kwargs[name] = asbool(value)
122
+
123
+ elif name == 'secure':
124
+ kwargs[name] = asbool(value)
125
+
126
+ elif name == 'use_numpy':
127
+ settings[name] = asbool(value)
128
+
129
+ elif name == 'round_robin':
130
+ kwargs[name] = asbool(value)
131
+
132
+ elif name == 'client_name':
133
+ kwargs[name] = value
134
+
135
+ elif name in timeouts:
136
+ kwargs[name] = float(value)
137
+
138
+ elif name == 'compress_block_size':
139
+ kwargs[name] = int(value)
140
+
141
+ elif name == 'settings_is_important':
142
+ kwargs[name] = asbool(value)
143
+
144
+ elif name == 'tcp_keepalive':
145
+ try:
146
+ kwargs[name] = asbool(value)
147
+ except ValueError:
148
+ parts = value.split(',')
149
+ kwargs[name] = (
150
+ int(parts[0]), int(parts[1]), int(parts[2])
151
+ )
152
+ elif name == 'client_revision':
153
+ kwargs[name] = int(value)
154
+
155
+ # ssl
156
+ elif name == 'verify':
157
+ kwargs[name] = asbool(value)
158
+ elif name == 'ssl_version':
159
+ kwargs[name] = getattr(ssl, value)
160
+ elif name in ['ca_certs', 'ciphers', 'keyfile', 'certfile',
161
+ 'server_hostname']:
162
+ kwargs[name] = value
163
+ elif name == 'alt_hosts':
164
+ kwargs['alt_hosts'] = value
165
+ else:
166
+ settings[name] = value
167
+
168
+ if settings:
169
+ kwargs['settings'] = settings
170
+
171
+ return host, kwargs
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: clickhouse-driver
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: Python driver with native interface for ClickHouse
5
5
  Home-page: https://github.com/mymarilyn/clickhouse-driver
6
6
  Author: Konstantin Lebedev
@@ -22,6 +22,7 @@ Classifier: Programming Language :: Python :: 3.8
22
22
  Classifier: Programming Language :: Python :: 3.9
23
23
  Classifier: Programming Language :: Python :: 3.10
24
24
  Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
25
26
  Classifier: Programming Language :: Python :: Implementation :: PyPy
26
27
  Classifier: Topic :: Database
27
28
  Classifier: Topic :: Software Development
@@ -1,39 +1,39 @@
1
- clickhouse_driver/__init__.py,sha256=OmAov0f6GIBaEKyG5T6rvrDLSL4q1Ysnetjt3iEsMZg,158
1
+ clickhouse_driver/__init__.py,sha256=RK_d8W2wu-969SgQpS3ggN249KbViz6uDBaJLbCYsp4,158
2
2
  clickhouse_driver/block.py,sha256=t2zZhtCzwp4aJj0CuDqXlDEgHXgwc6GRsIks2aaIZvI,6311
3
3
  clickhouse_driver/blockstreamprofileinfo.py,sha256=nYx9QXWAS8aPiRbtAzwLRT5JIlJ8S103JMkudncwpFg,712
4
- clickhouse_driver/bufferedreader.cp312-win32.pyd,sha256=RmJgKsXzvPwUlflnuPi7rJwsgPzZp3nZ50cRszfywrA,87552
5
- clickhouse_driver/bufferedwriter.cp312-win32.pyd,sha256=juFtqHO9FHQV8yA-jagPjZAy0Mjer9YhbujE0H2R8Es,86528
6
- clickhouse_driver/client.py,sha256=aMjWyS98BqonoEuZxNC_q4DdUjBf8vADLAAcrkJPmKA,34703
4
+ clickhouse_driver/bufferedreader.cp312-win32.pyd,sha256=SIMn9Yz0a_YWctgErzZ86CPdp_otOTRxPid2Apv3Kwg,87552
5
+ clickhouse_driver/bufferedwriter.cp312-win32.pyd,sha256=paIWJVUOTALQG5ekGiVGe29sWlK4n30S-qNvvTm8nCs,86528
6
+ clickhouse_driver/client.py,sha256=iYSz2DLQC-t6RLmtWJvtHoEWBAFtKDIafl874tz2ebs,32251
7
7
  clickhouse_driver/clientinfo.py,sha256=Tw3NbuDHglT6_f0AcT0IdhqW_hVePtzh9pypx5nk5ZE,4260
8
- clickhouse_driver/connection.py,sha256=Ol9ZljjN63P840yrUlWPl5g9lRldh9XTD5fVOiloYi8,28403
8
+ clickhouse_driver/connection.py,sha256=RYS-s3jjlfloFNeth6Vy7N3g6E-W5dXM1MGJ9F6H1cU,28760
9
9
  clickhouse_driver/context.py,sha256=yPkJ_BN4LGODvKCOjNlDGqABwxAMQTQl7w1vIGRPBDg,909
10
- clickhouse_driver/defines.py,sha256=hXIR10BvH_sxUN35pk-f-VeIbM7CA0Ll2B2yNuAy10A,1958
10
+ clickhouse_driver/defines.py,sha256=EwrQz7sNNUmGZmZywQFpDpBFc67nB9GAZOBQEvvUJzA,2130
11
11
  clickhouse_driver/errors.py,sha256=mffBg-Y2LFOSRzvE9V34RwFcvmfh67yqLeEBhrdjeXE,14343
12
12
  clickhouse_driver/log.py,sha256=P9VS_YDY3a4JQsNOeUNNK0L1AAallTC1GF4FG5gCrac,1091
13
13
  clickhouse_driver/opentelemetry.py,sha256=GIzHCxdB8LB1ozXtUjIpxsdznmRABAts64G2u2l4C_A,1622
14
- clickhouse_driver/progress.py,sha256=MagDPiLzWG-2Arecu5O6JlK98242ayt9yPa9H7v9o5k,1288
15
- clickhouse_driver/protocol.py,sha256=ZRJuawN_v8wXFrHrcpSiBqu7idKsPd3tQnCcDuTlIw8,2561
14
+ clickhouse_driver/progress.py,sha256=mom2NRLg8dfE_ObOEthKqjSBIliBvDjt7joePvY_Fdw,1574
15
+ clickhouse_driver/protocol.py,sha256=BxCJiZLH0QkFmdNwog1OJm9MEMwdPZ1i5Jv1_NHcLb0,2965
16
16
  clickhouse_driver/queryprocessingstage.py,sha256=lbV-bB5jWUp0hqYBTsUcRYkJhCgCTfN2G21AykMoAp0,186
17
17
  clickhouse_driver/reader.py,sha256=PWKOKwjszu0sJbG-dd_TyGn8tQAzxg2gCJVbz27G3-8,1322
18
18
  clickhouse_driver/readhelpers.py,sha256=tXOmSL9GSeHLdKE2yBlk0epfy-hGJ3bTOLq3Q6sXIkw,717
19
19
  clickhouse_driver/result.py,sha256=RpjBUvRQJ70xISye7u6gxgQBJwc2UkNuusLkaZF7SmM,4098
20
- clickhouse_driver/varint.cp312-win32.pyd,sha256=fjZmM5lZyqpvBZ4XLNG9hMYo5CXFqIHDG6tlI1vrUmU,34304
20
+ clickhouse_driver/varint.cp312-win32.pyd,sha256=io2cDLCdozT3uarNE8hRKu4fRCCt_dsfZT65bi5VJdQ,34304
21
21
  clickhouse_driver/writer.py,sha256=yf5f1vTr56YFtL-Swpi_jBsPw5bQS56j53joB0Acdyk,1286
22
22
  clickhouse_driver/columns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  clickhouse_driver/columns/arraycolumn.py,sha256=UiA48jw3o4-ert8BnzEbl2h1jVmtDH3jtcP1BTPru2w,5322
24
24
  clickhouse_driver/columns/base.py,sha256=jRThD8Ol7gwNy3x0M7vvslkm0RDOsCLJqKGf0arsa0w,6504
25
25
  clickhouse_driver/columns/boolcolumn.py,sha256=QgVCqbZWoFD1yvpppc92iiXIzReCVEh692efNSNH4UE,127
26
26
  clickhouse_driver/columns/datecolumn.py,sha256=FT6qzmniFGKw5SpjFITiBf-fJGEwaoUIz7PMZMFxe8M,3209
27
- clickhouse_driver/columns/datetimecolumn.py,sha256=pO8g1exACp6EfUO0prra5X3T_gg1MJ8bSoi5Rt2Vxjg,6691
27
+ clickhouse_driver/columns/datetimecolumn.py,sha256=RWucoNtcc4wUGQ6xPL0cTNmxFy8eQ50ZdHzexXBm3XE,6730
28
28
  clickhouse_driver/columns/decimalcolumn.py,sha256=MBczjN6AtI0jgbVTNguwVE7ZdWql0XuMl-QohxV-sN0,3450
29
- clickhouse_driver/columns/enumcolumn.py,sha256=GCSW-fjtJC4_5YKo9oKtG8GT9UhLcRWCjrBVhEAUp-A,3219
29
+ clickhouse_driver/columns/enumcolumn.py,sha256=zqZkSVVXfWsaPUbP59ayy7w8rG4otS9J51UPD29zs2Y,3674
30
30
  clickhouse_driver/columns/exceptions.py,sha256=vrZMZ9ORRP7RSSd34azM_xFaeMaaYbwy6h6ZCeFNbIg,163
31
31
  clickhouse_driver/columns/floatcolumn.py,sha256=Mci7Fl05dgkpDQRfjGaDP9QraZER5nkYX1lVsTA89Yk,925
32
32
  clickhouse_driver/columns/intcolumn.py,sha256=ntpxyMiu44VQYJ0HyHlglwxMgUtnIgf3JE9LUD9Xwwc,3519
33
33
  clickhouse_driver/columns/intervalcolumn.py,sha256=oQeybb4qrcp07LeVYfqgeZuHYGH5RaY7KnWVoIsDe1I,600
34
34
  clickhouse_driver/columns/ipcolumn.py,sha256=LIt-NiUy70-8u5Amu0v0tlAlrolZ8gXzlFxcJYmjRAk,4095
35
35
  clickhouse_driver/columns/jsoncolumn.py,sha256=SeCLSrmRoEg9wlvoehs7-EmrV8XkOL3lknzeOORhbJg,1175
36
- clickhouse_driver/columns/largeint.cp312-win32.pyd,sha256=WPxFFDlRVb3H0tP5j19djieoXjvQNBmxR_mlz0CrNII,56320
36
+ clickhouse_driver/columns/largeint.cp312-win32.pyd,sha256=BNlZzUPy6LEYQX7Q9SuqKZBxojnM9E56jMxTU1zLag8,56320
37
37
  clickhouse_driver/columns/lowcardinalitycolumn.py,sha256=vMlhYYUPNmFhQiUAS77pE25KjI8TrO6ySz6w0ByBdZQ,4920
38
38
  clickhouse_driver/columns/mapcolumn.py,sha256=gX7xvwsilfOHDCwmRJu4fW2Y1OrN_1cgZTmbvcyer30,2133
39
39
  clickhouse_driver/columns/nestedcolumn.py,sha256=7x3xNYR22kEmgV4_3rPVZea2zCTU364O1tlOewMgw3M,303
@@ -44,13 +44,13 @@ clickhouse_driver/columns/service.py,sha256=6nIGwvcG-5LErQFn_3a2GRKZI2OnKYsy2oII
44
44
  clickhouse_driver/columns/simpleaggregatefunctioncolumn.py,sha256=zDWBd_Hc7AktHFZ5JY7SwxIk7G4WBHdJdcPBqihe7q0,235
45
45
  clickhouse_driver/columns/stringcolumn.py,sha256=C-l7HaReg9AcJGQvgpSH07aV-CZMBP1jKArPHZi8Q2k,2059
46
46
  clickhouse_driver/columns/tuplecolumn.py,sha256=DnwtEwVXzm-YyL5-cPe9MiOLOoTEcDhcYeBY6SuuZZQ,2040
47
- clickhouse_driver/columns/util.py,sha256=5DRGBsWSTldqZRZJ53J85zh_jepkwkAsYXhAeDJQW4I,1395
47
+ clickhouse_driver/columns/util.py,sha256=3q965GjEmKkTmjIva31PhvAEGfuuGulad1amK7kQBEQ,1427
48
48
  clickhouse_driver/columns/uuidcolumn.py,sha256=7CLPxsHJtV6Zt9jxILSkE0LAwffloLmrjjbwCZH34mA,1865
49
49
  clickhouse_driver/columns/numpy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  clickhouse_driver/columns/numpy/base.py,sha256=Wk1ADpoQGWQv5X8sWi0esA2jmQGEoDakXZxImuYM2eM,1410
51
51
  clickhouse_driver/columns/numpy/boolcolumn.py,sha256=0_RwEroY2-ZqMuxKeTNG27ZCWN_y9BxYZzbuFKeqoQg,140
52
52
  clickhouse_driver/columns/numpy/datecolumn.py,sha256=xWFsFwiRmszK9A20UWnF4beTE5f8XQDj18x53xtXtSI,482
53
- clickhouse_driver/columns/numpy/datetimecolumn.py,sha256=XQ3JsxVdAvWJndNek4-i07JO2QJIdUnJQWzOxvF3PMc,4777
53
+ clickhouse_driver/columns/numpy/datetimecolumn.py,sha256=X6XgslCvWOF3dtVP3ogDQ4WLWhQqAkAdw5qAIuE8f1o,4890
54
54
  clickhouse_driver/columns/numpy/floatcolumn.py,sha256=WnnlyR3vabh6ixllXwdyQ_t8y5MSqCddImWityxz6pE,599
55
55
  clickhouse_driver/columns/numpy/intcolumn.py,sha256=ZzmjvjpEaZ_kk-mGEPdBAqUCjqCgGT8tUEzbQKwUVVA,792
56
56
  clickhouse_driver/columns/numpy/lowcardinalitycolumn.py,sha256=ExYtwBBn6WfSQtWC0f79ZqjdqO3ZJ3IL6KtlQOgMh-k,3368
@@ -69,7 +69,7 @@ clickhouse_driver/dbapi/errors.py,sha256=yv2SDIK-ZlWmIxBoF5_igfHRyh9zTUJSgAj9g8S
69
69
  clickhouse_driver/dbapi/extras.py,sha256=je1tjk6gb-QqLMoWu_iXCqhJK159vyyHsCB_8vXkXyw,2129
70
70
  clickhouse_driver/numpy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
71
  clickhouse_driver/numpy/block.py,sha256=k8CqQxaVSviZvicS03exPZG_LFwbzB5-NnLB2EuBKgQ,180
72
- clickhouse_driver/numpy/helpers.py,sha256=jKiZ3GOp1G5Q2Y-6S_YG9t9RtdSLa-AH1grz71OWyS0,704
72
+ clickhouse_driver/numpy/helpers.py,sha256=cwRvBX4a-o-QdccYIxFT3p8DPUaXqyXWsVNTSiG8Cdw,803
73
73
  clickhouse_driver/numpy/result.py,sha256=D-7IsaIt0u4WJ8iSzXYBB0OiPgPu5ptu-1HiJvTW-No,3563
74
74
  clickhouse_driver/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
75
  clickhouse_driver/settings/available.py,sha256=8b1YUjt-_6gO9Cio02VZSMPdhM70zk-NMhE4f_jwFx8,16613
@@ -77,13 +77,13 @@ clickhouse_driver/settings/types.py,sha256=u_A3FzREqIjj4OSEdKUwm1Xn8jEnGpp-9Avqb
77
77
  clickhouse_driver/settings/writer.py,sha256=x0FVdbKZR9lN-hXAT2xxkoqvGo1ojvWWwyP3NaI7ZDA,1099
78
78
  clickhouse_driver/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
79
  clickhouse_driver/streams/compressed.py,sha256=eyFCuq_sLX6oJLQ_h1QX3IB9IgUx56pPqPfhmeiA6ag,2865
80
- clickhouse_driver/streams/native.py,sha256=2qAs5deUU4NwLG3zQAyxNwGsKmJO41-qlTRKGRFSAJA,3316
80
+ clickhouse_driver/streams/native.py,sha256=lIJFxLRFrh2zqRAvf8W2JPmXdGtJu3LPDUkfaBrLAfk,3493
81
81
  clickhouse_driver/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
82
  clickhouse_driver/util/compat.py,sha256=wIB_6ULSapKx-Fi64lZ0YJ-TtWOQXePHE90wZopIM1I,876
83
- clickhouse_driver/util/escape.py,sha256=4RPfNzC5IvatoZB9llmJM4436XArCXQDEqT_cqdwCBk,2256
84
- clickhouse_driver/util/helpers.py,sha256=1oLkkkILXZnEbdjAe2Ags-Y-T-Bq9rk94W6edh-1ZLU,1448
85
- clickhouse_driver-0.2.8.dist-info/LICENSE,sha256=b2SjNa4zGQk6XzJwmeE1dQjjtWRvX_zxJIAl_ZbN_S8,1143
86
- clickhouse_driver-0.2.8.dist-info/METADATA,sha256=nmFh97sS6TF5P2tzzmvKfO-HUNGxXWzyrFwC4D6OkuU,6290
87
- clickhouse_driver-0.2.8.dist-info/WHEEL,sha256=4N7jptPh4OYjkcvBzbL_SyiQfKWhgnHPSC8E7zx3zFw,98
88
- clickhouse_driver-0.2.8.dist-info/top_level.txt,sha256=PrE0Lrs4d-gRQwzABaABfym9Qvr4nN6uTrDy6Q7zQME,18
89
- clickhouse_driver-0.2.8.dist-info/RECORD,,
83
+ clickhouse_driver/util/escape.py,sha256=vL8sY6XdHhjFwtHn8yQ3JbeZfocWt6jyvxFf-nEiRtM,2262
84
+ clickhouse_driver/util/helpers.py,sha256=AIKa7UPCiNMjGaMwFjn_n1PTij20PCYtA-YMePBKQFY,4483
85
+ clickhouse_driver-0.2.9.dist-info/LICENSE,sha256=b2SjNa4zGQk6XzJwmeE1dQjjtWRvX_zxJIAl_ZbN_S8,1143
86
+ clickhouse_driver-0.2.9.dist-info/METADATA,sha256=O7fUc77cROATgATo5BxkO01nhZH1Akh9uoOqOlADWcw,6342
87
+ clickhouse_driver-0.2.9.dist-info/WHEEL,sha256=4N7jptPh4OYjkcvBzbL_SyiQfKWhgnHPSC8E7zx3zFw,98
88
+ clickhouse_driver-0.2.9.dist-info/top_level.txt,sha256=PrE0Lrs4d-gRQwzABaABfym9Qvr4nN6uTrDy6Q7zQME,18
89
+ clickhouse_driver-0.2.9.dist-info/RECORD,,