clickhouse-driver 0.2.5__cp311-cp311-musllinux_1_1_aarch64.whl → 0.2.9__cp311-cp311-musllinux_1_1_aarch64.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.
- clickhouse_driver/__init__.py +1 -1
- clickhouse_driver/block.py +3 -2
- clickhouse_driver/bufferedreader.cpython-311-aarch64-linux-musl.so +0 -0
- clickhouse_driver/bufferedwriter.cpython-311-aarch64-linux-musl.so +0 -0
- clickhouse_driver/client.py +119 -99
- clickhouse_driver/clientinfo.py +2 -2
- clickhouse_driver/columns/arraycolumn.py +15 -6
- clickhouse_driver/columns/base.py +71 -7
- clickhouse_driver/columns/datecolumn.py +52 -13
- clickhouse_driver/columns/datetimecolumn.py +3 -2
- clickhouse_driver/columns/enumcolumn.py +27 -17
- clickhouse_driver/columns/jsoncolumn.py +37 -0
- clickhouse_driver/columns/largeint.cpython-311-aarch64-linux-musl.so +0 -0
- clickhouse_driver/columns/lowcardinalitycolumn.py +23 -4
- clickhouse_driver/columns/mapcolumn.py +9 -2
- clickhouse_driver/columns/nestedcolumn.py +2 -13
- clickhouse_driver/columns/numpy/datetimecolumn.py +21 -18
- clickhouse_driver/columns/numpy/lowcardinalitycolumn.py +2 -2
- clickhouse_driver/columns/service.py +12 -2
- clickhouse_driver/columns/tuplecolumn.py +31 -5
- clickhouse_driver/columns/util.py +2 -1
- clickhouse_driver/columns/uuidcolumn.py +1 -1
- clickhouse_driver/connection.py +117 -19
- clickhouse_driver/defines.py +12 -1
- clickhouse_driver/log.py +7 -3
- clickhouse_driver/numpy/helpers.py +5 -2
- clickhouse_driver/progress.py +15 -3
- clickhouse_driver/protocol.py +19 -3
- clickhouse_driver/settings/writer.py +7 -2
- clickhouse_driver/streams/native.py +24 -6
- clickhouse_driver/util/compat.py +12 -0
- clickhouse_driver/util/escape.py +36 -8
- clickhouse_driver/util/helpers.py +114 -0
- clickhouse_driver/varint.cpython-311-aarch64-linux-musl.so +0 -0
- {clickhouse_driver-0.2.5.dist-info → clickhouse_driver-0.2.9.dist-info}/METADATA +8 -8
- {clickhouse_driver-0.2.5.dist-info → clickhouse_driver-0.2.9.dist-info}/RECORD +71 -70
- {clickhouse_driver-0.2.5.dist-info → clickhouse_driver-0.2.9.dist-info}/WHEEL +1 -1
- {clickhouse_driver-0.2.5.dist-info → clickhouse_driver-0.2.9.dist-info}/LICENSE +0 -0
- {clickhouse_driver-0.2.5.dist-info → clickhouse_driver-0.2.9.dist-info}/top_level.txt +0 -0
|
@@ -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,
|
|
11
|
-
self.
|
|
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
|
-
|
|
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] =
|
|
33
|
+
items[i] = value_by_name[source_value]
|
|
30
34
|
else:
|
|
31
|
-
items[i] =
|
|
35
|
+
items[i] = value_by_name[name_by_value[source_value]]
|
|
32
36
|
except (ValueError, KeyError):
|
|
33
37
|
choices = ', '.join(
|
|
34
|
-
"'{}' = {}".format(
|
|
35
|
-
for
|
|
38
|
+
"'{}' = {}".format(name.replace("'", r"\'"), value)
|
|
39
|
+
for name, value in value_by_name.items()
|
|
36
40
|
)
|
|
37
|
-
enum_str = '{}({})'.format(
|
|
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
|
-
|
|
49
|
+
name_by_value = self.name_by_value
|
|
46
50
|
|
|
47
51
|
if nulls_map is None:
|
|
48
|
-
return tuple(
|
|
52
|
+
return tuple(name_by_value[item] for item in items)
|
|
49
53
|
else:
|
|
50
54
|
return tuple(
|
|
51
|
-
(None if is_null else
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
125
|
+
value = int(value)
|
|
126
|
+
name_by_value[value] = name
|
|
127
|
+
value_by_name[name] = value
|
|
118
128
|
|
|
119
|
-
return
|
|
129
|
+
return name_by_value, value_by_name
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from .base import Column
|
|
2
|
+
from .stringcolumn import String
|
|
3
|
+
from ..reader import read_binary_uint8, read_binary_str
|
|
4
|
+
from ..util.compat import json
|
|
5
|
+
from ..writer import write_binary_uint8
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class JsonColumn(Column):
|
|
9
|
+
py_types = (dict, )
|
|
10
|
+
|
|
11
|
+
# No NULL value actually
|
|
12
|
+
null_value = {}
|
|
13
|
+
|
|
14
|
+
def __init__(self, column_by_spec_getter, **kwargs):
|
|
15
|
+
self.column_by_spec_getter = column_by_spec_getter
|
|
16
|
+
self.string_column = String(**kwargs)
|
|
17
|
+
super(JsonColumn, self).__init__(**kwargs)
|
|
18
|
+
|
|
19
|
+
def write_state_prefix(self, buf):
|
|
20
|
+
# Read in binary format.
|
|
21
|
+
# Write in text format.
|
|
22
|
+
write_binary_uint8(1, buf)
|
|
23
|
+
|
|
24
|
+
def read_items(self, n_items, buf):
|
|
25
|
+
read_binary_uint8(buf)
|
|
26
|
+
spec = read_binary_str(buf)
|
|
27
|
+
col = self.column_by_spec_getter(spec)
|
|
28
|
+
col.read_state_prefix(buf)
|
|
29
|
+
return col.read_data(n_items, buf)
|
|
30
|
+
|
|
31
|
+
def write_items(self, items, buf):
|
|
32
|
+
items = [x if isinstance(x, str) else json.dumps(x) for x in items]
|
|
33
|
+
self.string_column.write_items(items, buf)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def create_json_column(spec, column_by_spec_getter, column_options):
|
|
37
|
+
return JsonColumn(column_by_spec_getter, **column_options)
|
|
Binary file
|
|
@@ -35,25 +35,32 @@ class LowCardinalityColumn(Column):
|
|
|
35
35
|
serialization_type = has_additional_keys_bit | need_update_dictionary
|
|
36
36
|
|
|
37
37
|
def __init__(self, nested_column, **kwargs):
|
|
38
|
+
self.init_kwargs = kwargs
|
|
38
39
|
self.nested_column = nested_column
|
|
39
40
|
super(LowCardinalityColumn, self).__init__(**kwargs)
|
|
40
41
|
|
|
41
42
|
def read_state_prefix(self, buf):
|
|
42
|
-
|
|
43
|
+
super(LowCardinalityColumn, self).read_state_prefix(buf)
|
|
44
|
+
|
|
45
|
+
read_binary_uint64(buf)
|
|
43
46
|
|
|
44
47
|
def write_state_prefix(self, buf):
|
|
48
|
+
super(LowCardinalityColumn, self).write_state_prefix(buf)
|
|
49
|
+
|
|
45
50
|
# KeysSerializationVersion. See ClickHouse docs.
|
|
46
51
|
write_binary_int64(1, buf)
|
|
47
52
|
|
|
48
53
|
def _write_data(self, items, buf):
|
|
49
54
|
index, keys = [], []
|
|
50
55
|
key_by_index_element = {}
|
|
56
|
+
nested_is_nullable = False
|
|
51
57
|
|
|
52
58
|
if self.nested_column.nullable:
|
|
53
59
|
# First element represents NULL if column is nullable.
|
|
54
60
|
index.append(self.nested_column.null_value)
|
|
55
61
|
# Prevent null map writing. Reset nested column nullable flag.
|
|
56
62
|
self.nested_column.nullable = False
|
|
63
|
+
nested_is_nullable = True
|
|
57
64
|
|
|
58
65
|
for x in items:
|
|
59
66
|
if x is None:
|
|
@@ -87,14 +94,26 @@ class LowCardinalityColumn(Column):
|
|
|
87
94
|
return
|
|
88
95
|
|
|
89
96
|
int_type = int(log(len(index), 2) / 8)
|
|
90
|
-
int_column = self.int_types[int_type]()
|
|
97
|
+
int_column = self.int_types[int_type](**self.init_kwargs)
|
|
91
98
|
|
|
92
99
|
serialization_type = self.serialization_type | int_type
|
|
93
100
|
|
|
94
101
|
write_binary_int64(serialization_type, buf)
|
|
95
102
|
write_binary_int64(len(index), buf)
|
|
96
103
|
|
|
97
|
-
|
|
104
|
+
if nested_is_nullable:
|
|
105
|
+
# Given we reset nested column nullable flag above,
|
|
106
|
+
# we need to write null map manually. If to invoke
|
|
107
|
+
# write_data method, it will cause an exception,
|
|
108
|
+
# because `prepare_data` may not be able to handle
|
|
109
|
+
# null value correctly.
|
|
110
|
+
self.nested_column.write_items(
|
|
111
|
+
[self.nested_column.null_value], buf)
|
|
112
|
+
# Remove null map from index, because it is already written.
|
|
113
|
+
index_to_write = index[1:]
|
|
114
|
+
self.nested_column.write_data(index_to_write, buf)
|
|
115
|
+
else:
|
|
116
|
+
self.nested_column.write_data(index, buf)
|
|
98
117
|
write_binary_int64(len(items), buf)
|
|
99
118
|
int_column.write_items(keys, buf)
|
|
100
119
|
|
|
@@ -106,7 +125,7 @@ class LowCardinalityColumn(Column):
|
|
|
106
125
|
|
|
107
126
|
# Lowest byte contains info about key type.
|
|
108
127
|
key_type = serialization_type & 0xf
|
|
109
|
-
keys_column = self.int_types[key_type]()
|
|
128
|
+
keys_column = self.int_types[key_type](**self.init_kwargs)
|
|
110
129
|
|
|
111
130
|
nullable = self.nested_column.nullable
|
|
112
131
|
# Prevent null map reading. Reset nested column nullable flag.
|
|
@@ -13,20 +13,27 @@ class MapColumn(Column):
|
|
|
13
13
|
null_value = {}
|
|
14
14
|
|
|
15
15
|
def __init__(self, key_column, value_column, **kwargs):
|
|
16
|
-
self.offset_column = UInt64Column()
|
|
16
|
+
self.offset_column = UInt64Column(**kwargs)
|
|
17
17
|
self.key_column = key_column
|
|
18
18
|
self.value_column = value_column
|
|
19
19
|
super(MapColumn, self).__init__(**kwargs)
|
|
20
20
|
|
|
21
21
|
def read_state_prefix(self, buf):
|
|
22
|
+
super(MapColumn, self).read_state_prefix(buf)
|
|
23
|
+
|
|
22
24
|
self.key_column.read_state_prefix(buf)
|
|
23
25
|
self.value_column.read_state_prefix(buf)
|
|
24
26
|
|
|
25
27
|
def write_state_prefix(self, buf):
|
|
28
|
+
super(MapColumn, self).write_state_prefix(buf)
|
|
29
|
+
|
|
26
30
|
self.key_column.write_state_prefix(buf)
|
|
27
31
|
self.value_column.write_state_prefix(buf)
|
|
28
32
|
|
|
29
33
|
def read_items(self, n_items, buf):
|
|
34
|
+
if not n_items:
|
|
35
|
+
return [{}]
|
|
36
|
+
|
|
30
37
|
offsets = list(self.offset_column.read_items(n_items, buf))
|
|
31
38
|
last_offset = offsets[-1]
|
|
32
39
|
keys = self.key_column.read_data(last_offset, buf)
|
|
@@ -57,7 +64,7 @@ class MapColumn(Column):
|
|
|
57
64
|
|
|
58
65
|
|
|
59
66
|
def create_map_column(spec, column_by_spec_getter, column_options):
|
|
60
|
-
# Match commas outside of parentheses so we don't match the comma in
|
|
67
|
+
# Match commas outside of parentheses, so we don't match the comma in
|
|
61
68
|
# Decimal types.
|
|
62
69
|
key, value = comma_re.split(spec[4:-1])
|
|
63
70
|
key_column = column_by_spec_getter(key.strip())
|
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
from .arraycolumn import create_array_column
|
|
3
|
-
from .util import get_inner_spec
|
|
4
|
-
get_inner_columns_with_types
|
|
3
|
+
from .util import get_inner_spec
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
def create_nested_column(spec, column_by_spec_getter, column_options):
|
|
8
7
|
return create_array_column(
|
|
9
|
-
'Array(Tuple({}))'.format(',
|
|
8
|
+
'Array(Tuple({}))'.format(get_inner_spec('Nested', spec)),
|
|
10
9
|
column_by_spec_getter, column_options
|
|
11
10
|
)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def get_nested_columns(spec):
|
|
15
|
-
inner_spec = get_inner_spec('Nested', spec)
|
|
16
|
-
return get_inner_columns(inner_spec)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def get_columns_with_types(spec):
|
|
20
|
-
inner_spec = get_inner_spec('Nested', spec)
|
|
21
|
-
return get_inner_columns_with_types(inner_spec)
|
|
@@ -21,19 +21,21 @@ class NumpyDateTimeColumnBase(NumpyColumn):
|
|
|
21
21
|
def apply_timezones_after_read(self, dt):
|
|
22
22
|
timezone = self.timezone if self.timezone else self.local_timezone
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if self.offset_naive:
|
|
24
|
+
if self.offset_naive and timezone.zone != 'UTC':
|
|
25
|
+
ts = pd.to_datetime(dt, utc=True).tz_convert(timezone)
|
|
27
26
|
ts = ts.tz_localize(None)
|
|
27
|
+
return ts.to_numpy(self.datetime_dtype)
|
|
28
28
|
|
|
29
|
-
return
|
|
29
|
+
return dt
|
|
30
30
|
|
|
31
31
|
def apply_timezones_before_write(self, items):
|
|
32
32
|
if isinstance(items, pd.DatetimeIndex):
|
|
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)
|
|
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)
|
|
@@ -65,7 +67,7 @@ class NumpyDateTimeColumn(NumpyDateTimeColumnBase):
|
|
|
65
67
|
|
|
66
68
|
|
|
67
69
|
class NumpyDateTime64Column(NumpyDateTimeColumnBase):
|
|
68
|
-
dtype = np.dtype(np.
|
|
70
|
+
dtype = np.dtype(np.int64)
|
|
69
71
|
datetime_dtype = 'datetime64[ns]'
|
|
70
72
|
|
|
71
73
|
max_scale = 9
|
|
@@ -75,15 +77,15 @@ class NumpyDateTime64Column(NumpyDateTimeColumnBase):
|
|
|
75
77
|
super(NumpyDateTime64Column, self).__init__(**kwargs)
|
|
76
78
|
|
|
77
79
|
def read_items(self, n_items, buf):
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
# Clickhouse: t seconds is represented as t * 10^scale.
|
|
81
|
+
# datetime64[ns]: t seconds is represented as t * 10^9.
|
|
82
|
+
# Since 0 <= scale <= 9, multiply by the integer 10^(9 - scale).
|
|
81
83
|
items = super(NumpyDateTime64Column, self).read_items(n_items, buf)
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
tmp = np.copy(items)
|
|
86
|
+
tmp *= 10 ** (9 - self.scale)
|
|
87
|
+
dt = tmp.view(dtype='datetime64[ns]')
|
|
85
88
|
|
|
86
|
-
dt = seconds + microseconds
|
|
87
89
|
return self.apply_timezones_after_read(dt)
|
|
88
90
|
|
|
89
91
|
def write_items(self, items, buf):
|
|
@@ -120,12 +122,12 @@ def create_numpy_datetime_column(spec, column_options):
|
|
|
120
122
|
|
|
121
123
|
context = column_options['context']
|
|
122
124
|
|
|
123
|
-
tz_name =
|
|
125
|
+
tz_name = None
|
|
124
126
|
offset_naive = True
|
|
125
127
|
|
|
126
128
|
# As Numpy do not use local timezone for converting timestamp to
|
|
127
129
|
# datetime we need always detect local timezone for manual converting.
|
|
128
|
-
|
|
130
|
+
local_tz_name = get_localzone_name_compat()
|
|
129
131
|
|
|
130
132
|
# Use column's timezone if it's specified.
|
|
131
133
|
if spec and spec[-1] == ')':
|
|
@@ -133,11 +135,12 @@ 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
|
-
|
|
137
|
-
|
|
138
|
+
remote_timezone = context.server_info.get_timezone()
|
|
139
|
+
if local_tz_name != remote_timezone:
|
|
140
|
+
tz_name = remote_timezone
|
|
138
141
|
|
|
139
|
-
if tz_name
|
|
140
|
-
|
|
142
|
+
timezone = get_timezone(tz_name) if tz_name else None
|
|
143
|
+
local_timezone = get_timezone(local_tz_name) if local_tz_name else None
|
|
141
144
|
|
|
142
145
|
return cls(timezone=timezone, offset_naive=offset_naive,
|
|
143
146
|
local_timezone=local_timezone, **column_options)
|
|
@@ -37,7 +37,7 @@ class NumpyLowCardinalityColumn(LowCardinalityColumn):
|
|
|
37
37
|
c = pd.Categorical(items)
|
|
38
38
|
|
|
39
39
|
int_type = int(log(len(c.codes), 2) / 8)
|
|
40
|
-
int_column = self.int_types[int_type]()
|
|
40
|
+
int_column = self.int_types[int_type](**self.init_kwargs)
|
|
41
41
|
|
|
42
42
|
serialization_type = self.serialization_type | int_type
|
|
43
43
|
|
|
@@ -66,7 +66,7 @@ class NumpyLowCardinalityColumn(LowCardinalityColumn):
|
|
|
66
66
|
|
|
67
67
|
# Lowest byte contains info about key type.
|
|
68
68
|
key_type = serialization_type & 0xf
|
|
69
|
-
keys_column = self.int_types[key_type]()
|
|
69
|
+
keys_column = self.int_types[key_type](**self.init_kwargs)
|
|
70
70
|
|
|
71
71
|
nullable = self.nested_column.nullable
|
|
72
72
|
# Prevent null map reading. Reset nested column nullable flag.
|
|
@@ -15,6 +15,7 @@ from .intcolumn import (
|
|
|
15
15
|
UInt8Column, UInt16Column, UInt32Column, UInt64Column
|
|
16
16
|
)
|
|
17
17
|
from .lowcardinalitycolumn import create_low_cardinality_column
|
|
18
|
+
from .jsoncolumn import create_json_column
|
|
18
19
|
from .mapcolumn import create_map_column
|
|
19
20
|
from .nothingcolumn import NothingColumn
|
|
20
21
|
from .nullcolumn import NullColumn
|
|
@@ -122,6 +123,11 @@ def get_column_by_spec(spec, column_options, use_numpy=None):
|
|
|
122
123
|
spec, create_column_with_options, column_options
|
|
123
124
|
)
|
|
124
125
|
|
|
126
|
+
elif spec.startswith("Object('json')"):
|
|
127
|
+
return create_json_column(
|
|
128
|
+
spec, create_column_with_options, column_options
|
|
129
|
+
)
|
|
130
|
+
|
|
125
131
|
else:
|
|
126
132
|
for alias, primitive in aliases:
|
|
127
133
|
if spec.startswith(alias):
|
|
@@ -137,8 +143,12 @@ def get_column_by_spec(spec, column_options, use_numpy=None):
|
|
|
137
143
|
raise errors.UnknownTypeError('Unknown type {}'.format(spec))
|
|
138
144
|
|
|
139
145
|
|
|
140
|
-
def read_column(context, column_spec, n_items, buf, use_numpy=None
|
|
141
|
-
|
|
146
|
+
def read_column(context, column_spec, n_items, buf, use_numpy=None,
|
|
147
|
+
has_custom_serialization=False):
|
|
148
|
+
column_options = {
|
|
149
|
+
'context': context,
|
|
150
|
+
'has_custom_serialization': has_custom_serialization
|
|
151
|
+
}
|
|
142
152
|
col = get_column_by_spec(column_spec, column_options, use_numpy=use_numpy)
|
|
143
153
|
col.read_state_prefix(buf)
|
|
144
154
|
return col.read_data(n_items, buf)
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
|
|
2
2
|
from .base import Column
|
|
3
|
-
from .util import get_inner_spec,
|
|
3
|
+
from .util import get_inner_spec, get_inner_columns_with_types
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class TupleColumn(Column):
|
|
7
7
|
py_types = (list, tuple)
|
|
8
8
|
|
|
9
|
-
def __init__(self, nested_columns, **kwargs):
|
|
9
|
+
def __init__(self, names, nested_columns, **kwargs):
|
|
10
|
+
self.names = names
|
|
10
11
|
self.nested_columns = nested_columns
|
|
12
|
+
client_settings = kwargs['context'].client_settings
|
|
13
|
+
settings = kwargs['context'].settings
|
|
14
|
+
self.namedtuple_as_json = (
|
|
15
|
+
settings.get('allow_experimental_object_type', False) and
|
|
16
|
+
client_settings.get('namedtuple_as_json', True)
|
|
17
|
+
)
|
|
18
|
+
|
|
11
19
|
super(TupleColumn, self).__init__(**kwargs)
|
|
12
20
|
self.null_value = tuple(x.null_value for x in nested_columns)
|
|
13
21
|
|
|
@@ -23,15 +31,33 @@ class TupleColumn(Column):
|
|
|
23
31
|
|
|
24
32
|
def read_data(self, n_items, buf):
|
|
25
33
|
rv = [x.read_data(n_items, buf) for x in self.nested_columns]
|
|
26
|
-
|
|
34
|
+
rv = list(zip(*rv))
|
|
35
|
+
|
|
36
|
+
if self.names[0] and self.namedtuple_as_json:
|
|
37
|
+
return [dict(zip(self.names, x)) for x in rv]
|
|
38
|
+
else:
|
|
39
|
+
return rv
|
|
27
40
|
|
|
28
41
|
def read_items(self, n_items, buf):
|
|
29
42
|
return self.read_data(n_items, buf)
|
|
30
43
|
|
|
44
|
+
def read_state_prefix(self, buf):
|
|
45
|
+
super(TupleColumn, self).read_state_prefix(buf)
|
|
46
|
+
|
|
47
|
+
for x in self.nested_columns:
|
|
48
|
+
x.read_state_prefix(buf)
|
|
49
|
+
|
|
50
|
+
def write_state_prefix(self, buf):
|
|
51
|
+
super(TupleColumn, self).write_state_prefix(buf)
|
|
52
|
+
|
|
53
|
+
for x in self.nested_columns:
|
|
54
|
+
x.write_state_prefix(buf)
|
|
55
|
+
|
|
31
56
|
|
|
32
57
|
def create_tuple_column(spec, column_by_spec_getter, column_options):
|
|
33
58
|
inner_spec = get_inner_spec('Tuple', spec)
|
|
34
|
-
|
|
59
|
+
columns_with_types = get_inner_columns_with_types(inner_spec)
|
|
60
|
+
names, types = zip(*columns_with_types)
|
|
35
61
|
|
|
36
|
-
return TupleColumn([column_by_spec_getter(x) for x in
|
|
62
|
+
return TupleColumn(names, [column_by_spec_getter(x) for x in types],
|
|
37
63
|
**column_options)
|
|
@@ -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((
|