@tracecode/harness 0.9.2 → 0.9.3
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 +13 -0
- package/package.json +1 -1
- package/workers/cpp/cpp-worker.js +367 -43
- package/workers/csharp/csharp-worker.js +582 -27
- package/workers/javascript/javascript-project-worker.js +1 -1
- package/workers/javascript/javascript-worker.js +105 -5
- package/workers/python/pyodide-worker.js +7 -24
- package/workers/python/runtime-core.js +331 -0
|
@@ -6481,9 +6481,6 @@ async function executeCode(payload) {
|
|
|
6481
6481
|
const consoleOutput = [];
|
|
6482
6482
|
const consoleProxy = createConsoleProxy(consoleOutput);
|
|
6483
6483
|
const runtimeGlobal = createJavaScriptRuntimeGlobal(consoleProxy);
|
|
6484
|
-
const normalizedInputs = normalizeInputs(inputs);
|
|
6485
|
-
const materializers = await resolveInputMaterializers(code, functionName, executionStyle, language);
|
|
6486
|
-
const materializedInputs = applyInputMaterializers(normalizedInputs, materializers);
|
|
6487
6484
|
|
|
6488
6485
|
try {
|
|
6489
6486
|
if (typeof code !== 'string') {
|
|
@@ -6494,6 +6491,9 @@ async function executeCode(payload) {
|
|
|
6494
6491
|
}
|
|
6495
6492
|
|
|
6496
6493
|
const executableCode = await prepareExecutableCode(code, language);
|
|
6494
|
+
const materializers = await resolveInputMaterializers(code, functionName, executionStyle, language);
|
|
6495
|
+
const normalizedInputs = normalizeInputs(inputs);
|
|
6496
|
+
const materializedInputs = applyInputMaterializers(normalizedInputs, materializers);
|
|
6497
6497
|
const hasNamedFunction = typeof functionName === 'string' && functionName.length > 0;
|
|
6498
6498
|
let output;
|
|
6499
6499
|
|
|
@@ -6539,6 +6539,19 @@ async function executeCode(payload) {
|
|
|
6539
6539
|
}
|
|
6540
6540
|
}
|
|
6541
6541
|
|
|
6542
|
+
function batchSignatureSampleInput(inputBatch) {
|
|
6543
|
+
const sample = {};
|
|
6544
|
+
for (const inputs of inputBatch) {
|
|
6545
|
+
if (!inputs || typeof inputs !== 'object' || Array.isArray(inputs)) continue;
|
|
6546
|
+
for (const key of Object.keys(inputs)) {
|
|
6547
|
+
if (!Object.prototype.hasOwnProperty.call(sample, key)) {
|
|
6548
|
+
sample[key] = inputs[key];
|
|
6549
|
+
}
|
|
6550
|
+
}
|
|
6551
|
+
}
|
|
6552
|
+
return sample;
|
|
6553
|
+
}
|
|
6554
|
+
|
|
6542
6555
|
async function executeCodeBatch(payload) {
|
|
6543
6556
|
const startedAt = performanceNow();
|
|
6544
6557
|
const inputBatch = Array.isArray(payload?.inputBatch)
|
|
@@ -6554,10 +6567,97 @@ async function executeCodeBatch(payload) {
|
|
|
6554
6567
|
};
|
|
6555
6568
|
}
|
|
6556
6569
|
|
|
6570
|
+
const {
|
|
6571
|
+
code,
|
|
6572
|
+
functionName,
|
|
6573
|
+
executionStyle = 'function',
|
|
6574
|
+
language = 'javascript',
|
|
6575
|
+
} = payload ?? {};
|
|
6576
|
+
|
|
6557
6577
|
const results = [];
|
|
6558
|
-
|
|
6559
|
-
|
|
6578
|
+
try {
|
|
6579
|
+
if (typeof code !== 'string') {
|
|
6580
|
+
throw new Error('`code` must be a string');
|
|
6581
|
+
}
|
|
6582
|
+
if (language !== 'javascript' && language !== 'typescript') {
|
|
6583
|
+
throw new Error(`Unsupported language for JavaScript worker: ${String(language)}`);
|
|
6584
|
+
}
|
|
6585
|
+
|
|
6586
|
+
const executableCode = await prepareExecutableCode(code, language);
|
|
6587
|
+
const materializers = await resolveInputMaterializers(code, functionName, executionStyle, language);
|
|
6588
|
+
const hasNamedFunction = typeof functionName === 'string' && functionName.length > 0;
|
|
6589
|
+
let runner;
|
|
6590
|
+
let inputArguments = [];
|
|
6591
|
+
let argNames = [];
|
|
6592
|
+
let argumentMaterializers = [];
|
|
6593
|
+
|
|
6594
|
+
if (hasNamedFunction) {
|
|
6595
|
+
if (executionStyle === 'ops-class') {
|
|
6596
|
+
runner = buildFunctionExecutionRunner(executableCode, executionStyle, [], [], code);
|
|
6597
|
+
} else {
|
|
6598
|
+
const sampleInputs = applyInputMaterializers(normalizeInputs(batchSignatureSampleInput(inputBatch)), materializers);
|
|
6599
|
+
inputArguments = await resolveOrderedInputArguments(code, functionName, sampleInputs, executionStyle, language);
|
|
6600
|
+
argNames = inputArguments.map((argument, index) => `__arg${index}${argument.rest ? '__tracecodeRest' : ''}`);
|
|
6601
|
+
argumentMaterializers = inputArguments.map((argument) => materializers[argument.key] ?? null);
|
|
6602
|
+
runner = buildFunctionExecutionRunner(executableCode, executionStyle, argNames, argumentMaterializers, code);
|
|
6603
|
+
}
|
|
6604
|
+
} else {
|
|
6605
|
+
if (executionStyle !== 'function') {
|
|
6606
|
+
throw new Error('Script-mode execution only supports executionStyle="function".');
|
|
6607
|
+
}
|
|
6608
|
+
runner = buildScriptExecutionRunner(executableCode, code);
|
|
6609
|
+
}
|
|
6610
|
+
|
|
6611
|
+
for (const inputs of inputBatch) {
|
|
6612
|
+
const consoleOutput = [];
|
|
6613
|
+
const consoleProxy = createConsoleProxy(consoleOutput);
|
|
6614
|
+
const runtimeGlobal = createJavaScriptRuntimeGlobal(consoleProxy);
|
|
6615
|
+
try {
|
|
6616
|
+
const materializedInputs = applyInputMaterializers(normalizeInputs(inputs), materializers);
|
|
6617
|
+
let output;
|
|
6618
|
+
if (hasNamedFunction) {
|
|
6619
|
+
if (executionStyle === 'ops-class') {
|
|
6620
|
+
const { operations, argumentsList } = getOpsClassInputs(materializedInputs);
|
|
6621
|
+
output = await Promise.resolve(runner(consoleProxy, functionName, operations, argumentsList, runtimeGlobal));
|
|
6622
|
+
} else {
|
|
6623
|
+
const argValues = inputArguments.map((argument) => materializedInputs[argument.key]);
|
|
6624
|
+
output = await Promise.resolve(runner(consoleProxy, functionName, ...argValues, runtimeGlobal));
|
|
6625
|
+
}
|
|
6626
|
+
} else {
|
|
6627
|
+
const scriptStdin = typeof materializedInputs.stdin === 'string' ? materializedInputs.stdin : undefined;
|
|
6628
|
+
output = await Promise.resolve(runner(consoleProxy, scriptStdin, runtimeGlobal));
|
|
6629
|
+
if (scriptStdin !== undefined && output === null) {
|
|
6630
|
+
output = consoleOutput.length > 0 ? `${consoleOutput.join('\n')}\n` : '';
|
|
6631
|
+
}
|
|
6632
|
+
}
|
|
6633
|
+
results.push({
|
|
6634
|
+
success: true,
|
|
6635
|
+
output: serializeOutputValue(output),
|
|
6636
|
+
consoleOutput,
|
|
6637
|
+
});
|
|
6638
|
+
} catch (error) {
|
|
6639
|
+
results.push({
|
|
6640
|
+
success: false,
|
|
6641
|
+
output: null,
|
|
6642
|
+
error: formatRuntimeErrorMessage(error),
|
|
6643
|
+
errorLine: extractUserErrorLine(error),
|
|
6644
|
+
consoleOutput,
|
|
6645
|
+
});
|
|
6646
|
+
}
|
|
6647
|
+
}
|
|
6648
|
+
} catch (error) {
|
|
6649
|
+
const message = formatRuntimeErrorMessage(error);
|
|
6650
|
+
for (let index = 0; index < inputBatch.length; index += 1) {
|
|
6651
|
+
results.push({
|
|
6652
|
+
success: false,
|
|
6653
|
+
output: null,
|
|
6654
|
+
error: message,
|
|
6655
|
+
errorLine: extractUserErrorLine(error),
|
|
6656
|
+
consoleOutput: [],
|
|
6657
|
+
});
|
|
6658
|
+
}
|
|
6560
6659
|
}
|
|
6660
|
+
|
|
6561
6661
|
return {
|
|
6562
6662
|
success: results.every((result) => result.success === true),
|
|
6563
6663
|
results,
|
|
@@ -4350,30 +4350,13 @@ json.dumps({
|
|
|
4350
4350
|
}
|
|
4351
4351
|
|
|
4352
4352
|
async function executeCodeBatch(code, functionName, inputBatch, executionStyle = 'function') {
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
results: [],
|
|
4361
|
-
error: 'Python batch execution requires a non-empty inputBatch array.',
|
|
4362
|
-
consoleOutput: [],
|
|
4363
|
-
timings: { totalMs: performance.now() - startedAt },
|
|
4364
|
-
};
|
|
4365
|
-
}
|
|
4366
|
-
|
|
4367
|
-
const results = [];
|
|
4368
|
-
for (const inputs of cases) {
|
|
4369
|
-
results.push(await executeCode(code, functionName, inputs, executionStyle));
|
|
4370
|
-
}
|
|
4371
|
-
return {
|
|
4372
|
-
success: results.every((result) => result.success === true),
|
|
4373
|
-
results,
|
|
4374
|
-
consoleOutput: results.flatMap((result) => result.consoleOutput ?? []),
|
|
4375
|
-
timings: { totalMs: performance.now() - startedAt },
|
|
4376
|
-
};
|
|
4353
|
+
return loadPyodideRuntimeCore().executeCodeBatch(
|
|
4354
|
+
buildRuntimeDeps(),
|
|
4355
|
+
code,
|
|
4356
|
+
functionName,
|
|
4357
|
+
inputBatch,
|
|
4358
|
+
executionStyle
|
|
4359
|
+
);
|
|
4377
4360
|
}
|
|
4378
4361
|
|
|
4379
4362
|
async function processMessage(data) {
|
|
@@ -4339,10 +4339,341 @@ json.dumps({
|
|
|
4339
4339
|
}
|
|
4340
4340
|
}
|
|
4341
4341
|
|
|
4342
|
+
async function executeCodeBatch(deps, code, functionName, inputBatch, executionStyle = 'function') {
|
|
4343
|
+
const startedAt = deps.performanceNow();
|
|
4344
|
+
const userCodeLineCount = code.split('\n').length;
|
|
4345
|
+
const cases = Array.isArray(inputBatch)
|
|
4346
|
+
? inputBatch.map((inputs) => (inputs && typeof inputs === 'object' && !Array.isArray(inputs) ? inputs : {}))
|
|
4347
|
+
: [];
|
|
4348
|
+
|
|
4349
|
+
if (cases.length === 0) {
|
|
4350
|
+
return {
|
|
4351
|
+
success: false,
|
|
4352
|
+
results: [],
|
|
4353
|
+
error: 'Python batch execution requires a non-empty inputBatch array.',
|
|
4354
|
+
consoleOutput: [],
|
|
4355
|
+
timings: { totalMs: deps.performanceNow() - startedAt },
|
|
4356
|
+
};
|
|
4357
|
+
}
|
|
4358
|
+
|
|
4359
|
+
try {
|
|
4360
|
+
await deps.loadPyodideInstance();
|
|
4361
|
+
|
|
4362
|
+
const functionNameLiteral = deps.toPythonLiteral(functionName);
|
|
4363
|
+
const executionStyleLiteral = deps.toPythonLiteral(executionStyle);
|
|
4364
|
+
const batchCode = `
|
|
4365
|
+
import copy as _copy
|
|
4366
|
+
import json
|
|
4367
|
+
import math
|
|
4368
|
+
import sys
|
|
4369
|
+
import builtins as _builtins
|
|
4370
|
+
${deps.PYTHON_CLASS_DEFINITIONS_SNIPPET}
|
|
4371
|
+
${PYTHON_DEFAULT_IMPORT_PRELUDE}
|
|
4372
|
+
pow = _builtins.pow
|
|
4373
|
+
|
|
4374
|
+
${deps.PYTHON_EXECUTE_SERIALIZE_FUNCTION_SNIPPET}
|
|
4375
|
+
${deps.PYTHON_CONVERSION_HELPERS_SNIPPET}
|
|
4376
|
+
|
|
4377
|
+
_USER_CODE = ${JSON.stringify(code)}
|
|
4378
|
+
_FUNCTION_NAME = ${functionNameLiteral}
|
|
4379
|
+
_EXECUTION_STYLE = ${executionStyleLiteral}
|
|
4380
|
+
_INPUT_BATCH = ${deps.toPythonLiteral(cases)}
|
|
4381
|
+
_USER_CODE_OBJECT = compile(_USER_CODE, "solution.py", "exec")
|
|
4382
|
+
_INPLACE_RESULT_NAMES = ('nums1', 'nums', 'arr', 'array', 'matrix', 'board', 'grid')
|
|
4383
|
+
|
|
4384
|
+
def _tracecode_materialize_custom_input(obj, _env):
|
|
4385
|
+
if isinstance(obj, _builtins.list):
|
|
4386
|
+
return [_tracecode_materialize_custom_input(item, _env) for item in obj]
|
|
4387
|
+
if isinstance(obj, _builtins.tuple):
|
|
4388
|
+
return tuple(_tracecode_materialize_custom_input(item, _env) for item in obj)
|
|
4389
|
+
if isinstance(obj, _builtins.dict):
|
|
4390
|
+
if obj.get('__type__') == 'TreeNode' or 'left' in obj or 'right' in obj:
|
|
4391
|
+
return _dict_to_tree(obj)
|
|
4392
|
+
if obj.get('__type__') == 'ListNode' or 'next' in obj:
|
|
4393
|
+
return _dict_to_list(obj)
|
|
4394
|
+
_type_name = obj.get('__type__') if isinstance(obj.get('__type__'), _builtins.str) else obj.get('__class__')
|
|
4395
|
+
_fields = {key: _tracecode_materialize_custom_input(value, _env) for key, value in obj.items() if key not in ('__type__', '__class__', '__id__')}
|
|
4396
|
+
if isinstance(_type_name, _builtins.str):
|
|
4397
|
+
_fields = {'__type__': _type_name, **_fields}
|
|
4398
|
+
_constructor_fields = {key: value for key, value in _fields.items() if key not in ('__type__', '__class__')}
|
|
4399
|
+
_cls = _env.get(_type_name) if isinstance(_type_name, _builtins.str) else None
|
|
4400
|
+
if isinstance(_cls, _builtins.type):
|
|
4401
|
+
try:
|
|
4402
|
+
return _cls(**_constructor_fields)
|
|
4403
|
+
except Exception:
|
|
4404
|
+
pass
|
|
4405
|
+
try:
|
|
4406
|
+
return _cls(*_builtins.list(_constructor_fields.values()))
|
|
4407
|
+
except Exception:
|
|
4408
|
+
pass
|
|
4409
|
+
try:
|
|
4410
|
+
_instance = _cls.__new__(_cls)
|
|
4411
|
+
for _key, _value in _constructor_fields.items():
|
|
4412
|
+
setattr(_instance, _key, _value)
|
|
4413
|
+
return _instance
|
|
4414
|
+
except Exception:
|
|
4415
|
+
pass
|
|
4416
|
+
return _fields
|
|
4417
|
+
return obj
|
|
4418
|
+
|
|
4419
|
+
def _tracecode_hydrate_for_annotation(_obj, _annotation, _env):
|
|
4420
|
+
try:
|
|
4421
|
+
import typing as _tracecode_typing
|
|
4422
|
+
import collections.abc as _tracecode_collections_abc
|
|
4423
|
+
except Exception:
|
|
4424
|
+
return _obj
|
|
4425
|
+
if _annotation is None:
|
|
4426
|
+
return _obj
|
|
4427
|
+
if isinstance(_annotation, _builtins.str):
|
|
4428
|
+
_annotation = _env.get(_annotation, _annotation)
|
|
4429
|
+
if _annotation in (_builtins.object, getattr(_tracecode_typing, 'Any', None)):
|
|
4430
|
+
return _obj
|
|
4431
|
+
_origin = _tracecode_typing.get_origin(_annotation)
|
|
4432
|
+
_args = _tracecode_typing.get_args(_annotation)
|
|
4433
|
+
if _origin is _tracecode_typing.Union:
|
|
4434
|
+
_non_none = [_arg for _arg in _args if _arg is not type(None)]
|
|
4435
|
+
return _tracecode_hydrate_for_annotation(_obj, _non_none[0], _env) if len(_non_none) == 1 else _obj
|
|
4436
|
+
if _origin in (_builtins.list, _builtins.tuple, _builtins.set, _builtins.frozenset):
|
|
4437
|
+
_item_annotation = _args[0] if _args else None
|
|
4438
|
+
if isinstance(_obj, _builtins.list):
|
|
4439
|
+
_items = [_tracecode_hydrate_for_annotation(_item, _item_annotation, _env) for _item in _obj]
|
|
4440
|
+
if _origin is _builtins.tuple:
|
|
4441
|
+
return tuple(_items)
|
|
4442
|
+
if _origin is _builtins.set:
|
|
4443
|
+
return _builtins.set(_items)
|
|
4444
|
+
if _origin is _builtins.frozenset:
|
|
4445
|
+
return _builtins.frozenset(_items)
|
|
4446
|
+
return _items
|
|
4447
|
+
return _obj
|
|
4448
|
+
if _origin in (_builtins.dict, _tracecode_collections_abc.Mapping, _tracecode_collections_abc.MutableMapping) and isinstance(_obj, _builtins.dict):
|
|
4449
|
+
_key_annotation = _args[0] if len(_args) > 0 else None
|
|
4450
|
+
_value_annotation = _args[1] if len(_args) > 1 else None
|
|
4451
|
+
return {
|
|
4452
|
+
_tracecode_hydrate_for_annotation(_key, _key_annotation, _env): _tracecode_hydrate_for_annotation(_value, _value_annotation, _env)
|
|
4453
|
+
for _key, _value in _obj.items()
|
|
4454
|
+
}
|
|
4455
|
+
if isinstance(_annotation, _builtins.type) and isinstance(_obj, _builtins.dict):
|
|
4456
|
+
if _annotation.__name__ in ('TreeNode', 'ListNode'):
|
|
4457
|
+
return _obj
|
|
4458
|
+
_fields = {key: value for key, value in _obj.items() if key not in ('__type__', '__class__', '__id__')}
|
|
4459
|
+
try:
|
|
4460
|
+
_ctor_hints = _tracecode_typing.get_type_hints(getattr(_annotation, '__init__'), _env, _env)
|
|
4461
|
+
except Exception:
|
|
4462
|
+
_ctor_hints = {}
|
|
4463
|
+
_hydrated_fields = {
|
|
4464
|
+
key: _tracecode_hydrate_for_annotation(value, _ctor_hints.get(key), _env)
|
|
4465
|
+
for key, value in _fields.items()
|
|
4466
|
+
}
|
|
4467
|
+
try:
|
|
4468
|
+
return _annotation(**_hydrated_fields)
|
|
4469
|
+
except Exception:
|
|
4470
|
+
pass
|
|
4471
|
+
try:
|
|
4472
|
+
return _annotation(*_builtins.list(_hydrated_fields.values()))
|
|
4473
|
+
except Exception:
|
|
4474
|
+
pass
|
|
4475
|
+
try:
|
|
4476
|
+
_instance = _annotation.__new__(_annotation)
|
|
4477
|
+
for _key, _value in _hydrated_fields.items():
|
|
4478
|
+
setattr(_instance, _key, _value)
|
|
4479
|
+
return _instance
|
|
4480
|
+
except Exception:
|
|
4481
|
+
return _obj
|
|
4482
|
+
return _obj
|
|
4483
|
+
|
|
4484
|
+
def _tracecode_resolve_target_callable(_env):
|
|
4485
|
+
if _EXECUTION_STYLE == 'solution-method' and 'Solution' in _env and hasattr(_env['Solution'], _FUNCTION_NAME):
|
|
4486
|
+
return getattr(_env['Solution'], _FUNCTION_NAME)
|
|
4487
|
+
if _FUNCTION_NAME in _env and callable(_env[_FUNCTION_NAME]):
|
|
4488
|
+
return _env[_FUNCTION_NAME]
|
|
4489
|
+
if 'Solution' in _env and hasattr(_env['Solution'], _FUNCTION_NAME):
|
|
4490
|
+
return getattr(_env['Solution'], _FUNCTION_NAME)
|
|
4491
|
+
return None
|
|
4492
|
+
|
|
4493
|
+
def _tracecode_hydrate_annotated_inputs(_env, _input_names):
|
|
4494
|
+
try:
|
|
4495
|
+
import typing as _tracecode_typing
|
|
4496
|
+
_callable = _tracecode_resolve_target_callable(_env)
|
|
4497
|
+
if _callable is None:
|
|
4498
|
+
return
|
|
4499
|
+
try:
|
|
4500
|
+
_annotations = _tracecode_typing.get_type_hints(_callable, _env, _env)
|
|
4501
|
+
except Exception:
|
|
4502
|
+
_annotations = getattr(_callable, '__annotations__', {}) or {}
|
|
4503
|
+
for _name in _input_names:
|
|
4504
|
+
if _name in _env and _name in _annotations:
|
|
4505
|
+
_env[_name] = _tracecode_hydrate_for_annotation(_env[_name], _annotations[_name], _env)
|
|
4506
|
+
except Exception:
|
|
4507
|
+
return
|
|
4508
|
+
|
|
4509
|
+
def _tracecode_resolve_entry_callable(_env):
|
|
4510
|
+
if _EXECUTION_STYLE == 'solution-method' and 'Solution' in _env and hasattr(_env['Solution'], _FUNCTION_NAME):
|
|
4511
|
+
return getattr(_env['Solution'](), _FUNCTION_NAME)
|
|
4512
|
+
if _FUNCTION_NAME in _env and callable(_env[_FUNCTION_NAME]):
|
|
4513
|
+
return _env[_FUNCTION_NAME]
|
|
4514
|
+
if 'Solution' in _env and hasattr(_env['Solution'], _FUNCTION_NAME):
|
|
4515
|
+
return getattr(_env['Solution'](), _FUNCTION_NAME)
|
|
4516
|
+
return None
|
|
4517
|
+
|
|
4518
|
+
def _tracecode_invoke_entry(_env, _input_names):
|
|
4519
|
+
import inspect as _tracecode_inspect
|
|
4520
|
+
_callable = _tracecode_resolve_entry_callable(_env)
|
|
4521
|
+
if _callable is None:
|
|
4522
|
+
raise NameError(f"Implement {_FUNCTION_NAME}(...) or Solution.{_FUNCTION_NAME}(...)")
|
|
4523
|
+
_values = {_name: _env[_name] for _name in _input_names if _name in _env}
|
|
4524
|
+
try:
|
|
4525
|
+
_signature = _tracecode_inspect.signature(_callable)
|
|
4526
|
+
except Exception:
|
|
4527
|
+
return _callable(**_values)
|
|
4528
|
+
_args = []
|
|
4529
|
+
_kwargs = {}
|
|
4530
|
+
_has_varargs = any(
|
|
4531
|
+
_parameter.kind is _tracecode_inspect.Parameter.VAR_POSITIONAL
|
|
4532
|
+
for _parameter in _signature.parameters.values()
|
|
4533
|
+
)
|
|
4534
|
+
for _parameter in _signature.parameters.values():
|
|
4535
|
+
if _parameter.name in ('self', 'cls'):
|
|
4536
|
+
continue
|
|
4537
|
+
_kind = _parameter.kind
|
|
4538
|
+
if _kind is _tracecode_inspect.Parameter.VAR_POSITIONAL:
|
|
4539
|
+
if _parameter.name in _values:
|
|
4540
|
+
_raw = _values[_parameter.name]
|
|
4541
|
+
if isinstance(_raw, (_builtins.list, _builtins.tuple)):
|
|
4542
|
+
_args.extend(_raw)
|
|
4543
|
+
else:
|
|
4544
|
+
_args.append(_raw)
|
|
4545
|
+
continue
|
|
4546
|
+
if _kind is _tracecode_inspect.Parameter.VAR_KEYWORD:
|
|
4547
|
+
if _parameter.name in _values and isinstance(_values[_parameter.name], _builtins.dict):
|
|
4548
|
+
_kwargs.update(_values[_parameter.name])
|
|
4549
|
+
continue
|
|
4550
|
+
if _parameter.name not in _values:
|
|
4551
|
+
continue
|
|
4552
|
+
if _kind is _tracecode_inspect.Parameter.POSITIONAL_ONLY:
|
|
4553
|
+
_args.append(_values[_parameter.name])
|
|
4554
|
+
elif _kind is _tracecode_inspect.Parameter.POSITIONAL_OR_KEYWORD and _has_varargs:
|
|
4555
|
+
_args.append(_values[_parameter.name])
|
|
4556
|
+
else:
|
|
4557
|
+
_kwargs[_parameter.name] = _values[_parameter.name]
|
|
4558
|
+
return _callable(*_args, **_kwargs)
|
|
4559
|
+
|
|
4560
|
+
def _tracecode_run_ops_class(_env):
|
|
4561
|
+
_ops = _env.get('operations', _env.get('ops'))
|
|
4562
|
+
_args = _env.get('arguments', _env.get('args'))
|
|
4563
|
+
if _ops is None or _args is None:
|
|
4564
|
+
raise ValueError("ops-class execution requires inputs.operations and inputs.arguments (or ops/args)")
|
|
4565
|
+
if len(_ops) != len(_args):
|
|
4566
|
+
raise ValueError("operations and arguments must have the same length")
|
|
4567
|
+
_cls = _env[_FUNCTION_NAME]
|
|
4568
|
+
_instance = None
|
|
4569
|
+
_out = []
|
|
4570
|
+
for _i, _op in enumerate(_ops):
|
|
4571
|
+
_call_args = _args[_i] if _i < len(_args) else []
|
|
4572
|
+
if _call_args is None:
|
|
4573
|
+
_call_args = []
|
|
4574
|
+
if not isinstance(_call_args, (_builtins.list, _builtins.tuple)):
|
|
4575
|
+
_call_args = [_call_args]
|
|
4576
|
+
if _i == 0:
|
|
4577
|
+
_instance = _cls(*_call_args)
|
|
4578
|
+
_out.append(None)
|
|
4579
|
+
else:
|
|
4580
|
+
if not hasattr(_instance, _op):
|
|
4581
|
+
raise AttributeError(f"Required method '{_op}' is not implemented on {_cls.__name__}")
|
|
4582
|
+
_method = getattr(_instance, _op)
|
|
4583
|
+
_out.append(_method(*_call_args))
|
|
4584
|
+
return _out
|
|
4585
|
+
|
|
4586
|
+
_TRACE_CODE_CASE_BASE_NAMES = tuple(
|
|
4587
|
+
name for name in globals()
|
|
4588
|
+
if name not in ('_USER_CODE', '_FUNCTION_NAME', '_EXECUTION_STYLE', '_INPUT_BATCH', '_USER_CODE_OBJECT')
|
|
4589
|
+
)
|
|
4590
|
+
|
|
4591
|
+
def _tracecode_base_env():
|
|
4592
|
+
_env = {name: globals()[name] for name in _TRACE_CODE_CASE_BASE_NAMES if name in globals()}
|
|
4593
|
+
_env['__builtins__'] = _builtins
|
|
4594
|
+
_env['__name__'] = '__main__'
|
|
4595
|
+
_env['print'] = None
|
|
4596
|
+
return _env
|
|
4597
|
+
|
|
4598
|
+
def _tracecode_run_case(_raw_inputs):
|
|
4599
|
+
_console_output = []
|
|
4600
|
+
def _custom_print(*args, **kwargs):
|
|
4601
|
+
_console_output.append(" ".join(str(arg) for arg in args))
|
|
4602
|
+
_env = _tracecode_base_env()
|
|
4603
|
+
_env['print'] = _custom_print
|
|
4604
|
+
try:
|
|
4605
|
+
_raw_input_items = _raw_inputs.items() if isinstance(_raw_inputs, _builtins.dict) else []
|
|
4606
|
+
if not isinstance(_FUNCTION_NAME, _builtins.str) or not _FUNCTION_NAME:
|
|
4607
|
+
_inputs = {
|
|
4608
|
+
str(_key): _tracecode_materialize_custom_input(_copy.deepcopy(_value), _env)
|
|
4609
|
+
for _key, _value in _raw_input_items
|
|
4610
|
+
}
|
|
4611
|
+
_env.update(_inputs)
|
|
4612
|
+
exec(_USER_CODE_OBJECT, _env)
|
|
4613
|
+
else:
|
|
4614
|
+
exec(_USER_CODE_OBJECT, _env)
|
|
4615
|
+
_inputs = {
|
|
4616
|
+
str(_key): _tracecode_materialize_custom_input(_copy.deepcopy(_value), _env)
|
|
4617
|
+
for _key, _value in _raw_input_items
|
|
4618
|
+
}
|
|
4619
|
+
_env.update(_inputs)
|
|
4620
|
+
_input_names = list(_inputs.keys())
|
|
4621
|
+
_tracecode_hydrate_annotated_inputs(_env, _input_names)
|
|
4622
|
+
if not isinstance(_FUNCTION_NAME, _builtins.str) or not _FUNCTION_NAME:
|
|
4623
|
+
_result = _env.get('result')
|
|
4624
|
+
elif _EXECUTION_STYLE == 'ops-class':
|
|
4625
|
+
_result = _tracecode_run_ops_class(_env)
|
|
4626
|
+
else:
|
|
4627
|
+
_result = _tracecode_invoke_entry(_env, _input_names)
|
|
4628
|
+
if _result is None:
|
|
4629
|
+
for _name in _INPLACE_RESULT_NAMES:
|
|
4630
|
+
if _name in _env:
|
|
4631
|
+
_result = _env[_name]
|
|
4632
|
+
break
|
|
4633
|
+
return {'success': True, 'output': _serialize(_result), 'consoleOutput': _console_output}
|
|
4634
|
+
except Exception as _error:
|
|
4635
|
+
return {'success': False, 'output': None, 'error': str(_error), 'consoleOutput': _console_output}
|
|
4636
|
+
|
|
4637
|
+
_results = [_tracecode_run_case(_case) for _case in _INPUT_BATCH]
|
|
4638
|
+
json.dumps({
|
|
4639
|
+
'success': all(_result.get('success') is True for _result in _results),
|
|
4640
|
+
'results': _results,
|
|
4641
|
+
'consoleOutput': [line for _result in _results for line in _result.get('consoleOutput', [])],
|
|
4642
|
+
})
|
|
4643
|
+
`;
|
|
4644
|
+
|
|
4645
|
+
const resultJson = await deps.getPyodide().runPythonAsync(batchCode);
|
|
4646
|
+
const parsed = JSON.parse(resultJson);
|
|
4647
|
+
return {
|
|
4648
|
+
success: parsed.success === true,
|
|
4649
|
+
results: Array.isArray(parsed.results) ? parsed.results : [],
|
|
4650
|
+
consoleOutput: Array.isArray(parsed.consoleOutput) ? parsed.consoleOutput : [],
|
|
4651
|
+
timings: { totalMs: deps.performanceNow() - startedAt },
|
|
4652
|
+
};
|
|
4653
|
+
} catch (error) {
|
|
4654
|
+
const rawError = error instanceof Error ? error.message : String(error);
|
|
4655
|
+
const { message, line } = parsePythonError(rawError, 1, userCodeLineCount);
|
|
4656
|
+
return {
|
|
4657
|
+
success: false,
|
|
4658
|
+
results: cases.map(() => ({
|
|
4659
|
+
success: false,
|
|
4660
|
+
output: null,
|
|
4661
|
+
error: message,
|
|
4662
|
+
errorLine: line,
|
|
4663
|
+
consoleOutput: [],
|
|
4664
|
+
})),
|
|
4665
|
+
error: message,
|
|
4666
|
+
consoleOutput: [],
|
|
4667
|
+
timings: { totalMs: deps.performanceNow() - startedAt },
|
|
4668
|
+
};
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
|
|
4342
4672
|
globalScope.__TRACECODE_PYODIDE_RUNTIME__ = {
|
|
4343
4673
|
generateTracingCode,
|
|
4344
4674
|
parsePythonError,
|
|
4345
4675
|
executeWithTracing,
|
|
4346
4676
|
executeCode,
|
|
4677
|
+
executeCodeBatch,
|
|
4347
4678
|
};
|
|
4348
4679
|
})(typeof self !== 'undefined' ? self : globalThis);
|