chtypes 2.0.0.dev8__py3-none-any.whl → 2.0.0.dev9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
chtypes/_decode.py CHANGED
@@ -431,8 +431,9 @@ def decode_batch(raw: bytes, export: bytes | None) -> BatchResult:
431
431
  export_declined = _bytes(obj, "export_declined", where)
432
432
  if export_declined:
433
433
  # A declined export has no payload and no spans, whatever buffer the call
434
- # returned: the library may hand back a zero-length one, so the document's
435
- # export_declined decides, never the buffer's length.
434
+ # returned: the library returns a NULL out_export for it (builds up to
435
+ # 20261011.105019 returned a zero-length buffer), and the document's
436
+ # export_declined decides, never the buffer.
436
437
  export, spans = None, None
437
438
  return BatchResult(
438
439
  outcome=Outcome.of(_text(obj, "outcome", where)),
chtypes/_input.py CHANGED
@@ -45,6 +45,31 @@ def body_bytes(value: bytes, what: str = "body") -> bytes:
45
45
  raise TypeError(f"{what} must be bytes, not {type(value).__name__}")
46
46
 
47
47
 
48
+ _NON_UTF8_HINT = (
49
+ "this ABI generation cannot carry a non-UTF-8 value in a JSON input; "
50
+ "write the bytes as unhex('<hex>') in the expression instead"
51
+ )
52
+
53
+
54
+ def _is_utf8(text: str) -> bool:
55
+ """False for a `str` that cannot be UTF-8 encoded (a lone surrogate, as
56
+ `surrogateescape` makes of undecodable bytes)."""
57
+ try:
58
+ text.encode("utf-8")
59
+ except UnicodeEncodeError:
60
+ return False
61
+ return True
62
+
63
+
64
+ def _refuse_non_utf8(what: str, part: str, key: str) -> Exception:
65
+ # The key is shown escaped (ASCII only), never as the raw text.
66
+ return misuse(
67
+ f"{what}: the key {json.dumps(key)} is not valid UTF-8, and {_NON_UTF8_HINT}"
68
+ if part == "key"
69
+ else f"{what}: the value for key {json.dumps(key)} is not valid UTF-8, and {_NON_UTF8_HINT}"
70
+ )
71
+
72
+
48
73
  def _string_map(mapping: Mapping[str, str], what: str) -> dict[str, str]:
49
74
  out: dict[str, str] = {}
50
75
  for key, value in mapping.items():
@@ -53,6 +78,12 @@ def _string_map(mapping: Mapping[str, str], what: str) -> dict[str, str]:
53
78
  f"{what} maps strings to strings only; got {type(key).__name__} -> "
54
79
  f"{type(value).__name__} for {key!r} (a value is never rewritten)"
55
80
  )
81
+ # json.dumps would write a lone surrogate as a \udXXX escape, a value
82
+ # the library does not read as the bytes the caller meant: refuse.
83
+ if not _is_utf8(key):
84
+ raise _refuse_non_utf8(what, "key", key)
85
+ if not _is_utf8(value):
86
+ raise _refuse_non_utf8(what, "value", key)
56
87
  out[key] = value
57
88
  return out
58
89
 
