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,50 +1,50 @@
1
- from ..util.helpers import asbool
2
- from ..varint import write_varint
3
- from ..writer import write_binary_str
4
-
5
-
6
- class SettingType(object):
7
- @classmethod
8
- def write(cls, value, buf):
9
- raise NotImplementedError
10
-
11
-
12
- class SettingUInt64(SettingType):
13
- @classmethod
14
- def write(cls, value, buf):
15
- write_varint(int(value), buf)
16
-
17
-
18
- class SettingBool(SettingType):
19
- @classmethod
20
- def write(cls, value, buf):
21
- write_varint(asbool(value), buf)
22
-
23
-
24
- class SettingString(SettingType):
25
- @classmethod
26
- def write(cls, value, buf):
27
- write_binary_str(value, buf)
28
-
29
-
30
- class SettingChar(SettingType):
31
- @classmethod
32
- def write(cls, value, buf):
33
- write_binary_str(value[0], buf)
34
-
35
-
36
- class SettingFloat(SettingType):
37
- @classmethod
38
- def write(cls, value, buf):
39
- """
40
- Float is written in string representation.
41
- """
42
- write_binary_str(str(value), buf)
43
-
44
-
45
- class SettingMaxThreads(SettingUInt64):
46
- @classmethod
47
- def write(cls, value, buf):
48
- if value == 'auto':
49
- value = 0
50
- super(SettingMaxThreads, cls).write(value, buf)
1
+ from ..util.helpers import asbool
2
+ from ..varint import write_varint
3
+ from ..writer import write_binary_str
4
+
5
+
6
+ class SettingType(object):
7
+ @classmethod
8
+ def write(cls, value, buf):
9
+ raise NotImplementedError
10
+
11
+
12
+ class SettingUInt64(SettingType):
13
+ @classmethod
14
+ def write(cls, value, buf):
15
+ write_varint(int(value), buf)
16
+
17
+
18
+ class SettingBool(SettingType):
19
+ @classmethod
20
+ def write(cls, value, buf):
21
+ write_varint(asbool(value), buf)
22
+
23
+
24
+ class SettingString(SettingType):
25
+ @classmethod
26
+ def write(cls, value, buf):
27
+ write_binary_str(value, buf)
28
+
29
+
30
+ class SettingChar(SettingType):
31
+ @classmethod
32
+ def write(cls, value, buf):
33
+ write_binary_str(value[0], buf)
34
+
35
+
36
+ class SettingFloat(SettingType):
37
+ @classmethod
38
+ def write(cls, value, buf):
39
+ """
40
+ Float is written in string representation.
41
+ """
42
+ write_binary_str(str(value), buf)
43
+
44
+
45
+ class SettingMaxThreads(SettingUInt64):
46
+ @classmethod
47
+ def write(cls, value, buf):
48
+ if value == 'auto':
49
+ value = 0
50
+ super(SettingMaxThreads, cls).write(value, buf)
@@ -1,29 +1,34 @@
1
- import logging
2
-
3
- from ..writer import write_binary_str, write_binary_uint8
4
- from .available import settings as available_settings
5
-
6
-
7
- logger = logging.getLogger(__name__)
8
-
9
-
10
- def write_settings(settings, buf, settings_as_strings, is_important=False):
11
- for setting, value in (settings or {}).items():
12
- # If the server support settings as string we do not need to know
13
- # anything about them, so we can write any setting.
14
- if settings_as_strings:
15
- write_binary_str(setting, buf)
16
- write_binary_uint8(int(is_important), buf)
17
- write_binary_str(str(value), buf)
18
-
19
- else:
20
- # If the server requires string in binary,
21
- # then they cannot be written without type.
22
- setting_writer = available_settings.get(setting)
23
- if not setting_writer:
24
- logger.warning('Unknown setting %s. Skipping', setting)
25
- continue
26
- write_binary_str(setting, buf)
27
- setting_writer.write(value, buf)
28
-
29
- write_binary_str('', buf) # end of settings
1
+ import logging
2
+
3
+ from ..writer import write_binary_str, write_binary_uint8
4
+ from .available import settings as available_settings
5
+
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ class SettingsFlags:
11
+ IMPORTANT = 0x1
12
+ CUSTOM = 0x2
13
+
14
+
15
+ def write_settings(settings, buf, settings_as_strings, flags):
16
+ for setting, value in (settings or {}).items():
17
+ # If the server support settings as string we do not need to know
18
+ # anything about them, so we can write any setting.
19
+ if settings_as_strings:
20
+ write_binary_str(setting, buf)
21
+ write_binary_uint8(flags, buf)
22
+ write_binary_str(str(value), buf)
23
+
24
+ else:
25
+ # If the server requires string in binary,
26
+ # then they cannot be written without type.
27
+ setting_writer = available_settings.get(setting)
28
+ if not setting_writer:
29
+ logger.warning('Unknown setting %s. Skipping', setting)
30
+ continue
31
+ write_binary_str(setting, buf)
32
+ setting_writer.write(value, buf)
33
+
34
+ write_binary_str('', buf) # end of settings
@@ -1,88 +1,88 @@
1
- from io import BytesIO
2
-
3
- try:
4
- from clickhouse_cityhash.cityhash import CityHash128
5
- except ImportError:
6
- raise RuntimeError(
7
- 'Package clickhouse-cityhash is required to use compression'
8
- )
9
-
10
- from .native import BlockOutputStream, BlockInputStream
11
- from ..bufferedreader import CompressedBufferedReader
12
- from ..bufferedwriter import CompressedBufferedWriter
13
- from ..compression import get_decompressor_cls
14
- from ..defines import BUFFER_SIZE
15
- from ..reader import read_binary_uint8, read_binary_uint128
16
- from ..writer import write_binary_uint8, write_binary_uint128
17
-
18
-
19
- class CompressedBlockOutputStream(BlockOutputStream):
20
- def __init__(self, compressor_cls, compress_block_size, fout, context):
21
- self.compressor_cls = compressor_cls
22
- self.compress_block_size = compress_block_size
23
- self.raw_fout = fout
24
-
25
- self.compressor = self.compressor_cls()
26
- self.fout = CompressedBufferedWriter(self.compressor, BUFFER_SIZE)
27
- super(CompressedBlockOutputStream, self).__init__(self.fout, context)
28
-
29
- def get_compressed_hash(self, data):
30
- return CityHash128(data)
31
-
32
- def finalize(self):
33
- self.fout.flush()
34
-
35
- compressed = self.get_compressed()
36
- compressed_size = len(compressed)
37
-
38
- compressed_hash = self.get_compressed_hash(compressed)
39
- write_binary_uint128(compressed_hash, self.raw_fout)
40
-
41
- block_size = self.compress_block_size
42
-
43
- i = 0
44
- while i < compressed_size:
45
- self.raw_fout.write(compressed[i:i + block_size])
46
- i += block_size
47
-
48
- self.raw_fout.flush()
49
-
50
- def get_compressed(self):
51
- compressed = BytesIO()
52
-
53
- if self.compressor.method_byte is not None:
54
- write_binary_uint8(self.compressor.method_byte, compressed)
55
- extra_header_size = 1 # method
56
- else:
57
- extra_header_size = 0
58
-
59
- data = self.compressor.get_compressed_data(extra_header_size)
60
- compressed.write(data)
61
-
62
- return compressed.getvalue()
63
-
64
-
65
- class CompressedBlockInputStream(BlockInputStream):
66
- def __init__(self, fin, context):
67
- self.raw_fin = fin
68
- fin = CompressedBufferedReader(self.read_block, BUFFER_SIZE)
69
- super(CompressedBlockInputStream, self).__init__(fin, context)
70
-
71
- def get_compressed_hash(self, data):
72
- return CityHash128(data)
73
-
74
- def read_block(self):
75
- compressed_hash = read_binary_uint128(self.raw_fin)
76
- method_byte = read_binary_uint8(self.raw_fin)
77
-
78
- decompressor_cls = get_decompressor_cls(method_byte)
79
- decompressor = decompressor_cls(self.raw_fin)
80
-
81
- if decompressor.method_byte is not None:
82
- extra_header_size = 1 # method
83
- else:
84
- extra_header_size = 0
85
-
86
- return decompressor.get_decompressed_data(
87
- method_byte, compressed_hash, extra_header_size
88
- )
1
+ from io import BytesIO
2
+
3
+ try:
4
+ from clickhouse_cityhash.cityhash import CityHash128
5
+ except ImportError:
6
+ raise RuntimeError(
7
+ 'Package clickhouse-cityhash is required to use compression'
8
+ )
9
+
10
+ from .native import BlockOutputStream, BlockInputStream
11
+ from ..bufferedreader import CompressedBufferedReader
12
+ from ..bufferedwriter import CompressedBufferedWriter
13
+ from ..compression import get_decompressor_cls
14
+ from ..defines import BUFFER_SIZE
15
+ from ..reader import read_binary_uint8, read_binary_uint128
16
+ from ..writer import write_binary_uint8, write_binary_uint128
17
+
18
+
19
+ class CompressedBlockOutputStream(BlockOutputStream):
20
+ def __init__(self, compressor_cls, compress_block_size, fout, context):
21
+ self.compressor_cls = compressor_cls
22
+ self.compress_block_size = compress_block_size
23
+ self.raw_fout = fout
24
+
25
+ self.compressor = self.compressor_cls()
26
+ self.fout = CompressedBufferedWriter(self.compressor, BUFFER_SIZE)
27
+ super(CompressedBlockOutputStream, self).__init__(self.fout, context)
28
+
29
+ def get_compressed_hash(self, data):
30
+ return CityHash128(data)
31
+
32
+ def finalize(self):
33
+ self.fout.flush()
34
+
35
+ compressed = self.get_compressed()
36
+ compressed_size = len(compressed)
37
+
38
+ compressed_hash = self.get_compressed_hash(compressed)
39
+ write_binary_uint128(compressed_hash, self.raw_fout)
40
+
41
+ block_size = self.compress_block_size
42
+
43
+ i = 0
44
+ while i < compressed_size:
45
+ self.raw_fout.write(compressed[i:i + block_size])
46
+ i += block_size
47
+
48
+ self.raw_fout.flush()
49
+
50
+ def get_compressed(self):
51
+ compressed = BytesIO()
52
+
53
+ if self.compressor.method_byte is not None:
54
+ write_binary_uint8(self.compressor.method_byte, compressed)
55
+ extra_header_size = 1 # method
56
+ else:
57
+ extra_header_size = 0
58
+
59
+ data = self.compressor.get_compressed_data(extra_header_size)
60
+ compressed.write(data)
61
+
62
+ return compressed.getvalue()
63
+
64
+
65
+ class CompressedBlockInputStream(BlockInputStream):
66
+ def __init__(self, fin, context):
67
+ self.raw_fin = fin
68
+ fin = CompressedBufferedReader(self.read_block, BUFFER_SIZE)
69
+ super(CompressedBlockInputStream, self).__init__(fin, context)
70
+
71
+ def get_compressed_hash(self, data):
72
+ return CityHash128(data)
73
+
74
+ def read_block(self):
75
+ compressed_hash = read_binary_uint128(self.raw_fin)
76
+ method_byte = read_binary_uint8(self.raw_fin)
77
+
78
+ decompressor_cls = get_decompressor_cls(method_byte)
79
+ decompressor = decompressor_cls(self.raw_fin)
80
+
81
+ if decompressor.method_byte is not None:
82
+ extra_header_size = 1 # method
83
+ else:
84
+ extra_header_size = 0
85
+
86
+ return decompressor.get_decompressed_data(
87
+ method_byte, compressed_hash, extra_header_size
88
+ )
@@ -1,90 +1,108 @@
1
- from ..block import ColumnOrientedBlock, BlockInfo
2
- from ..columns.service import read_column, write_column
3
- from ..reader import read_binary_str
4
- from ..varint import write_varint, read_varint
5
- from ..writer import write_binary_str
6
- from .. import defines
7
-
8
-
9
- class BlockOutputStream(object):
10
- def __init__(self, fout, context):
11
- self.fout = fout
12
- self.context = context
13
-
14
- super(BlockOutputStream, self).__init__()
15
-
16
- def write(self, block):
17
- revision = self.context.server_info.revision
18
- if revision >= defines.DBMS_MIN_REVISION_WITH_BLOCK_INFO:
19
- block.info.write(self.fout)
20
-
21
- # We write transposed data.
22
- n_columns = block.num_columns
23
- n_rows = block.num_rows
24
-
25
- write_varint(n_columns, self.fout)
26
- write_varint(n_rows, self.fout)
27
-
28
- for i, (col_name, col_type) in enumerate(block.columns_with_types):
29
- write_binary_str(col_name, self.fout)
30
- write_binary_str(col_type, self.fout)
31
-
32
- if n_columns:
33
- try:
34
- items = block.get_column_by_index(i)
35
- except IndexError:
36
- raise ValueError('Different rows length')
37
-
38
- write_column(self.context, col_name, col_type, items,
39
- self.fout, types_check=block.types_check)
40
-
41
- self.finalize()
42
-
43
- def finalize(self):
44
- self.fout.flush()
45
-
46
-
47
- class BlockInputStream(object):
48
- def __init__(self, fin, context):
49
- self.fin = fin
50
- self.context = context
51
-
52
- super(BlockInputStream, self).__init__()
53
-
54
- def read(self):
55
- info = BlockInfo()
56
-
57
- revision = self.context.server_info.revision
58
- if revision >= defines.DBMS_MIN_REVISION_WITH_BLOCK_INFO:
59
- info.read(self.fin)
60
-
61
- n_columns = read_varint(self.fin)
62
- n_rows = read_varint(self.fin)
63
-
64
- data, names, types = [], [], []
65
-
66
- for i in range(n_columns):
67
- column_name = read_binary_str(self.fin)
68
- column_type = read_binary_str(self.fin)
69
-
70
- names.append(column_name)
71
- types.append(column_type)
72
-
73
- if n_rows:
74
- column = read_column(self.context, column_type, n_rows,
75
- self.fin)
76
- data.append(column)
77
-
78
- if self.context.client_settings['use_numpy']:
79
- from ..numpy.block import NumpyColumnOrientedBlock
80
- block_cls = NumpyColumnOrientedBlock
81
- else:
82
- block_cls = ColumnOrientedBlock
83
-
84
- block = block_cls(
85
- columns_with_types=list(zip(names, types)),
86
- data=data,
87
- info=info,
88
- )
89
-
90
- return block
1
+ import logging
2
+
3
+ from ..block import ColumnOrientedBlock, BlockInfo
4
+ from ..columns.service import read_column, write_column
5
+ from ..reader import read_binary_str, read_binary_uint8
6
+ from ..varint import write_varint, read_varint
7
+ from ..writer import write_binary_str, write_binary_uint8
8
+ from .. import defines
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class BlockOutputStream(object):
14
+ def __init__(self, fout, context):
15
+ self.fout = fout
16
+ self.context = context
17
+
18
+ super(BlockOutputStream, self).__init__()
19
+
20
+ def write(self, block):
21
+ revision = self.context.server_info.used_revision
22
+ if revision >= defines.DBMS_MIN_REVISION_WITH_BLOCK_INFO:
23
+ block.info.write(self.fout)
24
+
25
+ # We write transposed data.
26
+ n_columns = block.num_columns
27
+ n_rows = block.num_rows
28
+
29
+ write_varint(n_columns, self.fout)
30
+ write_varint(n_rows, self.fout)
31
+
32
+ for i, (col_name, col_type) in enumerate(block.columns_with_types):
33
+ write_binary_str(col_name, self.fout)
34
+ write_binary_str(col_type, self.fout)
35
+
36
+ if n_columns:
37
+ try:
38
+ items = block.get_column_by_index(i)
39
+ except IndexError:
40
+ raise ValueError('Different rows length')
41
+
42
+ if revision >= \
43
+ defines.DBMS_MIN_REVISION_WITH_CUSTOM_SERIALIZATION:
44
+ # We write always sparse data without custom serialization.
45
+ write_binary_uint8(0, self.fout)
46
+
47
+ logger.debug('Writing column %s', col_name)
48
+ write_column(self.context, col_name, col_type, items,
49
+ self.fout, types_check=block.types_check)
50
+
51
+ self.finalize()
52
+
53
+ def finalize(self):
54
+ self.fout.flush()
55
+
56
+
57
+ class BlockInputStream(object):
58
+ def __init__(self, fin, context):
59
+ self.fin = fin
60
+ self.context = context
61
+
62
+ super(BlockInputStream, self).__init__()
63
+
64
+ def read(self, use_numpy=None):
65
+ info = BlockInfo()
66
+
67
+ revision = self.context.server_info.used_revision
68
+ if revision >= defines.DBMS_MIN_REVISION_WITH_BLOCK_INFO:
69
+ info.read(self.fin)
70
+
71
+ n_columns = read_varint(self.fin)
72
+ n_rows = read_varint(self.fin)
73
+
74
+ data, names, types = [], [], []
75
+
76
+ for i in range(n_columns):
77
+ column_name = read_binary_str(self.fin)
78
+ column_type = read_binary_str(self.fin)
79
+
80
+ names.append(column_name)
81
+ types.append(column_type)
82
+
83
+ has_custom_serialization = False
84
+ if revision >= defines.DBMS_MIN_REVISION_WITH_CUSTOM_SERIALIZATION:
85
+ has_custom_serialization = bool(read_binary_uint8(self.fin))
86
+
87
+ if n_rows:
88
+ logger.debug('Reading column %s', column_name)
89
+ column = read_column(
90
+ self.context, column_type, n_rows,
91
+ self.fin, use_numpy=use_numpy,
92
+ has_custom_serialization=has_custom_serialization
93
+ )
94
+ data.append(column)
95
+
96
+ if self.context.client_settings['use_numpy']:
97
+ from ..numpy.block import NumpyColumnOrientedBlock
98
+ block_cls = NumpyColumnOrientedBlock
99
+ else:
100
+ block_cls = ColumnOrientedBlock
101
+
102
+ block = block_cls(
103
+ columns_with_types=list(zip(names, types)),
104
+ data=data,
105
+ info=info,
106
+ )
107
+
108
+ return block
@@ -0,0 +1,39 @@
1
+
2
+ # Drop this when minimum supported version will be 3.7.
3
+ try:
4
+ import threading
5
+ except ImportError:
6
+ import dummy_threading as threading # noqa: F401
7
+
8
+ import json # noqa: F401
9
+ try:
10
+ import orjson as json # noqa: F811
11
+ except ImportError:
12
+ pass
13
+
14
+ try:
15
+ import ujson as json # noqa: F811,F401
16
+ except ImportError:
17
+ pass
18
+
19
+
20
+ try:
21
+ # since tzlocal 4.0+
22
+ # this will avoid warning for get_localzone().key
23
+ from tzlocal import get_localzone_name
24
+
25
+ def get_localzone_name_compat():
26
+ try:
27
+ return get_localzone_name()
28
+ except Exception:
29
+ return None
30
+ except ImportError:
31
+ from tzlocal import get_localzone
32
+
33
+ def get_localzone_name_compat():
34
+ try:
35
+ return get_localzone().key
36
+ except AttributeError:
37
+ return get_localzone().zone
38
+ except Exception:
39
+ return None