trodo-python 2.22.0__py3-none-any.whl → 2.23.0__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.
trodo/prompts/compile.py CHANGED
@@ -36,6 +36,36 @@ def _q(value: Any) -> str:
36
36
  except (TypeError, ValueError):
37
37
  return repr(value)
38
38
 
39
+ def _js_string(value: Any) -> str:
40
+ """JavaScript ``String()`` semantics, byte-for-byte.
41
+
42
+ A non-string passed for a string-typed variable is a caller type mismatch,
43
+ but all three engines must agree on what it renders as -- the backend
44
+ reference (which powers the playground) and the Node SDK both go through
45
+ JS ``String()``, so ``True`` must render ``true``, ``3.0`` must render
46
+ ``3``, a list joins with commas, and a dict renders the infamous
47
+ ``[object Object]``. The JSON rendering callers actually want lives on the
48
+ ``json`` variable type, where all three engines already emit compact JSON.
49
+ """
50
+ if value is None:
51
+ return ""
52
+ if isinstance(value, bool):
53
+ return "true" if value else "false"
54
+ if isinstance(value, float) and value.is_integer() and abs(value) < 1e21:
55
+ return str(int(value))
56
+ if isinstance(value, (int, float)):
57
+ return str(value)
58
+ if isinstance(value, str):
59
+ return value
60
+ if isinstance(value, (list, tuple)):
61
+ # Array.prototype.toString: elements joined by ',', null/undefined
62
+ # rendering empty, recursively.
63
+ return ",".join(_js_string(x) for x in value)
64
+ if isinstance(value, dict):
65
+ return "[object Object]"
66
+ return str(value)
67
+
68
+
39
69
  def _coerce(value: Any, type_: str, name: str, errors: List[str]) -> Any:
