clickhouse-driver 0.2.1__cp39-cp39-win_amd64.whl → 0.2.10__cp39-cp39-win_amd64.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.
Files changed (85) hide show
  1. clickhouse_driver/__init__.py +9 -9
  2. clickhouse_driver/block.py +227 -195
  3. clickhouse_driver/blockstreamprofileinfo.py +22 -22
  4. clickhouse_driver/bufferedreader.cp39-win_amd64.pyd +0 -0
  5. clickhouse_driver/bufferedwriter.cp39-win_amd64.pyd +0 -0
  6. clickhouse_driver/client.py +812 -666
  7. clickhouse_driver/clientinfo.py +119 -80
  8. clickhouse_driver/columns/arraycolumn.py +161 -150
  9. clickhouse_driver/columns/base.py +221 -147
  10. clickhouse_driver/columns/boolcolumn.py +7 -0
  11. clickhouse_driver/columns/datecolumn.py +108 -49
  12. clickhouse_driver/columns/datetimecolumn.py +203 -207
  13. clickhouse_driver/columns/decimalcolumn.py +116 -118
  14. clickhouse_driver/columns/enumcolumn.py +129 -119
  15. clickhouse_driver/columns/exceptions.py +12 -12
  16. clickhouse_driver/columns/floatcolumn.py +34 -34
  17. clickhouse_driver/columns/intcolumn.py +157 -157
  18. clickhouse_driver/columns/intervalcolumn.py +33 -33
  19. clickhouse_driver/columns/ipcolumn.py +118 -118
  20. clickhouse_driver/columns/jsoncolumn.py +37 -0
  21. clickhouse_driver/columns/largeint.cp39-win_amd64.pyd +0 -0
  22. clickhouse_driver/columns/lowcardinalitycolumn.py +142 -123
  23. clickhouse_driver/columns/mapcolumn.py +73 -58
  24. clickhouse_driver/columns/nestedcolumn.py +10 -0
  25. clickhouse_driver/columns/nothingcolumn.py +13 -13
  26. clickhouse_driver/columns/nullablecolumn.py +7 -7
  27. clickhouse_driver/columns/nullcolumn.py +15 -15
  28. clickhouse_driver/columns/numpy/base.py +47 -14
  29. clickhouse_driver/columns/numpy/boolcolumn.py +8 -0
  30. clickhouse_driver/columns/numpy/datecolumn.py +19 -12
  31. clickhouse_driver/columns/numpy/datetimecolumn.py +146 -145
  32. clickhouse_driver/columns/numpy/floatcolumn.py +24 -13
  33. clickhouse_driver/columns/numpy/intcolumn.py +43 -43
  34. clickhouse_driver/columns/numpy/lowcardinalitycolumn.py +96 -83
  35. clickhouse_driver/columns/numpy/service.py +58 -80
  36. clickhouse_driver/columns/numpy/stringcolumn.py +78 -76
  37. clickhouse_driver/columns/numpy/tuplecolumn.py +37 -0
  38. clickhouse_driver/columns/service.py +185 -131
  39. clickhouse_driver/columns/simpleaggregatefunctioncolumn.py +7 -7
  40. clickhouse_driver/columns/stringcolumn.py +73 -73
  41. clickhouse_driver/columns/tuplecolumn.py +63 -65
  42. clickhouse_driver/columns/util.py +61 -0
  43. clickhouse_driver/columns/uuidcolumn.py +64 -64
  44. clickhouse_driver/compression/__init__.py +32 -28
  45. clickhouse_driver/compression/base.py +87 -52
  46. clickhouse_driver/compression/lz4.py +21 -55
  47. clickhouse_driver/compression/lz4hc.py +9 -9
  48. clickhouse_driver/compression/zstd.py +20 -51
  49. clickhouse_driver/connection.py +825 -632
  50. clickhouse_driver/context.py +36 -36
  51. clickhouse_driver/dbapi/__init__.py +62 -62
  52. clickhouse_driver/dbapi/connection.py +99 -96
  53. clickhouse_driver/dbapi/cursor.py +370 -368
  54. clickhouse_driver/dbapi/errors.py +40 -40
  55. clickhouse_driver/dbapi/extras.py +73 -0
  56. clickhouse_driver/defines.py +58 -42
  57. clickhouse_driver/errors.py +453 -446
  58. clickhouse_driver/log.py +48 -44
  59. clickhouse_driver/numpy/block.py +8 -8
  60. clickhouse_driver/numpy/helpers.py +28 -25
  61. clickhouse_driver/numpy/result.py +123 -123
  62. clickhouse_driver/opentelemetry.py +43 -0
  63. clickhouse_driver/progress.py +44 -32
  64. clickhouse_driver/protocol.py +130 -105
  65. clickhouse_driver/queryprocessingstage.py +8 -8
  66. clickhouse_driver/reader.py +69 -69
  67. clickhouse_driver/readhelpers.py +26 -26
  68. clickhouse_driver/result.py +144 -144
  69. clickhouse_driver/settings/available.py +405 -405
  70. clickhouse_driver/settings/types.py +50 -50
  71. clickhouse_driver/settings/writer.py +34 -29
  72. clickhouse_driver/streams/compressed.py +88 -88
  73. clickhouse_driver/streams/native.py +108 -90
  74. clickhouse_driver/util/compat.py +39 -0
  75. clickhouse_driver/util/escape.py +94 -55
  76. clickhouse_driver/util/helpers.py +173 -57
  77. clickhouse_driver/varint.cp39-win_amd64.pyd +0 -0
  78. clickhouse_driver/writer.py +67 -67
  79. clickhouse_driver-0.2.10.dist-info/METADATA +215 -0
  80. clickhouse_driver-0.2.10.dist-info/RECORD +89 -0
  81. {clickhouse_driver-0.2.1.dist-info → clickhouse_driver-0.2.10.dist-info}/WHEEL +1 -1
  82. {clickhouse_driver-0.2.1.dist-info → clickhouse_driver-0.2.10.dist-info/licenses}/LICENSE +21 -21
  83. clickhouse_driver-0.2.1.dist-info/METADATA +0 -24
  84. clickhouse_driver-0.2.1.dist-info/RECORD +0 -80
  85. {clickhouse_driver-0.2.1.dist-info → clickhouse_driver-0.2.10.dist-info}/top_level.txt +0 -0
