@tracecode/harness 0.4.0
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.
- package/CHANGELOG.md +113 -0
- package/LICENSE +674 -0
- package/README.md +266 -0
- package/dist/browser.cjs +1352 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +49 -0
- package/dist/browser.d.ts +49 -0
- package/dist/browser.js +1317 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli.cjs +70 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +70 -0
- package/dist/cli.js.map +1 -0
- package/dist/core.cjs +286 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +69 -0
- package/dist/core.d.ts +69 -0
- package/dist/core.js +254 -0
- package/dist/core.js.map +1 -0
- package/dist/index.cjs +2603 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +2538 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/browser.cjs +647 -0
- package/dist/internal/browser.cjs.map +1 -0
- package/dist/internal/browser.d.cts +143 -0
- package/dist/internal/browser.d.ts +143 -0
- package/dist/internal/browser.js +617 -0
- package/dist/internal/browser.js.map +1 -0
- package/dist/javascript.cjs +549 -0
- package/dist/javascript.cjs.map +1 -0
- package/dist/javascript.d.cts +11 -0
- package/dist/javascript.d.ts +11 -0
- package/dist/javascript.js +518 -0
- package/dist/javascript.js.map +1 -0
- package/dist/python.cjs +744 -0
- package/dist/python.cjs.map +1 -0
- package/dist/python.d.cts +97 -0
- package/dist/python.d.ts +97 -0
- package/dist/python.js +698 -0
- package/dist/python.js.map +1 -0
- package/dist/runtime-types-C7d1LFbx.d.ts +85 -0
- package/dist/runtime-types-Dvgn07z9.d.cts +85 -0
- package/dist/types-Bzr1Ohcf.d.cts +96 -0
- package/dist/types-Bzr1Ohcf.d.ts +96 -0
- package/package.json +89 -0
- package/workers/javascript/javascript-worker.js +2918 -0
- package/workers/python/generated-python-harness-snippets.js +20 -0
- package/workers/python/pyodide-worker.js +1197 -0
- package/workers/python/runtime-core.js +1529 -0
- package/workers/vendor/typescript.js +200276 -0
package/dist/python.js
ADDED
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
// packages/harness-python/src/generated/python-harness-snippets.ts
|
|
2
|
+
function toPythonLiteral(value) {
|
|
3
|
+
if (value === null || value === void 0) {
|
|
4
|
+
return "None";
|
|
5
|
+
}
|
|
6
|
+
if (typeof value === "boolean") {
|
|
7
|
+
return value ? "True" : "False";
|
|
8
|
+
}
|
|
9
|
+
if (typeof value === "number") {
|
|
10
|
+
return String(value);
|
|
11
|
+
}
|
|
12
|
+
if (typeof value === "string") {
|
|
13
|
+
return JSON.stringify(value);
|
|
14
|
+
}
|
|
15
|
+
if (Array.isArray(value)) {
|
|
16
|
+
return "[" + value.map(toPythonLiteral).join(", ") + "]";
|
|
17
|
+
}
|
|
18
|
+
if (typeof value === "object") {
|
|
19
|
+
const entries = Object.entries(value).map(([k, v]) => `${JSON.stringify(k)}: ${toPythonLiteral(v)}`).join(", ");
|
|
20
|
+
return "{" + entries + "}";
|
|
21
|
+
}
|
|
22
|
+
return JSON.stringify(value);
|
|
23
|
+
}
|
|
24
|
+
var PYTHON_CLASS_DEFINITIONS = `
|
|
25
|
+
class TreeNode:
|
|
26
|
+
def __init__(self, val=0, left=None, right=None):
|
|
27
|
+
self.val = val
|
|
28
|
+
self.value = val
|
|
29
|
+
self.left = left
|
|
30
|
+
self.right = right
|
|
31
|
+
def __getitem__(self, key):
|
|
32
|
+
if key == 'val': return getattr(self, 'val', getattr(self, 'value', None))
|
|
33
|
+
if key == 'value': return getattr(self, 'value', getattr(self, 'val', None))
|
|
34
|
+
if key == 'left': return self.left
|
|
35
|
+
if key == 'right': return self.right
|
|
36
|
+
raise KeyError(key)
|
|
37
|
+
def get(self, key, default=None):
|
|
38
|
+
if key == 'val': return getattr(self, 'val', getattr(self, 'value', default))
|
|
39
|
+
if key == 'value': return getattr(self, 'value', getattr(self, 'val', default))
|
|
40
|
+
if key == 'left': return self.left
|
|
41
|
+
if key == 'right': return self.right
|
|
42
|
+
return default
|
|
43
|
+
def __repr__(self):
|
|
44
|
+
return f"TreeNode({getattr(self, 'val', getattr(self, 'value', None))})"
|
|
45
|
+
|
|
46
|
+
class ListNode:
|
|
47
|
+
def __init__(self, val=0, next=None):
|
|
48
|
+
self.val = val
|
|
49
|
+
self.value = val
|
|
50
|
+
self.next = next
|
|
51
|
+
def __getitem__(self, key):
|
|
52
|
+
if key == 'val': return getattr(self, 'val', getattr(self, 'value', None))
|
|
53
|
+
if key == 'value': return getattr(self, 'value', getattr(self, 'val', None))
|
|
54
|
+
if key == 'next': return self.next
|
|
55
|
+
raise KeyError(key)
|
|
56
|
+
def get(self, key, default=None):
|
|
57
|
+
if key == 'val': return getattr(self, 'val', getattr(self, 'value', default))
|
|
58
|
+
if key == 'value': return getattr(self, 'value', getattr(self, 'val', default))
|
|
59
|
+
if key == 'next': return self.next
|
|
60
|
+
return default
|
|
61
|
+
def __repr__(self):
|
|
62
|
+
return f"ListNode({getattr(self, 'val', getattr(self, 'value', None))})"
|
|
63
|
+
`;
|
|
64
|
+
var PYTHON_CONVERSION_HELPERS = "\ndef _ensure_node_value_aliases(node):\n if node is None:\n return node\n try:\n has_val = hasattr(node, 'val')\n has_value = hasattr(node, 'value')\n if has_value and not has_val:\n try:\n setattr(node, 'val', getattr(node, 'value'))\n except Exception:\n pass\n elif has_val and not has_value:\n try:\n setattr(node, 'value', getattr(node, 'val'))\n except Exception:\n pass\n except Exception:\n pass\n return node\n\ndef _dict_to_tree(d):\n if d is None:\n return None\n if not isinstance(d, dict):\n return d\n if 'val' not in d and 'value' not in d:\n return d\n node = TreeNode(d.get('val', d.get('value', 0)))\n _ensure_node_value_aliases(node)\n node.left = _dict_to_tree(d.get('left'))\n node.right = _dict_to_tree(d.get('right'))\n return node\n\ndef _dict_to_list(d, _refs=None):\n if _refs is None:\n _refs = {}\n if d is None:\n return None\n if not isinstance(d, dict):\n return d\n if '__ref__' in d:\n return _refs.get(d.get('__ref__'))\n if 'val' not in d and 'value' not in d:\n return d\n node = ListNode(d.get('val', d.get('value', 0)))\n _ensure_node_value_aliases(node)\n node_id = d.get('__id__')\n if isinstance(node_id, str) and node_id:\n _refs[node_id] = node\n node.next = _dict_to_list(d.get('next'), _refs)\n return node\n";
|
|
65
|
+
var PYTHON_TRACE_SERIALIZE_FUNCTION = `
|
|
66
|
+
# Sentinel to mark skipped values (functions, etc.) - distinct from None
|
|
67
|
+
_SKIP_SENTINEL = "__TRACECODE_SKIP__"
|
|
68
|
+
_MAX_SERIALIZE_DEPTH = 48
|
|
69
|
+
|
|
70
|
+
def _serialize(obj, depth=0, node_refs=None):
|
|
71
|
+
if node_refs is None:
|
|
72
|
+
node_refs = {}
|
|
73
|
+
if isinstance(obj, (bool, int, str, type(None))):
|
|
74
|
+
return obj
|
|
75
|
+
elif isinstance(obj, float):
|
|
76
|
+
if not math.isfinite(obj):
|
|
77
|
+
if math.isnan(obj):
|
|
78
|
+
return "NaN"
|
|
79
|
+
return "Infinity" if obj > 0 else "-Infinity"
|
|
80
|
+
return obj
|
|
81
|
+
if depth > _MAX_SERIALIZE_DEPTH:
|
|
82
|
+
return "<max depth>"
|
|
83
|
+
elif isinstance(obj, (list, tuple)):
|
|
84
|
+
return [_serialize(x, depth + 1, node_refs) for x in obj]
|
|
85
|
+
elif getattr(obj, '__class__', None) and getattr(obj.__class__, '__name__', '') == 'deque':
|
|
86
|
+
return [_serialize(x, depth + 1, node_refs) for x in obj]
|
|
87
|
+
elif isinstance(obj, dict):
|
|
88
|
+
return {str(k): _serialize(v, depth + 1, node_refs) for k, v in obj.items()}
|
|
89
|
+
elif isinstance(obj, set):
|
|
90
|
+
# Use try/except for sorting to handle heterogeneous sets
|
|
91
|
+
try:
|
|
92
|
+
sorted_vals = sorted([_serialize(x, depth + 1, node_refs) for x in obj])
|
|
93
|
+
except TypeError:
|
|
94
|
+
sorted_vals = [_serialize(x, depth + 1, node_refs) for x in obj]
|
|
95
|
+
return {"__type__": "set", "values": sorted_vals}
|
|
96
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and (hasattr(obj, 'left') or hasattr(obj, 'right')):
|
|
97
|
+
obj_ref = id(obj)
|
|
98
|
+
if obj_ref in node_refs:
|
|
99
|
+
return {"__ref__": node_refs[obj_ref]}
|
|
100
|
+
node_id = f"tree-{obj_ref}"
|
|
101
|
+
node_refs[obj_ref] = node_id
|
|
102
|
+
result = {
|
|
103
|
+
"__type__": "TreeNode",
|
|
104
|
+
"__id__": node_id,
|
|
105
|
+
"val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1, node_refs),
|
|
106
|
+
}
|
|
107
|
+
if hasattr(obj, 'left'):
|
|
108
|
+
result["left"] = _serialize(obj.left, depth + 1, node_refs)
|
|
109
|
+
if hasattr(obj, 'right'):
|
|
110
|
+
result["right"] = _serialize(obj.right, depth + 1, node_refs)
|
|
111
|
+
return result
|
|
112
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and hasattr(obj, 'next'):
|
|
113
|
+
obj_ref = id(obj)
|
|
114
|
+
if obj_ref in node_refs:
|
|
115
|
+
return {"__ref__": node_refs[obj_ref]}
|
|
116
|
+
node_id = f"list-{obj_ref}"
|
|
117
|
+
node_refs[obj_ref] = node_id
|
|
118
|
+
result = {
|
|
119
|
+
"__type__": "ListNode",
|
|
120
|
+
"__id__": node_id,
|
|
121
|
+
"val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1, node_refs),
|
|
122
|
+
}
|
|
123
|
+
result["next"] = _serialize(obj.next, depth + 1, node_refs)
|
|
124
|
+
return result
|
|
125
|
+
elif callable(obj):
|
|
126
|
+
# Skip functions entirely - return sentinel
|
|
127
|
+
return _SKIP_SENTINEL
|
|
128
|
+
else:
|
|
129
|
+
repr_str = repr(obj)
|
|
130
|
+
# Filter out function-like representations (e.g., <function foo at 0x...>)
|
|
131
|
+
if repr_str.startswith('<') and repr_str.endswith('>'):
|
|
132
|
+
return _SKIP_SENTINEL
|
|
133
|
+
return repr_str
|
|
134
|
+
`;
|
|
135
|
+
var PYTHON_EXECUTE_SERIALIZE_FUNCTION = `
|
|
136
|
+
_MAX_SERIALIZE_DEPTH = 48
|
|
137
|
+
|
|
138
|
+
def _serialize(obj, depth=0):
|
|
139
|
+
if isinstance(obj, (bool, int, str, type(None))):
|
|
140
|
+
return obj
|
|
141
|
+
elif isinstance(obj, float):
|
|
142
|
+
if not math.isfinite(obj):
|
|
143
|
+
if math.isnan(obj):
|
|
144
|
+
return "NaN"
|
|
145
|
+
return "Infinity" if obj > 0 else "-Infinity"
|
|
146
|
+
return obj
|
|
147
|
+
if depth > _MAX_SERIALIZE_DEPTH:
|
|
148
|
+
return "<max depth>"
|
|
149
|
+
elif isinstance(obj, (list, tuple)):
|
|
150
|
+
return [_serialize(x, depth + 1) for x in obj]
|
|
151
|
+
elif getattr(obj, '__class__', None) and getattr(obj.__class__, '__name__', '') == 'deque':
|
|
152
|
+
return [_serialize(x, depth + 1) for x in obj]
|
|
153
|
+
elif isinstance(obj, dict):
|
|
154
|
+
return {str(k): _serialize(v, depth + 1) for k, v in obj.items()}
|
|
155
|
+
elif isinstance(obj, set):
|
|
156
|
+
try:
|
|
157
|
+
return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
|
|
158
|
+
except TypeError:
|
|
159
|
+
return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
|
|
160
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and (hasattr(obj, 'left') or hasattr(obj, 'right')):
|
|
161
|
+
result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
|
|
162
|
+
if hasattr(obj, 'left'):
|
|
163
|
+
result["left"] = _serialize(obj.left, depth + 1)
|
|
164
|
+
if hasattr(obj, 'right'):
|
|
165
|
+
result["right"] = _serialize(obj.right, depth + 1)
|
|
166
|
+
return result
|
|
167
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and hasattr(obj, 'next'):
|
|
168
|
+
result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
|
|
169
|
+
result["next"] = _serialize(obj.next, depth + 1)
|
|
170
|
+
return result
|
|
171
|
+
elif callable(obj):
|
|
172
|
+
return None
|
|
173
|
+
else:
|
|
174
|
+
repr_str = repr(obj)
|
|
175
|
+
if repr_str.startswith('<') and repr_str.endswith('>'):
|
|
176
|
+
return None
|
|
177
|
+
return repr_str
|
|
178
|
+
`;
|
|
179
|
+
var PYTHON_PRACTICE_MATERIALIZE_SERIALIZE_FUNCTION = `
|
|
180
|
+
def _serialize(obj, depth=0, state=None):
|
|
181
|
+
if state is None:
|
|
182
|
+
state = {"nodes": 0, "seen": set()}
|
|
183
|
+
if depth > 64:
|
|
184
|
+
return "__MAX_DEPTH__"
|
|
185
|
+
if isinstance(obj, (int, float, str, bool, type(None))):
|
|
186
|
+
return obj
|
|
187
|
+
|
|
188
|
+
state["nodes"] += 1
|
|
189
|
+
if state["nodes"] > 600:
|
|
190
|
+
return "__MAX_NODES__"
|
|
191
|
+
|
|
192
|
+
if isinstance(obj, (list, tuple)):
|
|
193
|
+
return [_serialize(x, depth + 1, state) for x in obj]
|
|
194
|
+
elif isinstance(obj, dict):
|
|
195
|
+
return {str(k): _serialize(v, depth + 1, state) for k, v in obj.items()}
|
|
196
|
+
elif isinstance(obj, set):
|
|
197
|
+
serialized = [_serialize(x, depth + 1, state) for x in obj]
|
|
198
|
+
try:
|
|
199
|
+
serialized = sorted(serialized)
|
|
200
|
+
except TypeError:
|
|
201
|
+
pass
|
|
202
|
+
return {"__type__": "set", "values": serialized}
|
|
203
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and (hasattr(obj, 'left') or hasattr(obj, 'right')):
|
|
204
|
+
obj_id = id(obj)
|
|
205
|
+
if obj_id in state["seen"]:
|
|
206
|
+
return "__CYCLE__"
|
|
207
|
+
state["seen"].add(obj_id)
|
|
208
|
+
result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1, state)}
|
|
209
|
+
if hasattr(obj, 'left'):
|
|
210
|
+
result["left"] = _serialize(obj.left, depth + 1, state)
|
|
211
|
+
if hasattr(obj, 'right'):
|
|
212
|
+
result["right"] = _serialize(obj.right, depth + 1, state)
|
|
213
|
+
state["seen"].remove(obj_id)
|
|
214
|
+
return result
|
|
215
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and hasattr(obj, 'next'):
|
|
216
|
+
obj_id = id(obj)
|
|
217
|
+
if obj_id in state["seen"]:
|
|
218
|
+
return "__CYCLE__"
|
|
219
|
+
state["seen"].add(obj_id)
|
|
220
|
+
result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1, state)}
|
|
221
|
+
result["next"] = _serialize(obj.next, depth + 1, state)
|
|
222
|
+
state["seen"].remove(obj_id)
|
|
223
|
+
return result
|
|
224
|
+
else:
|
|
225
|
+
return repr(obj)
|
|
226
|
+
`;
|
|
227
|
+
var PYTHON_INTERVIEW_MATERIALIZE_SERIALIZE_FUNCTION = `
|
|
228
|
+
def _serialize(obj, depth=0):
|
|
229
|
+
if depth > 10:
|
|
230
|
+
return "<max depth>"
|
|
231
|
+
if isinstance(obj, (int, float, str, bool, type(None))):
|
|
232
|
+
return obj
|
|
233
|
+
elif isinstance(obj, (list, tuple)):
|
|
234
|
+
return [_serialize(x, depth + 1) for x in obj]
|
|
235
|
+
elif isinstance(obj, dict):
|
|
236
|
+
return {str(k): _serialize(v, depth + 1) for k, v in obj.items()}
|
|
237
|
+
elif isinstance(obj, set):
|
|
238
|
+
try:
|
|
239
|
+
return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
|
|
240
|
+
except TypeError:
|
|
241
|
+
return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
|
|
242
|
+
elif hasattr(obj, 'val') and (hasattr(obj, 'left') or hasattr(obj, 'right')):
|
|
243
|
+
result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', None), depth + 1)}
|
|
244
|
+
if hasattr(obj, 'left'):
|
|
245
|
+
result["left"] = _serialize(obj.left, depth + 1)
|
|
246
|
+
if hasattr(obj, 'right'):
|
|
247
|
+
result["right"] = _serialize(obj.right, depth + 1)
|
|
248
|
+
return result
|
|
249
|
+
elif hasattr(obj, 'val') and hasattr(obj, 'next'):
|
|
250
|
+
result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', None), depth + 1)}
|
|
251
|
+
result["next"] = _serialize(obj.next, depth + 1)
|
|
252
|
+
return result
|
|
253
|
+
else:
|
|
254
|
+
return repr(obj)
|
|
255
|
+
`;
|
|
256
|
+
var PYTHON_SERIALIZE_FUNCTION = `
|
|
257
|
+
_MAX_SERIALIZE_DEPTH = 48
|
|
258
|
+
|
|
259
|
+
def _serialize(obj, depth=0):
|
|
260
|
+
if isinstance(obj, (bool, int, str, type(None))):
|
|
261
|
+
return obj
|
|
262
|
+
elif isinstance(obj, float):
|
|
263
|
+
if not math.isfinite(obj):
|
|
264
|
+
if math.isnan(obj):
|
|
265
|
+
return "NaN"
|
|
266
|
+
return "Infinity" if obj > 0 else "-Infinity"
|
|
267
|
+
return obj
|
|
268
|
+
if depth > _MAX_SERIALIZE_DEPTH:
|
|
269
|
+
return "<max depth>"
|
|
270
|
+
elif isinstance(obj, (list, tuple)):
|
|
271
|
+
return [_serialize(x, depth + 1) for x in obj]
|
|
272
|
+
elif getattr(obj, '__class__', None) and getattr(obj.__class__, '__name__', '') == 'deque':
|
|
273
|
+
return [_serialize(x, depth + 1) for x in obj]
|
|
274
|
+
elif isinstance(obj, dict):
|
|
275
|
+
return {str(k): _serialize(v, depth + 1) for k, v in obj.items()}
|
|
276
|
+
elif isinstance(obj, set):
|
|
277
|
+
try:
|
|
278
|
+
return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
|
|
279
|
+
except TypeError:
|
|
280
|
+
return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
|
|
281
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and (hasattr(obj, 'left') or hasattr(obj, 'right')):
|
|
282
|
+
result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
|
|
283
|
+
if hasattr(obj, 'left'):
|
|
284
|
+
result["left"] = _serialize(obj.left, depth + 1)
|
|
285
|
+
if hasattr(obj, 'right'):
|
|
286
|
+
result["right"] = _serialize(obj.right, depth + 1)
|
|
287
|
+
return result
|
|
288
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and hasattr(obj, 'next'):
|
|
289
|
+
result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
|
|
290
|
+
result["next"] = _serialize(obj.next, depth + 1)
|
|
291
|
+
return result
|
|
292
|
+
elif callable(obj):
|
|
293
|
+
return None
|
|
294
|
+
else:
|
|
295
|
+
repr_str = repr(obj)
|
|
296
|
+
if repr_str.startswith('<') and repr_str.endswith('>'):
|
|
297
|
+
return None
|
|
298
|
+
return repr_str
|
|
299
|
+
`;
|
|
300
|
+
|
|
301
|
+
// packages/harness-python/src/python-harness.ts
|
|
302
|
+
function identifyConversions(inputs) {
|
|
303
|
+
const treeKeys = [];
|
|
304
|
+
const listKeys = [];
|
|
305
|
+
for (const [key, value] of Object.entries(inputs)) {
|
|
306
|
+
if (value && typeof value === "object" && !Array.isArray(value) && ("val" in value || "value" in value)) {
|
|
307
|
+
const obj = value;
|
|
308
|
+
const hasLeft = "left" in obj;
|
|
309
|
+
const hasRight = "right" in obj;
|
|
310
|
+
const hasNext = "next" in obj;
|
|
311
|
+
if (hasLeft || hasRight) {
|
|
312
|
+
treeKeys.push(key);
|
|
313
|
+
} else if (hasNext) {
|
|
314
|
+
listKeys.push(key);
|
|
315
|
+
} else {
|
|
316
|
+
treeKeys.push(key);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return { treeKeys, listKeys };
|
|
321
|
+
}
|
|
322
|
+
function generateConversionCode(inputs) {
|
|
323
|
+
const { treeKeys, listKeys } = identifyConversions(inputs);
|
|
324
|
+
const lines = [];
|
|
325
|
+
for (const key of treeKeys) {
|
|
326
|
+
lines.push(`${key} = _dict_to_tree(${key})`);
|
|
327
|
+
}
|
|
328
|
+
for (const key of listKeys) {
|
|
329
|
+
lines.push(`${key} = _dict_to_list(${key})`);
|
|
330
|
+
}
|
|
331
|
+
return lines.join("\n");
|
|
332
|
+
}
|
|
333
|
+
function generateInputSetup(inputs) {
|
|
334
|
+
return Object.entries(inputs).map(([key, value]) => `${key} = ${toPythonLiteral(value)}`).join("\n");
|
|
335
|
+
}
|
|
336
|
+
function generateSolutionScript(solutionCode, functionName, inputs) {
|
|
337
|
+
const inputSetup = generateInputSetup(inputs);
|
|
338
|
+
const conversionCode = generateConversionCode(inputs);
|
|
339
|
+
const paramList = Object.keys(inputs).map((key) => `${key}=${key}`).join(", ");
|
|
340
|
+
return `
|
|
341
|
+
import json
|
|
342
|
+
import sys
|
|
343
|
+
|
|
344
|
+
${PYTHON_CLASS_DEFINITIONS}
|
|
345
|
+
|
|
346
|
+
${PYTHON_CONVERSION_HELPERS}
|
|
347
|
+
|
|
348
|
+
${PYTHON_SERIALIZE_FUNCTION}
|
|
349
|
+
|
|
350
|
+
# Solution code
|
|
351
|
+
${solutionCode}
|
|
352
|
+
|
|
353
|
+
# Set up inputs
|
|
354
|
+
${inputSetup}
|
|
355
|
+
|
|
356
|
+
# Convert tree/list inputs
|
|
357
|
+
${conversionCode}
|
|
358
|
+
|
|
359
|
+
# Run the function
|
|
360
|
+
try:
|
|
361
|
+
_result = ${functionName}(${paramList})
|
|
362
|
+
print(json.dumps({"success": True, "output": _serialize(_result)}))
|
|
363
|
+
except Exception as e:
|
|
364
|
+
print(json.dumps({"success": False, "error": f"{type(e).__name__}: {str(e)}"}))
|
|
365
|
+
`;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// packages/harness-python/src/python-harness-template.ts
|
|
369
|
+
function templateToPythonLiteral(value) {
|
|
370
|
+
if (value === null || value === void 0) {
|
|
371
|
+
return "None";
|
|
372
|
+
}
|
|
373
|
+
if (typeof value === "boolean") {
|
|
374
|
+
return value ? "True" : "False";
|
|
375
|
+
}
|
|
376
|
+
if (typeof value === "number") {
|
|
377
|
+
return String(value);
|
|
378
|
+
}
|
|
379
|
+
if (typeof value === "string") {
|
|
380
|
+
return JSON.stringify(value);
|
|
381
|
+
}
|
|
382
|
+
if (Array.isArray(value)) {
|
|
383
|
+
return "[" + value.map(templateToPythonLiteral).join(", ") + "]";
|
|
384
|
+
}
|
|
385
|
+
if (typeof value === "object") {
|
|
386
|
+
const entries = Object.entries(value).map(([k, v]) => `${JSON.stringify(k)}: ${templateToPythonLiteral(v)}`).join(", ");
|
|
387
|
+
return "{" + entries + "}";
|
|
388
|
+
}
|
|
389
|
+
return JSON.stringify(value);
|
|
390
|
+
}
|
|
391
|
+
var TEMPLATE_PYTHON_CLASS_DEFINITIONS = `
|
|
392
|
+
class TreeNode:
|
|
393
|
+
def __init__(self, val=0, left=None, right=None):
|
|
394
|
+
self.val = val
|
|
395
|
+
self.value = val
|
|
396
|
+
self.left = left
|
|
397
|
+
self.right = right
|
|
398
|
+
def __getitem__(self, key):
|
|
399
|
+
if key == 'val': return getattr(self, 'val', getattr(self, 'value', None))
|
|
400
|
+
if key == 'value': return getattr(self, 'value', getattr(self, 'val', None))
|
|
401
|
+
if key == 'left': return self.left
|
|
402
|
+
if key == 'right': return self.right
|
|
403
|
+
raise KeyError(key)
|
|
404
|
+
def get(self, key, default=None):
|
|
405
|
+
if key == 'val': return getattr(self, 'val', getattr(self, 'value', default))
|
|
406
|
+
if key == 'value': return getattr(self, 'value', getattr(self, 'val', default))
|
|
407
|
+
if key == 'left': return self.left
|
|
408
|
+
if key == 'right': return self.right
|
|
409
|
+
return default
|
|
410
|
+
def __repr__(self):
|
|
411
|
+
return f"TreeNode({getattr(self, 'val', getattr(self, 'value', None))})"
|
|
412
|
+
|
|
413
|
+
class ListNode:
|
|
414
|
+
def __init__(self, val=0, next=None):
|
|
415
|
+
self.val = val
|
|
416
|
+
self.value = val
|
|
417
|
+
self.next = next
|
|
418
|
+
def __getitem__(self, key):
|
|
419
|
+
if key == 'val': return getattr(self, 'val', getattr(self, 'value', None))
|
|
420
|
+
if key == 'value': return getattr(self, 'value', getattr(self, 'val', None))
|
|
421
|
+
if key == 'next': return self.next
|
|
422
|
+
raise KeyError(key)
|
|
423
|
+
def get(self, key, default=None):
|
|
424
|
+
if key == 'val': return getattr(self, 'val', getattr(self, 'value', default))
|
|
425
|
+
if key == 'value': return getattr(self, 'value', getattr(self, 'val', default))
|
|
426
|
+
if key == 'next': return self.next
|
|
427
|
+
return default
|
|
428
|
+
def __repr__(self):
|
|
429
|
+
return f"ListNode({getattr(self, 'val', getattr(self, 'value', None))})"
|
|
430
|
+
`;
|
|
431
|
+
var TEMPLATE_PYTHON_CONVERSION_HELPERS = `
|
|
432
|
+
def _ensure_node_value_aliases(node):
|
|
433
|
+
if node is None:
|
|
434
|
+
return node
|
|
435
|
+
try:
|
|
436
|
+
has_val = hasattr(node, 'val')
|
|
437
|
+
has_value = hasattr(node, 'value')
|
|
438
|
+
if has_value and not has_val:
|
|
439
|
+
try:
|
|
440
|
+
setattr(node, 'val', getattr(node, 'value'))
|
|
441
|
+
except Exception:
|
|
442
|
+
pass
|
|
443
|
+
elif has_val and not has_value:
|
|
444
|
+
try:
|
|
445
|
+
setattr(node, 'value', getattr(node, 'val'))
|
|
446
|
+
except Exception:
|
|
447
|
+
pass
|
|
448
|
+
except Exception:
|
|
449
|
+
pass
|
|
450
|
+
return node
|
|
451
|
+
|
|
452
|
+
def _dict_to_tree(d):
|
|
453
|
+
if d is None:
|
|
454
|
+
return None
|
|
455
|
+
if not isinstance(d, dict):
|
|
456
|
+
return d
|
|
457
|
+
if 'val' not in d and 'value' not in d:
|
|
458
|
+
return d
|
|
459
|
+
node = TreeNode(d.get('val', d.get('value', 0)))
|
|
460
|
+
_ensure_node_value_aliases(node)
|
|
461
|
+
node.left = _dict_to_tree(d.get('left'))
|
|
462
|
+
node.right = _dict_to_tree(d.get('right'))
|
|
463
|
+
return node
|
|
464
|
+
|
|
465
|
+
def _dict_to_list(d, _refs=None):
|
|
466
|
+
if _refs is None:
|
|
467
|
+
_refs = {}
|
|
468
|
+
if d is None:
|
|
469
|
+
return None
|
|
470
|
+
if not isinstance(d, dict):
|
|
471
|
+
return d
|
|
472
|
+
if '__ref__' in d:
|
|
473
|
+
return _refs.get(d.get('__ref__'))
|
|
474
|
+
if 'val' not in d and 'value' not in d:
|
|
475
|
+
return d
|
|
476
|
+
node = ListNode(d.get('val', d.get('value', 0)))
|
|
477
|
+
_ensure_node_value_aliases(node)
|
|
478
|
+
node_id = d.get('__id__')
|
|
479
|
+
if isinstance(node_id, str) and node_id:
|
|
480
|
+
_refs[node_id] = node
|
|
481
|
+
node.next = _dict_to_list(d.get('next'), _refs)
|
|
482
|
+
return node
|
|
483
|
+
`;
|
|
484
|
+
var TEMPLATE_PYTHON_TRACE_SERIALIZE_FUNCTION = `
|
|
485
|
+
# Sentinel to mark skipped values (functions, etc.) - distinct from None
|
|
486
|
+
_SKIP_SENTINEL = "__TRACECODE_SKIP__"
|
|
487
|
+
_MAX_SERIALIZE_DEPTH = 48
|
|
488
|
+
|
|
489
|
+
def _serialize(obj, depth=0, node_refs=None):
|
|
490
|
+
if node_refs is None:
|
|
491
|
+
node_refs = {}
|
|
492
|
+
if isinstance(obj, (bool, int, str, type(None))):
|
|
493
|
+
return obj
|
|
494
|
+
elif isinstance(obj, float):
|
|
495
|
+
if not math.isfinite(obj):
|
|
496
|
+
if math.isnan(obj):
|
|
497
|
+
return "NaN"
|
|
498
|
+
return "Infinity" if obj > 0 else "-Infinity"
|
|
499
|
+
return obj
|
|
500
|
+
if depth > _MAX_SERIALIZE_DEPTH:
|
|
501
|
+
return "<max depth>"
|
|
502
|
+
elif isinstance(obj, (list, tuple)):
|
|
503
|
+
return [_serialize(x, depth + 1, node_refs) for x in obj]
|
|
504
|
+
elif getattr(obj, '__class__', None) and getattr(obj.__class__, '__name__', '') == 'deque':
|
|
505
|
+
return [_serialize(x, depth + 1, node_refs) for x in obj]
|
|
506
|
+
elif isinstance(obj, dict):
|
|
507
|
+
return {str(k): _serialize(v, depth + 1, node_refs) for k, v in obj.items()}
|
|
508
|
+
elif isinstance(obj, set):
|
|
509
|
+
# Use try/except for sorting to handle heterogeneous sets
|
|
510
|
+
try:
|
|
511
|
+
sorted_vals = sorted([_serialize(x, depth + 1, node_refs) for x in obj])
|
|
512
|
+
except TypeError:
|
|
513
|
+
sorted_vals = [_serialize(x, depth + 1, node_refs) for x in obj]
|
|
514
|
+
return {"__type__": "set", "values": sorted_vals}
|
|
515
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and (hasattr(obj, 'left') or hasattr(obj, 'right')):
|
|
516
|
+
obj_ref = id(obj)
|
|
517
|
+
if obj_ref in node_refs:
|
|
518
|
+
return {"__ref__": node_refs[obj_ref]}
|
|
519
|
+
node_id = f"tree-{obj_ref}"
|
|
520
|
+
node_refs[obj_ref] = node_id
|
|
521
|
+
result = {
|
|
522
|
+
"__type__": "TreeNode",
|
|
523
|
+
"__id__": node_id,
|
|
524
|
+
"val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1, node_refs),
|
|
525
|
+
}
|
|
526
|
+
if hasattr(obj, 'left'):
|
|
527
|
+
result["left"] = _serialize(obj.left, depth + 1, node_refs)
|
|
528
|
+
if hasattr(obj, 'right'):
|
|
529
|
+
result["right"] = _serialize(obj.right, depth + 1, node_refs)
|
|
530
|
+
return result
|
|
531
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and hasattr(obj, 'next'):
|
|
532
|
+
obj_ref = id(obj)
|
|
533
|
+
if obj_ref in node_refs:
|
|
534
|
+
return {"__ref__": node_refs[obj_ref]}
|
|
535
|
+
node_id = f"list-{obj_ref}"
|
|
536
|
+
node_refs[obj_ref] = node_id
|
|
537
|
+
result = {
|
|
538
|
+
"__type__": "ListNode",
|
|
539
|
+
"__id__": node_id,
|
|
540
|
+
"val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1, node_refs),
|
|
541
|
+
}
|
|
542
|
+
result["next"] = _serialize(obj.next, depth + 1, node_refs)
|
|
543
|
+
return result
|
|
544
|
+
elif callable(obj):
|
|
545
|
+
# Skip functions entirely - return sentinel
|
|
546
|
+
return _SKIP_SENTINEL
|
|
547
|
+
else:
|
|
548
|
+
repr_str = repr(obj)
|
|
549
|
+
# Filter out function-like representations (e.g., <function foo at 0x...>)
|
|
550
|
+
if repr_str.startswith('<') and repr_str.endswith('>'):
|
|
551
|
+
return _SKIP_SENTINEL
|
|
552
|
+
return repr_str
|
|
553
|
+
`;
|
|
554
|
+
var TEMPLATE_PYTHON_EXECUTE_SERIALIZE_FUNCTION = `
|
|
555
|
+
_MAX_SERIALIZE_DEPTH = 48
|
|
556
|
+
|
|
557
|
+
def _serialize(obj, depth=0):
|
|
558
|
+
if isinstance(obj, (bool, int, str, type(None))):
|
|
559
|
+
return obj
|
|
560
|
+
elif isinstance(obj, float):
|
|
561
|
+
if not math.isfinite(obj):
|
|
562
|
+
if math.isnan(obj):
|
|
563
|
+
return "NaN"
|
|
564
|
+
return "Infinity" if obj > 0 else "-Infinity"
|
|
565
|
+
return obj
|
|
566
|
+
if depth > _MAX_SERIALIZE_DEPTH:
|
|
567
|
+
return "<max depth>"
|
|
568
|
+
elif isinstance(obj, (list, tuple)):
|
|
569
|
+
return [_serialize(x, depth + 1) for x in obj]
|
|
570
|
+
elif getattr(obj, '__class__', None) and getattr(obj.__class__, '__name__', '') == 'deque':
|
|
571
|
+
return [_serialize(x, depth + 1) for x in obj]
|
|
572
|
+
elif isinstance(obj, dict):
|
|
573
|
+
return {str(k): _serialize(v, depth + 1) for k, v in obj.items()}
|
|
574
|
+
elif isinstance(obj, set):
|
|
575
|
+
try:
|
|
576
|
+
return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
|
|
577
|
+
except TypeError:
|
|
578
|
+
return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
|
|
579
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and (hasattr(obj, 'left') or hasattr(obj, 'right')):
|
|
580
|
+
result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
|
|
581
|
+
if hasattr(obj, 'left'):
|
|
582
|
+
result["left"] = _serialize(obj.left, depth + 1)
|
|
583
|
+
if hasattr(obj, 'right'):
|
|
584
|
+
result["right"] = _serialize(obj.right, depth + 1)
|
|
585
|
+
return result
|
|
586
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and hasattr(obj, 'next'):
|
|
587
|
+
result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1)}
|
|
588
|
+
result["next"] = _serialize(obj.next, depth + 1)
|
|
589
|
+
return result
|
|
590
|
+
elif callable(obj):
|
|
591
|
+
return None
|
|
592
|
+
else:
|
|
593
|
+
repr_str = repr(obj)
|
|
594
|
+
if repr_str.startswith('<') and repr_str.endswith('>'):
|
|
595
|
+
return None
|
|
596
|
+
return repr_str
|
|
597
|
+
`;
|
|
598
|
+
var TEMPLATE_PYTHON_PRACTICE_MATERIALIZE_SERIALIZE_FUNCTION = `
|
|
599
|
+
def _serialize(obj, depth=0, state=None):
|
|
600
|
+
if state is None:
|
|
601
|
+
state = {"nodes": 0, "seen": set()}
|
|
602
|
+
if depth > 64:
|
|
603
|
+
return "__MAX_DEPTH__"
|
|
604
|
+
if isinstance(obj, (int, float, str, bool, type(None))):
|
|
605
|
+
return obj
|
|
606
|
+
|
|
607
|
+
state["nodes"] += 1
|
|
608
|
+
if state["nodes"] > 600:
|
|
609
|
+
return "__MAX_NODES__"
|
|
610
|
+
|
|
611
|
+
if isinstance(obj, (list, tuple)):
|
|
612
|
+
return [_serialize(x, depth + 1, state) for x in obj]
|
|
613
|
+
elif isinstance(obj, dict):
|
|
614
|
+
return {str(k): _serialize(v, depth + 1, state) for k, v in obj.items()}
|
|
615
|
+
elif isinstance(obj, set):
|
|
616
|
+
serialized = [_serialize(x, depth + 1, state) for x in obj]
|
|
617
|
+
try:
|
|
618
|
+
serialized = sorted(serialized)
|
|
619
|
+
except TypeError:
|
|
620
|
+
pass
|
|
621
|
+
return {"__type__": "set", "values": serialized}
|
|
622
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and (hasattr(obj, 'left') or hasattr(obj, 'right')):
|
|
623
|
+
obj_id = id(obj)
|
|
624
|
+
if obj_id in state["seen"]:
|
|
625
|
+
return "__CYCLE__"
|
|
626
|
+
state["seen"].add(obj_id)
|
|
627
|
+
result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1, state)}
|
|
628
|
+
if hasattr(obj, 'left'):
|
|
629
|
+
result["left"] = _serialize(obj.left, depth + 1, state)
|
|
630
|
+
if hasattr(obj, 'right'):
|
|
631
|
+
result["right"] = _serialize(obj.right, depth + 1, state)
|
|
632
|
+
state["seen"].remove(obj_id)
|
|
633
|
+
return result
|
|
634
|
+
elif (hasattr(obj, 'val') or hasattr(obj, 'value')) and hasattr(obj, 'next'):
|
|
635
|
+
obj_id = id(obj)
|
|
636
|
+
if obj_id in state["seen"]:
|
|
637
|
+
return "__CYCLE__"
|
|
638
|
+
state["seen"].add(obj_id)
|
|
639
|
+
result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', getattr(obj, 'value', None)), depth + 1, state)}
|
|
640
|
+
result["next"] = _serialize(obj.next, depth + 1, state)
|
|
641
|
+
state["seen"].remove(obj_id)
|
|
642
|
+
return result
|
|
643
|
+
else:
|
|
644
|
+
return repr(obj)
|
|
645
|
+
`;
|
|
646
|
+
var TEMPLATE_PYTHON_INTERVIEW_MATERIALIZE_SERIALIZE_FUNCTION = `
|
|
647
|
+
def _serialize(obj, depth=0):
|
|
648
|
+
if depth > 10:
|
|
649
|
+
return "<max depth>"
|
|
650
|
+
if isinstance(obj, (int, float, str, bool, type(None))):
|
|
651
|
+
return obj
|
|
652
|
+
elif isinstance(obj, (list, tuple)):
|
|
653
|
+
return [_serialize(x, depth + 1) for x in obj]
|
|
654
|
+
elif isinstance(obj, dict):
|
|
655
|
+
return {str(k): _serialize(v, depth + 1) for k, v in obj.items()}
|
|
656
|
+
elif isinstance(obj, set):
|
|
657
|
+
try:
|
|
658
|
+
return {"__type__": "set", "values": sorted([_serialize(x, depth + 1) for x in obj])}
|
|
659
|
+
except TypeError:
|
|
660
|
+
return {"__type__": "set", "values": [_serialize(x, depth + 1) for x in obj]}
|
|
661
|
+
elif hasattr(obj, 'val') and (hasattr(obj, 'left') or hasattr(obj, 'right')):
|
|
662
|
+
result = {"__type__": "TreeNode", "val": _serialize(getattr(obj, 'val', None), depth + 1)}
|
|
663
|
+
if hasattr(obj, 'left'):
|
|
664
|
+
result["left"] = _serialize(obj.left, depth + 1)
|
|
665
|
+
if hasattr(obj, 'right'):
|
|
666
|
+
result["right"] = _serialize(obj.right, depth + 1)
|
|
667
|
+
return result
|
|
668
|
+
elif hasattr(obj, 'val') and hasattr(obj, 'next'):
|
|
669
|
+
result = {"__type__": "ListNode", "val": _serialize(getattr(obj, 'val', None), depth + 1)}
|
|
670
|
+
result["next"] = _serialize(obj.next, depth + 1)
|
|
671
|
+
return result
|
|
672
|
+
else:
|
|
673
|
+
return repr(obj)
|
|
674
|
+
`;
|
|
675
|
+
var TEMPLATE_PYTHON_SERIALIZE_FUNCTION = TEMPLATE_PYTHON_EXECUTE_SERIALIZE_FUNCTION;
|
|
676
|
+
export {
|
|
677
|
+
PYTHON_CLASS_DEFINITIONS,
|
|
678
|
+
PYTHON_CONVERSION_HELPERS,
|
|
679
|
+
PYTHON_EXECUTE_SERIALIZE_FUNCTION,
|
|
680
|
+
PYTHON_INTERVIEW_MATERIALIZE_SERIALIZE_FUNCTION,
|
|
681
|
+
PYTHON_PRACTICE_MATERIALIZE_SERIALIZE_FUNCTION,
|
|
682
|
+
PYTHON_SERIALIZE_FUNCTION,
|
|
683
|
+
PYTHON_TRACE_SERIALIZE_FUNCTION,
|
|
684
|
+
TEMPLATE_PYTHON_CLASS_DEFINITIONS,
|
|
685
|
+
TEMPLATE_PYTHON_CONVERSION_HELPERS,
|
|
686
|
+
TEMPLATE_PYTHON_EXECUTE_SERIALIZE_FUNCTION,
|
|
687
|
+
TEMPLATE_PYTHON_INTERVIEW_MATERIALIZE_SERIALIZE_FUNCTION,
|
|
688
|
+
TEMPLATE_PYTHON_PRACTICE_MATERIALIZE_SERIALIZE_FUNCTION,
|
|
689
|
+
TEMPLATE_PYTHON_SERIALIZE_FUNCTION,
|
|
690
|
+
TEMPLATE_PYTHON_TRACE_SERIALIZE_FUNCTION,
|
|
691
|
+
generateConversionCode,
|
|
692
|
+
generateInputSetup,
|
|
693
|
+
generateSolutionScript,
|
|
694
|
+
identifyConversions,
|
|
695
|
+
templateToPythonLiteral,
|
|
696
|
+
toPythonLiteral
|
|
697
|
+
};
|
|
698
|
+
//# sourceMappingURL=python.js.map
|