@@ -75,6 +106,8 @@ def settings_json(
75
106
  if session_timezone is not None:
76
107
  if not isinstance(session_timezone, str):
77
108
  raise TypeError(f"session_timezone must be str, not {type(session_timezone).__name__}")
109
+ if not _is_utf8(session_timezone):
110
+ raise misuse(f"the zone: the value is not valid UTF-8, and {_NON_UTF8_HINT}")
78
111
  if _ZONE_KEY in merged:
79
112
  raise misuse(
80
113
  f"the {_ZONE_KEY} option and a {_ZONE_KEY} settings key were both given; "
@@ -141,10 +174,12 @@ def server_profile_json(profile: ServerProfile) -> bytes:
141
174
  if profile.timezone is not None:
142
175
  if not isinstance(profile.timezone, str):
143
176
  raise TypeError(f"timezone must be str, not {type(profile.timezone).__name__}")
177
+ if not _is_utf8(profile.timezone):
178
+ raise misuse(f"server profile: the timezone is not valid UTF-8, and {_NON_UTF8_HINT}")
144
179
  if profile.timezone != "":
145
180
  doc["timezone"] = profile.timezone
146
181
  if profile.settings is not None:
147
- doc["settings"] = _string_map(profile.settings, "settings")
182
+ doc["settings"] = _string_map(profile.settings, "server profile settings")
148
183
  if profile.macros is not None:
149
- doc["macros"] = _string_map(profile.macros, "macros")
184
+ doc["macros"] = _string_map(profile.macros, "server profile macros")
150
185
  return _dump(doc)
chtypes/library.py CHANGED
@@ -296,7 +296,7 @@ class Schema(_Handle):
296
296
  zone is its own, fixed here: its WHERE runs in the session this call's
297
297
  `session_timezone` (or `settings`) names, on every evaluation."""
298
298
  expr_bytes = to_bytes(expr, "expr")
299
- params_bytes = string_map_json(params, "params")
299
+ params_bytes = string_map_json(params, "query parameters")
300
300
  settings_bytes = settings_json(settings, session_timezone)
301
301
  with _hold(self._guard):
302
302
  handle = self._library._api.filter_create(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: chtypes
3
- Version: 2.0.0.dev8
3
+ Version: 2.0.0.dev9
4
4
  Summary: Python binding for the chtypes artifacts: ClickHouse's own type system, per version, behind the frozen chs_* C ABI
5
5
  Project-URL: Homepage, https://github.com/wave-rf/chtypes
6
6
  Project-URL: Repository, https://github.com/wave-rf/chtypes
@@ -1,13 +1,13 @@
1
1
  chtypes/__init__.py,sha256=nYd9hTbAU8ffzVj5mYqUAEWxzfYg-67zW_h0j5XasMA,6187
2
2
  chtypes/__main__.py,sha256=mrpF3Cf0_l-ODhqVzrN8JwwjG64glJ__Soehs6-ALu8,18081
3
3
  chtypes/_codes.py,sha256=yiLLEiJDJ20WseyFZE1VzlqSiL9J8GC8JMj8tKXCZss,1238
4
- chtypes/_decode.py,sha256=NV5IgBsAJuEqYD5u2SBZIlDSQnAe4t_ckSBRAG0x1jM,23208
4
+ chtypes/_decode.py,sha256=ta2D6gDu6JOxYacypT5emt3MCdWp5gCZlcyPz0k1Dzo,23272
5
5
  chtypes/_ed25519.py,sha256=uwaAKWvgoc936e1ZfgLrtR47W87WWCL541kFaqBXrB0,4141
6
6
  chtypes/_guard.py,sha256=kVgvxRWu7H-eba3hTqPBmpqjxOCWdQGwiFAHvSnl1OU,1996
7
- chtypes/_input.py,sha256=VBNIUeDSEsq6EvgFW63UJt0kyAOSYJpb1nQOXvUQbOI,6031
7
+ chtypes/_input.py,sha256=NczeJ6LR7gRc_dhgccv5zcrKlZ4nkh3wP0TBx5vHIbw,7468
8
8
  chtypes/_setup.py,sha256=7mXvPxLCHS9h1FRWNr5uKfCUg-Gk8VjmC-5KNW5HogI,6125
9
9
  chtypes/errors.py,sha256=uDs-M2NQpacoJK-LiWQDM_s5v_Jbm3tbyWduqvLgsyI,9410
10
- chtypes/library.py,sha256=G6DJFiRuv8--JARxfiSNEqeFLkafaMs_n9nG-IwoC74,17878
10
+ chtypes/library.py,sha256=MurZz2CFLwm_lRMC_0X4SZNDNIlkwbdqKW7oFTl2XWc,17888
11
11
  chtypes/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  chtypes/registry.py,sha256=GozFQresMLLG0JmCD_rVtOgtNZzl9fgT0O7jQMsnHCE,21945
13
13
  chtypes/results.py,sha256=gue7f4pqnpvXlSteYqhmqU1ZuAYCD7p4AgTiuYWpgYY,12591
@@ -35,8 +35,8 @@ chtypes/_ocifetch/_referrers.py,sha256=J2b4gN6vryz_IzYHxrd2Tp-tQO9Cz766rZtKgCVcK
35
35
  chtypes/_ocifetch/_resolve.py,sha256=Qv8xFUdOR-Kb_JqmUeDiQ4_Xv2ETuNFpmoDckMp7eV8,11239
36
36
  chtypes/_ocifetch/_retired.py,sha256=MQ6nbWLJw50IZYY1VfM6AiCZ4BySK0GVkGVOtAXaq3Y,3060
37
37
  chtypes/_ocifetch/_unpack.py,sha256=Cn4-up63KL63L8pnkS5zwJ6VbbHPSigpCnmOdcHJ4RI,5609
38
- chtypes-2.0.0.dev8.dist-info/METADATA,sha256=IySGKPKxLdX-9HnkivYd1uK7-qQdwylgbljzw7XyNCs,11315
39
- chtypes-2.0.0.dev8.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
40
- chtypes-2.0.0.dev8.dist-info/entry_points.txt,sha256=TdNcluWBR0VOt5mVFROsp-NiVPAdR3EHo0UsHlMC0r0,50
41
- chtypes-2.0.0.dev8.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
42
- chtypes-2.0.0.dev8.dist-info/RECORD,,
38
+ chtypes-2.0.0.dev9.dist-info/METADATA,sha256=AqDs8WwXXigXIHHi0XGvpM5IpTTJSC9vHqHwESJF0H8,11315
39
+ chtypes-2.0.0.dev9.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
40
+ chtypes-2.0.0.dev9.dist-info/entry_points.txt,sha256=TdNcluWBR0VOt5mVFROsp-NiVPAdR3EHo0UsHlMC0r0,50
41
+ chtypes-2.0.0.dev9.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
42
+ chtypes-2.0.0.dev9.dist-info/RECORD,,