@@ -1,80 +1,119 @@
1
- import socket
2
- import getpass
3
-
4
- from . import defines
5
- from . import errors
6
- from .varint import write_varint
7
- from .writer import write_binary_str, write_binary_uint8
8
-
9
-
10
- class ClientInfo(object):
11
- class Interface(object):
12
- TCP = 1
13
- HTTP = 2
14
-
15
- class QueryKind(object):
16
- # Uninitialized object.
17
- NO_QUERY = 0
18
-
19
- INITIAL_QUERY = 1
20
-
21
- # Query that was initiated by another query for distributed query
22
- # execution.
23
- SECONDARY_QUERY = 2
24
-
25
- client_version_major = defines.CLIENT_VERSION_MAJOR
26
- client_version_minor = defines.CLIENT_VERSION_MINOR
27
- client_version_patch = defines.CLIENT_VERSION_PATCH
28
- client_revision = defines.CLIENT_REVISION
29
- interface = Interface.TCP
30
-
31
- initial_user = ''
32
- initial_query_id = ''
33
- initial_address = '0.0.0.0:0'
34
-
35
- quota_key = ''
36
-
37
- def __init__(self, client_name):
38
- self.query_kind = ClientInfo.QueryKind.NO_QUERY
39
-
40
- try:
41
- self.os_user = getpass.getuser()
42
- except KeyError:
43
- self.os_user = ''
44
- self.client_hostname = socket.gethostname()
45
- self.client_name = client_name
46
-
47
- super(ClientInfo, self).__init__()
48
-
49
- @property
50
- def empty(self):
51
- return self.query_kind == ClientInfo.QueryKind.NO_QUERY
52
-
53
- def write(self, server_revision, fout):
54
- revision = server_revision
55
- if server_revision < defines.DBMS_MIN_REVISION_WITH_CLIENT_INFO:
56
- raise errors.LogicalError('Method ClientInfo.write is called '
57
- 'for unsupported server revision')
58
-
59
- write_binary_uint8(self.query_kind, fout)
60
- if self.empty:
61
- return
62
-
63
- write_binary_str(self.initial_user, fout)
64
- write_binary_str(self.initial_query_id, fout)
65
- write_binary_str(self.initial_address, fout)
66
-
67
- write_binary_uint8(self.interface, fout)
68
-
69
- write_binary_str(self.os_user, fout)
70
- write_binary_str(self.client_hostname, fout)
71
- write_binary_str(self.client_name, fout)
72
- write_varint(self.client_version_major, fout)
73
- write_varint(self.client_version_minor, fout)
74
- write_varint(self.client_revision, fout)
75
-
76
- if revision >= defines.DBMS_MIN_REVISION_WITH_QUOTA_KEY_IN_CLIENT_INFO:
77
- write_binary_str(self.quota_key, fout)
78
-
79
- if revision >= defines.DBMS_MIN_REVISION_WITH_VERSION_PATCH:
80
- write_varint(self.client_version_patch, fout)
1
+ import socket
2
+ import getpass
3
+ from time import time
4
+
5
+ from . import defines
6
+ from . import errors
7
+ from .opentelemetry import OpenTelemetryTraceContext
8
+ from .varint import write_varint
9
+ from .writer import write_binary_str, write_binary_uint8, \
10
+ write_binary_uint64, write_binary_uint128
11
+
12
+
13
+ class ClientInfo(object):
14
+ class Interface(object):
15
+ TCP = 1
16
+ HTTP = 2
17
+
18
+ class QueryKind(object):
19
+ # Uninitialized object.
20
+ NO_QUERY = 0
21
+
22
+ INITIAL_QUERY = 1
23
+
24
+ # Query that was initiated by another query for distributed query
25
+ # execution.
26
+ SECONDARY_QUERY = 2
27
+
28
+ client_version_major = defines.CLIENT_VERSION_MAJOR
29
+ client_version_minor = defines.CLIENT_VERSION_MINOR
30
+ client_version_patch = defines.CLIENT_VERSION_PATCH
31
+ interface = Interface.TCP
32
+
33
+ initial_user = ''
34
+ initial_query_id = ''
35
+ initial_address = '0.0.0.0:0'
36
+
37
+ def __init__(self, client_name, context, client_revision):
38
+ self.query_kind = ClientInfo.QueryKind.NO_QUERY
39
+
40
+ try:
41
+ self.os_user = getpass.getuser()
42
+ except (KeyError, OSError):
43
+ self.os_user = ''
44
+ self.client_hostname = socket.gethostname()
45
+ self.client_name = client_name
46
+ self.client_revision = client_revision
47
+
48
+ self.client_trace_context = OpenTelemetryTraceContext(
49
+ context.client_settings['opentelemetry_traceparent'],
50
+ context.client_settings['opentelemetry_tracestate']
51
+ )
52
+
53
+ self.quota_key = context.client_settings['quota_key']
54
+ self.distributed_depth = 0
55
+ self.initial_query_start_time_microseconds = int(time() * 1000000)
56
+
57
+ super(ClientInfo, self).__init__()
58
+
59
+ @property
60
+ def empty(self):
61
+ return self.query_kind == ClientInfo.QueryKind.NO_QUERY
62
+
63
+ def write(self, server_revision, fout):
64
+ revision = server_revision
65
+ if server_revision < defines.DBMS_MIN_REVISION_WITH_CLIENT_INFO:
66
+ raise errors.LogicalError('Method ClientInfo.write is called '
67
+ 'for unsupported server revision')
68
+
69
+ write_binary_uint8(self.query_kind, fout)
70
+ if self.empty:
71
+ return
72
+
73
+ write_binary_str(self.initial_user, fout)
74
+ write_binary_str(self.initial_query_id, fout)
75
+ write_binary_str(self.initial_address, fout)
76
+
77
+ if (
78
+ revision >=
79
+ defines.DBMS_MIN_PROTOCOL_VERSION_WITH_INITIAL_QUERY_START_TIME
80
+ ):
81
+ write_binary_uint64(
82
+ self.initial_query_start_time_microseconds, fout
83
+ )
84
+
85
+ write_binary_uint8(self.interface, fout)
86
+
87
+ write_binary_str(self.os_user, fout)
88
+ write_binary_str(self.client_hostname, fout)
89
+ write_binary_str(self.client_name, fout)
90
+ write_varint(self.client_version_major, fout)
91
+ write_varint(self.client_version_minor, fout)
92
+ write_varint(self.client_revision, fout)
93
+
94
+ if revision >= defines.DBMS_MIN_REVISION_WITH_QUOTA_KEY_IN_CLIENT_INFO:
95
+ write_binary_str(self.quota_key, fout)
96
+
97
+ if revision >= \
98
+ defines.DBMS_MIN_PROTOCOL_VERSION_WITH_DISTRIBUTED_DEPTH:
99
+ write_varint(self.distributed_depth, fout)
100
+
101
+ if revision >= defines.DBMS_MIN_REVISION_WITH_VERSION_PATCH:
102
+ write_varint(self.client_version_patch, fout)
103
+
104
+ if revision >= defines.DBMS_MIN_REVISION_WITH_OPENTELEMETRY:
105
+ if self.client_trace_context.trace_id is not None:
106
+ # Have OpenTelemetry header.
107
+ write_binary_uint8(1, fout)
108
+ write_binary_uint128(self.client_trace_context.trace_id, fout)
109
+ write_binary_uint64(self.client_trace_context.span_id, fout)
110
+ write_binary_str(self.client_trace_context.tracestate, fout)
111
+ write_binary_uint8(self.client_trace_context.trace_flags, fout)
112
+ else:
113
+ # Don't have OpenTelemetry header.
114
+ write_binary_uint8(0, fout)
115
+
116
+ if revision >= defines.DBMS_MIN_REVISION_WITH_PARALLEL_REPLICAS:
117
+ write_varint(0, fout) # collaborate_with_initiator
118
+ write_varint(0, fout) # count_participating_replicas
119
+ write_varint(0, fout) # number_of_current_replica
@@ -1,150 +1,161 @@
1
- from itertools import chain
2
- from struct import Struct
3
-
4
- from .base import Column
5
- from .intcolumn import UInt64Column
6
- from ..util.helpers import pairwise
7
-
8
-
9
- class ArrayColumn(Column):
10
- """
11
- Nested arrays written in flatten form after information about their
12
- sizes (offsets really).
13
- One element of array of arrays can be represented as tree:
14
- (0 depth) [[3, 4], [5, 6]]
15
- | |
16
- (1 depth) [3, 4] [5, 6]
17
- | | | |
18
- (leaf) 3 4 5 6
19
-
20
- Offsets (sizes) written in breadth-first search order. In example above
21
- following sequence of offset will be written: 4 -> 2 -> 4
22
- 1) size of whole array: 4
23
- 2) size of array 1 in depth=1: 2
24
- 3) size of array 2 plus size of all array before in depth=1: 2 + 2 = 4
25
-
26
- After sizes info comes flatten data: 3 -> 4 -> 5 -> 6
27
- """
28
- py_types = (list, tuple)
29
-
30
- def __init__(self, nested_column, **kwargs):
31
- self.size_column = UInt64Column()
32
- self.nested_column = nested_column
33
- self._write_depth_0_size = True
34
- super(ArrayColumn, self).__init__(**kwargs)
35
-
36
- def write_data(self, data, buf):
37
- # Column of Array(T) is stored in "compact" format and passed to server
38
- # wrapped into another Array without size of wrapper array.
39
- self.nested_column = ArrayColumn(self.nested_column)
40
- self.nested_column.nullable = self.nullable
41
- self.nullable = False
42
- self._write_depth_0_size = False
43
- self._write(data, buf)
44
-
45
- def read_data(self, rows, buf):
46
- self.nested_column = ArrayColumn(self.nested_column)
47
- self.nested_column.nullable = self.nullable
48
- self.nullable = False
49
- return self._read(rows, buf)[0]
50
-
51
- def _write_sizes(self, value, buf):
52
- nulls_map = []
53
-
54
- column = self
55
- sizes = [len(value)] if self._write_depth_0_size else []
56
-
57
- while True:
58
- nested_column = column.nested_column
59
- if not isinstance(nested_column, ArrayColumn):
60
- if column.nullable:
61
- nulls_map = [x is None for x in value]
62
- break
63
-
64
- offset = 0
65
- new_value = []
66
- for x in value:
67
- offset += len(x)
68
- sizes.append(offset)
69
- new_value.extend(x)
70
-
71
- value = new_value
72
- column = nested_column
73
-
74
- if nulls_map:
75
- self._write_nulls_map(nulls_map, buf)
76
-
77
- ns = Struct('<{}Q'.format(len(sizes)))
78
- buf.write(ns.pack(*sizes))
79
-
80
- def _write_data(self, value, buf):
81
- if self.nullable:
82
- value = value or []
83
-
84
- if isinstance(self.nested_column, ArrayColumn):
85
- value = list(chain.from_iterable(value))
86
-
87
- if value:
88
- self.nested_column._write_data(value, buf)
89
-
90
- def _write_nulls_data(self, value, buf):
91
- if self.nullable:
92
- value = value or []
93
-
94
- if isinstance(self.nested_column, ArrayColumn):
95
- value = list(chain.from_iterable(value))
96
- self.nested_column._write_nulls_data(value, buf)
97
- else:
98
- if self.nested_column.nullable:
99
- self.nested_column._write_nulls_map(value, buf)
100
-
101
- def _write(self, value, buf):
102
- self._write_sizes(value, buf)
103
- self._write_nulls_data(value, buf)
104
- self._write_data(value, buf)
105
-
106
- def read_state_prefix(self, buf):
107
- return self.nested_column.read_state_prefix(buf)
108
-
109
- def write_state_prefix(self, buf):
110
- self.nested_column.write_state_prefix(buf)
111
-
112
- def _read(self, size, buf):
113
- slices_series = [[0, size]]
114
- nested_column = self.nested_column
115
-
116
- cur_level_slice_size = size
117
- cur_level_slice = None
118
- while (isinstance(nested_column, ArrayColumn)):
119
- if cur_level_slice is None:
120
- cur_level_slice = [0]
121
- ns = Struct('<{}Q'.format(cur_level_slice_size))
122
- nested_sizes = ns.unpack(buf.read(ns.size))
123
- cur_level_slice.extend(nested_sizes)
124
- slices_series.append(cur_level_slice)
125
- cur_level_slice = None
126
- cur_level_slice_size = nested_sizes[-1] if len(nested_sizes) > 0 \
127
- else 0
128
- nested_column = nested_column.nested_column
129
-
130
- n_items = cur_level_slice_size if size > 0 else 0
131
- nulls_map = None
132
- if nested_column.nullable:
133
- nulls_map = self._read_nulls_map(n_items, buf)
134
-
135
- data = []
136
- if n_items:
137
- data = list(nested_column._read_data(
138
- n_items, buf, nulls_map=nulls_map
139
- ))
140
-
141
- # Build nested structure.
142
- for slices in reversed(slices_series):
143
- data = [data[begin:end] for begin, end in pairwise(slices)]
144
-
145
- return tuple(data)
146
-
147
-
148
- def create_array_column(spec, column_by_spec_getter):
149
- inner = spec[6:-1]
150
- return ArrayColumn(column_by_spec_getter(inner))
1
+ from itertools import chain
2
+ from struct import Struct
3
+
4
+ from .base import Column
5
+ from .intcolumn import UInt64Column
6
+ from ..util.helpers import pairwise
7
+
8
+
9
+ class ArrayColumn(Column):
10
+ """
11
+ Nested arrays written in flatten form after information about their
12
+ sizes (offsets really).
13
+ One element of array of arrays can be represented as tree:
14
+ (0 depth) [[3, 4], [5, 6]]
15
+ | |
16
+ (1 depth) [3, 4] [5, 6]
17
+ | | | |
18
+ (leaf) 3 4 5 6
19
+
20
+ Offsets (sizes) written in breadth-first search order. In example above
21
+ following sequence of offset will be written: 4 -> 2 -> 4
22
+ 1) size of whole array: 4
23
+ 2) size of array 1 in depth=1: 2
24
+ 3) size of array 2 plus size of all array before in depth=1: 2 + 2 = 4
25
+
26
+ After sizes info comes flatten data: 3 -> 4 -> 5 -> 6
27
+ """
28
+ py_types = (list, tuple)
29
+
30
+ def __init__(self, nested_column, **kwargs):
31
+ self.init_kwargs = kwargs
32
+ self.size_column = UInt64Column(**kwargs)
33
+ self.nested_column = nested_column
34
+ self._write_depth_0_size = True
35
+ super(ArrayColumn, self).__init__(**kwargs)
36
+ self.null_value = []
37
+
38
+ def write_data(self, data, buf):
39
+ # Column of Array(T) is stored in "compact" format and passed to server
40
+ # wrapped into another Array without size of wrapper array.
41
+ self.nested_column = ArrayColumn(
42
+ self.nested_column, **self.init_kwargs
43
+ )
44
+ self.nested_column.nullable = self.nullable
45
+ self.nullable = False
46
+ self._write_depth_0_size = False
47
+ self._write(data, buf)
48
+
49
+ def read_data(self, n_rows, buf):
50
+ self.nested_column = ArrayColumn(
51
+ self.nested_column, **self.init_kwargs
52
+ )
53
+ self.nested_column.nullable = self.nullable
54
+ self.nullable = False
55
+ return self._read(n_rows, buf)[0]
56
+
57
+ def _write_sizes(self, value, buf):
58
+ nulls_map = []
59
+
60
+ column = self
61
+ sizes = [len(value)] if self._write_depth_0_size else []
62
+
63
+ while True:
64
+ nested_column = column.nested_column
65
+ if not isinstance(nested_column, ArrayColumn):
66
+ if column.nullable:
67
+ nulls_map = [x is None for x in value]
68
+ break
69
+
70
+ offset = 0
71
+ new_value = []
72
+ for x in value:
73
+ offset += len(x)
74
+ sizes.append(offset)
75
+ new_value.extend(x)
76
+
77
+ value = new_value
78
+ column = nested_column
79
+
80
+ if nulls_map:
81
+ self._write_nulls_map(nulls_map, buf)
82
+
83
+ ns = Struct('<{}Q'.format(len(sizes)))
84
+ buf.write(ns.pack(*sizes))
85
+
86
+ def _write_data(self, value, buf):
87
+ if self.nullable:
88
+ value = value or []
89
+
90
+ if isinstance(self.nested_column, ArrayColumn):
91
+ value = list(chain.from_iterable(value))
92
+
93
+ if value:
94
+ self.nested_column._write_data(value, buf)
95
+
96
+ def _write_nulls_data(self, value, buf):
97
+ if self.nullable:
98
+ value = value or []
99
+
100
+ if isinstance(self.nested_column, ArrayColumn):
101
+ value = list(chain.from_iterable(value))
102
+ self.nested_column._write_nulls_data(value, buf)
103
+ else:
104
+ if self.nested_column.nullable:
105
+ self.nested_column._write_nulls_map(value, buf)
106
+
107
+ def _write(self, value, buf):
108
+ value = self.prepare_items(value)
109
+ self._write_sizes(value, buf)
110
+ self._write_nulls_data(value, buf)
111
+ self._write_data(value, buf)
112
+
113
+ def read_state_prefix(self, buf):
114
+ super(ArrayColumn, self).read_state_prefix(buf)
115
+
116
+ self.nested_column.read_state_prefix(buf)
117
+
118
+ def write_state_prefix(self, buf):
119
+ super(ArrayColumn, self).write_state_prefix(buf)
120
+
121
+ self.nested_column.write_state_prefix(buf)
122
+
123
+ def _read(self, size, buf):
124
+ slices_series = [[0, size]]
125
+ nested_column = self.nested_column
126
+
127
+ cur_level_slice_size = size
128
+ cur_level_slice = None
129
+ while (isinstance(nested_column, ArrayColumn)):
130
+ if cur_level_slice is None:
131
+ cur_level_slice = [0]
132
+ ns = Struct('<{}Q'.format(cur_level_slice_size))
133
+ nested_sizes = ns.unpack(buf.read(ns.size))
134
+ cur_level_slice.extend(nested_sizes)
135
+ slices_series.append(cur_level_slice)
136
+ cur_level_slice = None
137
+ cur_level_slice_size = nested_sizes[-1] if len(nested_sizes) > 0 \
138
+ else 0
139
+ nested_column = nested_column.nested_column
140
+
141
+ n_items = cur_level_slice_size if size > 0 else 0
142
+ nulls_map = None
143
+ if nested_column.nullable:
144
+ nulls_map = self._read_nulls_map(n_items, buf)
145
+
146
+ data = []
147
+ if n_items:
148
+ data = list(nested_column._read_data(
149
+ n_items, buf, nulls_map=nulls_map
150
+ ))
151
+
152
+ # Build nested structure.
153
+ for slices in reversed(slices_series):
154
+ data = [data[begin:end] for begin, end in pairwise(slices)]
155
+
156
+ return tuple(data)
157
+
158
+
159
+ def create_array_column(spec, column_by_spec_getter, column_options):
160
+ inner = spec[6:-1]
161
+ return ArrayColumn(column_by_spec_getter(inner), **column_options)