40
70
  """Coerce a caller value to the declared type.
41
71
 
@@ -71,7 +101,7 @@ def _coerce(value: Any, type_: str, name: str, errors: List[str]) -> Any:
71
101
  return value
72
102
 
73
103
  if type_ == "string":
74
- return value if isinstance(value, str) else str(value)
104
+ return value if isinstance(value, str) else _js_string(value)
75
105
 
76
106
  if type_ == "messages":
77
107
  if not isinstance(value, list):
@@ -119,7 +149,13 @@ def build_scope(
119
149
  # empty. That IS the point of declaring a default -- there is no third
120
150
  # case where the caller has to have supplied something, and adding one
121
151
  # would turn an empty render into a crash for no gain.
122
- if not has or value is None:
152
+ #
153
+ # The default applies to an ABSENT key only. An explicit ``None`` is a
154
+ # value -- "render this empty" -- exactly as ``null`` is in the backend
155
+ # reference engine and the Node SDK. This engine used to substitute the
156
+ # default for an explicit ``None``, so the same call rendered different
157
+ # text in Python than everywhere else, including the playground.
158
+ if not has:
123
159
  value = default if has_default else ([] if type_ == "messages" else "")
124
160
 
125
161
  scope[name] = _coerce(value, type_, name, errors)
trodo/prompts/template.py CHANGED
@@ -159,6 +159,21 @@ def _lookup(path: str, scopes: Sequence[Any]) -> Tuple[bool, Any]:
159
159
  return False, None
160
160
 
161
161
 
162
+ def _jsonable(value):
163
+ """Normalise for JSON.stringify parity: JS has one number type, so a float
164
+ that is a whole number must serialise as ``1`` and not ``1.0`` -- at any
165
+ depth. Everything else passes through untouched."""
166
+ if isinstance(value, bool):
167
+ return value
168
+ if isinstance(value, float) and value.is_integer() and abs(value) < 1e21:
169
+ return int(value)
170
+ if isinstance(value, dict):
171
+ return {k: _jsonable(v) for k, v in value.items()}
172
+ if isinstance(value, (list, tuple)):
173
+ return [_jsonable(v) for v in value]
174
+ return value
175
+
176
+
162
177
  def _stringify(value: Any) -> str:
163
178
  if value is None:
164
179
  return ""
@@ -173,7 +188,7 @@ def _stringify(value: Any) -> str:
173
188
  return str(int(value))
174
189
  return str(value)
175
190
  try:
176
- return json.dumps(value, separators=(",", ":"))
191
+ return json.dumps(_jsonable(value), separators=(",", ":"), ensure_ascii=False)
177
192
  except (TypeError, ValueError):
178
193
  return str(value)
179
194
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trodo-python
3
- Version: 2.22.0
3
+ Version: 2.23.0
4
4
  Summary: Trodo Analytics SDK for Python — server-side event tracking
5
5
  License: ISC
6
6
  Keywords: analytics,tracking,trodo,server-side
@@ -25,8 +25,8 @@ trodo/otel/register.py,sha256=bV_ePTfUvPugig2GZnylhzxi2QfoPWs96A9mGLPMrSQ,9387
25
25
  trodo/otel/transport.py,sha256=hzZz8gwSMGJ8CxdijmLn1Ljt18owr9XTWy13DLbwYbw,2441
26
26
  trodo/otel/wrap_agent.py,sha256=Izty1jxF4ANVqS72L0CR9jmMuW372AApaEO_0LC5Thw,43860
27
27
  trodo/prompts/__init__.py,sha256=yunNc8WkTSfEEkRR-NZWXAt_ZB3Ee2INRh-4RE7uHj4,806
28
- trodo/prompts/compile.py,sha256=fAYq55LdGIvglNVCnBF3YXyM8W9raLku1M8OAzaQExE,7135
29
- trodo/prompts/template.py,sha256=obQiivPCR6LEdz7q1cby7uL25tYHYui4aoEaiUNqWfs,9357
28
+ trodo/prompts/compile.py,sha256=XoKDKz6Yaofhrk-87AVW-SnwbiXLvfp161AL2bAFzNY,8802
29
+ trodo/prompts/template.py,sha256=eGO2ZVNOw6JK7Ffj1UCYDMJFYyX5qQW2POlmFJSQpAo,9975
30
30
  trodo/prompts/types.py,sha256=OYpaLi1H9pJjeq0gsJo8eb-bWoF8rw2u_7pdukudtqo,5258
31
31
  trodo/queue/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  trodo/queue/batch_flusher.py,sha256=4Lg6T3Urwi9U0Q4FpFGPmjDYKg4ZliCTR-ND8BJvWaY,1298
@@ -36,7 +36,7 @@ trodo/session/server_session.py,sha256=McsudEiq33XDq3nqxgzBcUvIjQxCMscwEuAPnYXrT
36
36
  trodo/session/session_manager.py,sha256=7ht5LeeZX1HLLfPeNV_a8NkXGbHl3up0CRtCGr3EzjQ,2995
37
37
  trodo/util/__init__.py,sha256=Z9c4rPPdKg06Kk3byKheDqksSgR4WNvS475oQ5sNljc,54
38
38
  trodo/util/lru.py,sha256=QIsM7s6J_E9ZjiXatSyReZIEeGypTAcgrPWWy8YsRa4,2465
39
- trodo_python-2.22.0.dist-info/METADATA,sha256=RmvsK5vGdIvPBMeZqjANQygwnolV11Hb4006GzI6Xcg,25308
40
- trodo_python-2.22.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
41
- trodo_python-2.22.0.dist-info/top_level.txt,sha256=VCQu1CJWFmNsqTs1YxMcw4Mq35Tc3z3uI9RwHEXAayQ,6
42
- trodo_python-2.22.0.dist-info/RECORD,,
39
+ trodo_python-2.23.0.dist-info/METADATA,sha256=HklaG2r4SZNydUnzdRUluF9KLh1d-IszAlS1Sr4UEFI,25308
40
+ trodo_python-2.23.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
41
+ trodo_python-2.23.0.dist-info/top_level.txt,sha256=VCQu1CJWFmNsqTs1YxMcw4Mq35Tc3z3uI9RwHEXAayQ,6
42
+ trodo_python-2.23.0.dist-info/RECORD,,