superacli 1.1.4 → 1.1.6
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/__tests__/adapter-schema.test.js +2 -0
- package/__tests__/config.test.js +62 -1
- package/__tests__/help-json.test.js +2 -0
- package/__tests__/mcp-adapter.test.js +14 -4
- package/__tests__/mcp-local.test.js +159 -0
- package/__tests__/mcp-stdio-jsonrpc.test.js +105 -0
- package/__tests__/monty-plugin.test.js +121 -0
- package/__tests__/plugin-browser-use-uninstall.test.js +23 -0
- package/__tests__/plugin-browser-use.test.js +77 -0
- package/__tests__/plugins-command.test.js +92 -1
- package/__tests__/plugins-learn.test.js +62 -0
- package/__tests__/plugins-registry.test.js +3 -1
- package/__tests__/resend-plugin.test.js +122 -0
- package/__tests__/skills.test.js +4 -0
- package/cli/adapter-schema.js +3 -2
- package/cli/adapters/mcp.js +22 -3
- package/cli/adapters/process.js +34 -7
- package/cli/config.js +27 -1
- package/cli/help-json.js +2 -2
- package/cli/mcp-diagnostics.js +152 -0
- package/cli/mcp-discovery.js +221 -0
- package/cli/mcp-local.js +267 -25
- package/cli/mcp-stdio-jsonrpc.js +246 -0
- package/cli/plugin-install-guidance.js +25 -0
- package/cli/plugins-command.js +86 -3
- package/cli/plugins-learn.js +177 -0
- package/cli/plugins-manager.js +3 -0
- package/cli/plugins-registry.js +2 -1
- package/cli/skills-mcp.js +102 -0
- package/cli/skills.js +6 -40
- package/cli/supercli.js +7 -2
- package/docs/initial/mcp-local-mode.md +35 -0
- package/docs/mcp-cheatsheet.md +324 -0
- package/docs/plugins.md +7 -0
- package/package.json +1 -1
- package/plugins/browser-use/plugin.json +23 -0
- package/plugins/browser-use/scripts/post-install.js +146 -0
- package/plugins/browser-use/scripts/post-uninstall.js +28 -0
- package/plugins/browser-use/skills/quickstart/SKILL.md +47 -0
- package/plugins/monty/README.md +49 -0
- package/plugins/monty/plugin.json +69 -0
- package/plugins/monty/scripts/post-install.js +73 -0
- package/plugins/monty/scripts/post-uninstall.js +23 -0
- package/plugins/monty/scripts/run-python.js +140 -0
- package/plugins/monty/scripts/setup-monty.js +27 -0
- package/plugins/plugins.json +29 -0
- package/plugins/resend/plugin.json +371 -0
- package/plugins/resend/scripts/post-install.js +59 -0
- package/plugins/resend/scripts/post-uninstall.js +23 -0
- package/plugins/resend/scripts/setup-resend.js +27 -0
- package/plugins/resend/skills/quickstart/SKILL.md +80 -0
- package/ref-monty/.cargo/config.toml +3 -0
- package/ref-monty/.claude/settings.json +60 -0
- package/ref-monty/.claude/skills/fastmod/SKILL.md +22 -0
- package/ref-monty/.claude/skills/python-playground/SKILL.md +47 -0
- package/ref-monty/.codecov.yml +12 -0
- package/ref-monty/.github/actions/build-pgo-wheel/action.yml +72 -0
- package/ref-monty/.github/workflows/ci.yml +776 -0
- package/ref-monty/.github/workflows/codspeed.yml +45 -0
- package/ref-monty/.github/workflows/init-npm-packages.yml +82 -0
- package/ref-monty/.pre-commit-config.yaml +47 -0
- package/ref-monty/.python-version +1 -0
- package/ref-monty/.rustfmt.toml +4 -0
- package/ref-monty/.zed/settings.json +11 -0
- package/ref-monty/CLAUDE.md +535 -0
- package/ref-monty/Cargo.lock +3798 -0
- package/ref-monty/Cargo.toml +87 -0
- package/ref-monty/LICENSE +21 -0
- package/ref-monty/Makefile +216 -0
- package/ref-monty/README.md +430 -0
- package/ref-monty/RELEASING.md +47 -0
- package/ref-monty/crates/fuzz/Cargo.toml +30 -0
- package/ref-monty/crates/fuzz/fuzz_targets/string_input_panic.rs +37 -0
- package/ref-monty/crates/fuzz/fuzz_targets/tokens_input_panic.rs +552 -0
- package/ref-monty/crates/monty/Cargo.toml +68 -0
- package/ref-monty/crates/monty/benches/main.rs +247 -0
- package/ref-monty/crates/monty/build.rs +10 -0
- package/ref-monty/crates/monty/src/args.rs +733 -0
- package/ref-monty/crates/monty/src/asyncio.rs +179 -0
- package/ref-monty/crates/monty/src/builtins/abs.rs +55 -0
- package/ref-monty/crates/monty/src/builtins/all.rs +30 -0
- package/ref-monty/crates/monty/src/builtins/any.rs +30 -0
- package/ref-monty/crates/monty/src/builtins/bin.rs +59 -0
- package/ref-monty/crates/monty/src/builtins/chr.rs +46 -0
- package/ref-monty/crates/monty/src/builtins/divmod.rs +164 -0
- package/ref-monty/crates/monty/src/builtins/enumerate.rs +52 -0
- package/ref-monty/crates/monty/src/builtins/filter.rs +67 -0
- package/ref-monty/crates/monty/src/builtins/getattr.rs +65 -0
- package/ref-monty/crates/monty/src/builtins/hash.rs +28 -0
- package/ref-monty/crates/monty/src/builtins/hex.rs +58 -0
- package/ref-monty/crates/monty/src/builtins/id.rs +24 -0
- package/ref-monty/crates/monty/src/builtins/isinstance.rs +68 -0
- package/ref-monty/crates/monty/src/builtins/len.rs +25 -0
- package/ref-monty/crates/monty/src/builtins/map.rs +98 -0
- package/ref-monty/crates/monty/src/builtins/min_max.rs +113 -0
- package/ref-monty/crates/monty/src/builtins/mod.rs +246 -0
- package/ref-monty/crates/monty/src/builtins/next.rs +21 -0
- package/ref-monty/crates/monty/src/builtins/oct.rs +59 -0
- package/ref-monty/crates/monty/src/builtins/ord.rs +67 -0
- package/ref-monty/crates/monty/src/builtins/pow.rs +365 -0
- package/ref-monty/crates/monty/src/builtins/print.rs +141 -0
- package/ref-monty/crates/monty/src/builtins/repr.rs +16 -0
- package/ref-monty/crates/monty/src/builtins/reversed.rs +28 -0
- package/ref-monty/crates/monty/src/builtins/round.rs +174 -0
- package/ref-monty/crates/monty/src/builtins/sorted.rs +151 -0
- package/ref-monty/crates/monty/src/builtins/sum.rs +66 -0
- package/ref-monty/crates/monty/src/builtins/type_.rs +16 -0
- package/ref-monty/crates/monty/src/builtins/zip.rs +77 -0
- package/ref-monty/crates/monty/src/bytecode/builder.rs +699 -0
- package/ref-monty/crates/monty/src/bytecode/code.rs +310 -0
- package/ref-monty/crates/monty/src/bytecode/compiler.rs +3206 -0
- package/ref-monty/crates/monty/src/bytecode/mod.rs +24 -0
- package/ref-monty/crates/monty/src/bytecode/op.rs +617 -0
- package/ref-monty/crates/monty/src/bytecode/vm/async_exec.rs +1058 -0
- package/ref-monty/crates/monty/src/bytecode/vm/attr.rs +63 -0
- package/ref-monty/crates/monty/src/bytecode/vm/binary.rs +487 -0
- package/ref-monty/crates/monty/src/bytecode/vm/call.rs +767 -0
- package/ref-monty/crates/monty/src/bytecode/vm/collections.rs +741 -0
- package/ref-monty/crates/monty/src/bytecode/vm/compare.rs +147 -0
- package/ref-monty/crates/monty/src/bytecode/vm/exceptions.rs +297 -0
- package/ref-monty/crates/monty/src/bytecode/vm/format.rs +132 -0
- package/ref-monty/crates/monty/src/bytecode/vm/mod.rs +1958 -0
- package/ref-monty/crates/monty/src/bytecode/vm/scheduler.rs +620 -0
- package/ref-monty/crates/monty/src/exception_private.rs +1513 -0
- package/ref-monty/crates/monty/src/exception_public.rs +346 -0
- package/ref-monty/crates/monty/src/expressions.rs +694 -0
- package/ref-monty/crates/monty/src/fstring.rs +854 -0
- package/ref-monty/crates/monty/src/function.rs +119 -0
- package/ref-monty/crates/monty/src/heap.rs +1073 -0
- package/ref-monty/crates/monty/src/heap_data.rs +985 -0
- package/ref-monty/crates/monty/src/heap_traits.rs +312 -0
- package/ref-monty/crates/monty/src/intern.rs +837 -0
- package/ref-monty/crates/monty/src/io.rs +106 -0
- package/ref-monty/crates/monty/src/lib.rs +52 -0
- package/ref-monty/crates/monty/src/modules/asyncio.rs +144 -0
- package/ref-monty/crates/monty/src/modules/math.rs +1453 -0
- package/ref-monty/crates/monty/src/modules/mod.rs +120 -0
- package/ref-monty/crates/monty/src/modules/os.rs +116 -0
- package/ref-monty/crates/monty/src/modules/pathlib.rs +33 -0
- package/ref-monty/crates/monty/src/modules/re.rs +606 -0
- package/ref-monty/crates/monty/src/modules/sys.rs +60 -0
- package/ref-monty/crates/monty/src/modules/typing.rs +70 -0
- package/ref-monty/crates/monty/src/namespace.rs +21 -0
- package/ref-monty/crates/monty/src/object.rs +1040 -0
- package/ref-monty/crates/monty/src/os.rs +215 -0
- package/ref-monty/crates/monty/src/parse.rs +1730 -0
- package/ref-monty/crates/monty/src/prepare.rs +3015 -0
- package/ref-monty/crates/monty/src/repl.rs +1109 -0
- package/ref-monty/crates/monty/src/resource.rs +559 -0
- package/ref-monty/crates/monty/src/run.rs +457 -0
- package/ref-monty/crates/monty/src/run_progress.rs +821 -0
- package/ref-monty/crates/monty/src/signature.rs +651 -0
- package/ref-monty/crates/monty/src/sorting.rs +100 -0
- package/ref-monty/crates/monty/src/types/bytes.rs +2356 -0
- package/ref-monty/crates/monty/src/types/dataclass.rs +345 -0
- package/ref-monty/crates/monty/src/types/dict.rs +879 -0
- package/ref-monty/crates/monty/src/types/dict_view.rs +619 -0
- package/ref-monty/crates/monty/src/types/iter.rs +799 -0
- package/ref-monty/crates/monty/src/types/list.rs +929 -0
- package/ref-monty/crates/monty/src/types/long_int.rs +211 -0
- package/ref-monty/crates/monty/src/types/mod.rs +48 -0
- package/ref-monty/crates/monty/src/types/module.rs +146 -0
- package/ref-monty/crates/monty/src/types/namedtuple.rs +261 -0
- package/ref-monty/crates/monty/src/types/path.rs +596 -0
- package/ref-monty/crates/monty/src/types/property.rs +35 -0
- package/ref-monty/crates/monty/src/types/py_trait.rs +322 -0
- package/ref-monty/crates/monty/src/types/range.rs +285 -0
- package/ref-monty/crates/monty/src/types/re_match.rs +522 -0
- package/ref-monty/crates/monty/src/types/re_pattern.rs +726 -0
- package/ref-monty/crates/monty/src/types/set.rs +1373 -0
- package/ref-monty/crates/monty/src/types/slice.rs +257 -0
- package/ref-monty/crates/monty/src/types/str.rs +2051 -0
- package/ref-monty/crates/monty/src/types/tuple.rs +376 -0
- package/ref-monty/crates/monty/src/types/type.rs +407 -0
- package/ref-monty/crates/monty/src/value.rs +2558 -0
- package/ref-monty/crates/monty/test_cases/args__dict_get_no_args.py +3 -0
- package/ref-monty/crates/monty/test_cases/args__dict_get_too_many.py +3 -0
- package/ref-monty/crates/monty/test_cases/args__dict_items_with_args.py +3 -0
- package/ref-monty/crates/monty/test_cases/args__dict_keys_with_args.py +3 -0
- package/ref-monty/crates/monty/test_cases/args__dict_pop_no_args.py +3 -0
- package/ref-monty/crates/monty/test_cases/args__dict_pop_too_many.py +3 -0
- package/ref-monty/crates/monty/test_cases/args__dict_values_with_args.py +3 -0
- package/ref-monty/crates/monty/test_cases/args__id_too_many.py +2 -0
- package/ref-monty/crates/monty/test_cases/args__len_no_args.py +2 -0
- package/ref-monty/crates/monty/test_cases/args__len_too_many.py +2 -0
- package/ref-monty/crates/monty/test_cases/args__len_type_error_int.py +9 -0
- package/ref-monty/crates/monty/test_cases/args__len_type_error_none.py +9 -0
- package/ref-monty/crates/monty/test_cases/args__list_append_no_args.py +3 -0
- package/ref-monty/crates/monty/test_cases/args__list_append_too_many.py +3 -0
- package/ref-monty/crates/monty/test_cases/args__list_insert_too_few.py +3 -0
- package/ref-monty/crates/monty/test_cases/args__list_insert_too_many.py +3 -0
- package/ref-monty/crates/monty/test_cases/args__repr_no_args.py +2 -0
- package/ref-monty/crates/monty/test_cases/arith__div_zero_float.py +2 -0
- package/ref-monty/crates/monty/test_cases/arith__div_zero_int.py +2 -0
- package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_float.py +2 -0
- package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_int.py +2 -0
- package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg.py +2 -0
- package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg_builtin.py +9 -0
- package/ref-monty/crates/monty/test_cases/assert__expr_fail.py +2 -0
- package/ref-monty/crates/monty/test_cases/assert__fail.py +2 -0
- package/ref-monty/crates/monty/test_cases/assert__fail_msg.py +2 -0
- package/ref-monty/crates/monty/test_cases/assert__fn_fail.py +3 -0
- package/ref-monty/crates/monty/test_cases/assert__ops.py +11 -0
- package/ref-monty/crates/monty/test_cases/async__asyncio_run.py +47 -0
- package/ref-monty/crates/monty/test_cases/async__basic.py +10 -0
- package/ref-monty/crates/monty/test_cases/async__closure.py +14 -0
- package/ref-monty/crates/monty/test_cases/async__double_await_coroutine.py +16 -0
- package/ref-monty/crates/monty/test_cases/async__exception.py +10 -0
- package/ref-monty/crates/monty/test_cases/async__ext_call.py +73 -0
- package/ref-monty/crates/monty/test_cases/async__gather_all.py +85 -0
- package/ref-monty/crates/monty/test_cases/async__nested_await.py +15 -0
- package/ref-monty/crates/monty/test_cases/async__nested_gather_ext.py +37 -0
- package/ref-monty/crates/monty/test_cases/async__not_awaitable.py +10 -0
- package/ref-monty/crates/monty/test_cases/async__not_imported.py +14 -0
- package/ref-monty/crates/monty/test_cases/async__recursion_depth_isolation.py +27 -0
- package/ref-monty/crates/monty/test_cases/async__return_types.py +31 -0
- package/ref-monty/crates/monty/test_cases/async__sequential.py +16 -0
- package/ref-monty/crates/monty/test_cases/async__traceback.py +19 -0
- package/ref-monty/crates/monty/test_cases/async__with_args.py +14 -0
- package/ref-monty/crates/monty/test_cases/attr__get_int_error.py +9 -0
- package/ref-monty/crates/monty/test_cases/attr__get_list_error.py +9 -0
- package/ref-monty/crates/monty/test_cases/attr__set_frozen_nonfield.py +12 -0
- package/ref-monty/crates/monty/test_cases/attr__set_int_error.py +10 -0
- package/ref-monty/crates/monty/test_cases/attr__set_list_error.py +10 -0
- package/ref-monty/crates/monty/test_cases/bench__kitchen_sink.py +68 -0
- package/ref-monty/crates/monty/test_cases/bool__ops.py +20 -0
- package/ref-monty/crates/monty/test_cases/builtin__add_type_error.py +2 -0
- package/ref-monty/crates/monty/test_cases/builtin__filter.py +62 -0
- package/ref-monty/crates/monty/test_cases/builtin__filter_not_iterable.py +11 -0
- package/ref-monty/crates/monty/test_cases/builtin__getattr.py +84 -0
- package/ref-monty/crates/monty/test_cases/builtin__iter_funcs.py +42 -0
- package/ref-monty/crates/monty/test_cases/builtin__iter_next.py +66 -0
- package/ref-monty/crates/monty/test_cases/builtin__map.py +74 -0
- package/ref-monty/crates/monty/test_cases/builtin__map_not_iterable.py +11 -0
- package/ref-monty/crates/monty/test_cases/builtin__math_funcs.py +154 -0
- package/ref-monty/crates/monty/test_cases/builtin__more_iter_funcs.py +148 -0
- package/ref-monty/crates/monty/test_cases/builtin__next_stop_iteration.py +10 -0
- package/ref-monty/crates/monty/test_cases/builtin__print_invalid_kwarg.py +9 -0
- package/ref-monty/crates/monty/test_cases/builtin__print_kwargs.py +12 -0
- package/ref-monty/crates/monty/test_cases/builtin__repr.py +3 -0
- package/ref-monty/crates/monty/test_cases/builtin__string_funcs.py +73 -0
- package/ref-monty/crates/monty/test_cases/bytes__decode_invalid_utf8.py +18 -0
- package/ref-monty/crates/monty/test_cases/bytes__endswith_str_error.py +10 -0
- package/ref-monty/crates/monty/test_cases/bytes__getitem_index_error.py +10 -0
- package/ref-monty/crates/monty/test_cases/bytes__index_start_gt_end.py +10 -0
- package/ref-monty/crates/monty/test_cases/bytes__methods.py +394 -0
- package/ref-monty/crates/monty/test_cases/bytes__negative_count.py +9 -0
- package/ref-monty/crates/monty/test_cases/bytes__ops.py +90 -0
- package/ref-monty/crates/monty/test_cases/bytes__startswith_str_error.py +10 -0
- package/ref-monty/crates/monty/test_cases/call_object.py +3 -0
- package/ref-monty/crates/monty/test_cases/chain_comparison__all.py +79 -0
- package/ref-monty/crates/monty/test_cases/closure__param_shadows_outer.py +81 -0
- package/ref-monty/crates/monty/test_cases/closure__pep448.py +203 -0
- package/ref-monty/crates/monty/test_cases/closure__undefined_nonlocal.py +13 -0
- package/ref-monty/crates/monty/test_cases/compare__mixed_types.py +120 -0
- package/ref-monty/crates/monty/test_cases/comprehension__all.py +208 -0
- package/ref-monty/crates/monty/test_cases/comprehension__scope.py +7 -0
- package/ref-monty/crates/monty/test_cases/comprehension__unbound_local.py +14 -0
- package/ref-monty/crates/monty/test_cases/dataclass__basic.py +238 -0
- package/ref-monty/crates/monty/test_cases/dataclass__call_field_error.py +12 -0
- package/ref-monty/crates/monty/test_cases/dataclass__frozen_set_error.py +12 -0
- package/ref-monty/crates/monty/test_cases/dataclass__get_missing_attr_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/dict__get_unhashable_key.py +3 -0
- package/ref-monty/crates/monty/test_cases/dict__literal_unhashable_key.py +2 -0
- package/ref-monty/crates/monty/test_cases/dict__method_pop_missing_error.py +3 -0
- package/ref-monty/crates/monty/test_cases/dict__methods.py +151 -0
- package/ref-monty/crates/monty/test_cases/dict__ops.py +133 -0
- package/ref-monty/crates/monty/test_cases/dict__pop_unhashable_key.py +4 -0
- package/ref-monty/crates/monty/test_cases/dict__popitem_empty.py +9 -0
- package/ref-monty/crates/monty/test_cases/dict__subscript_missing_key.py +3 -0
- package/ref-monty/crates/monty/test_cases/dict__unhashable_dict_key.py +2 -0
- package/ref-monty/crates/monty/test_cases/dict__unhashable_list_key.py +2 -0
- package/ref-monty/crates/monty/test_cases/dict__unpack_type_error.py +2 -0
- package/ref-monty/crates/monty/test_cases/dict__views.py +165 -0
- package/ref-monty/crates/monty/test_cases/edge__all.py +26 -0
- package/ref-monty/crates/monty/test_cases/edge__float_int_mod.py +2 -0
- package/ref-monty/crates/monty/test_cases/edge__int_float_mod.py +2 -0
- package/ref-monty/crates/monty/test_cases/exc__args.py +16 -0
- package/ref-monty/crates/monty/test_cases/exc__str.py +15 -0
- package/ref-monty/crates/monty/test_cases/execute_ok__all.py +54 -0
- package/ref-monty/crates/monty/test_cases/execute_raise__error_instance_str.py +2 -0
- package/ref-monty/crates/monty/test_cases/execute_raise__error_no_args.py +2 -0
- package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg.py +2 -0
- package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg_quotes.py +2 -0
- package/ref-monty/crates/monty/test_cases/execute_raise__error_type.py +2 -0
- package/ref-monty/crates/monty/test_cases/execute_raise__raise_instance_via_var.py +4 -0
- package/ref-monty/crates/monty/test_cases/execute_raise__raise_list.py +2 -0
- package/ref-monty/crates/monty/test_cases/execute_raise__raise_number.py +2 -0
- package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_call_via_var.py +4 -0
- package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_direct.py +3 -0
- package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_via_var.py +4 -0
- package/ref-monty/crates/monty/test_cases/ext_call__arg_side_effect_bug.py +22 -0
- package/ref-monty/crates/monty/test_cases/ext_call__augmented.py +17 -0
- package/ref-monty/crates/monty/test_cases/ext_call__augmented_refcount_bug.py +7 -0
- package/ref-monty/crates/monty/test_cases/ext_call__bare_raise_after_resume.py +34 -0
- package/ref-monty/crates/monty/test_cases/ext_call__basic.py +99 -0
- package/ref-monty/crates/monty/test_cases/ext_call__boolean.py +37 -0
- package/ref-monty/crates/monty/test_cases/ext_call__boolean_side_effect_hang.py +17 -0
- package/ref-monty/crates/monty/test_cases/ext_call__closure_bug.py +16 -0
- package/ref-monty/crates/monty/test_cases/ext_call__comparison.py +26 -0
- package/ref-monty/crates/monty/test_cases/ext_call__deep_call_stack.py +18 -0
- package/ref-monty/crates/monty/test_cases/ext_call__elif.py +171 -0
- package/ref-monty/crates/monty/test_cases/ext_call__exc.py +4 -0
- package/ref-monty/crates/monty/test_cases/ext_call__exc_deep_stack.py +39 -0
- package/ref-monty/crates/monty/test_cases/ext_call__exc_in_function.py +17 -0
- package/ref-monty/crates/monty/test_cases/ext_call__exc_nested_functions.py +31 -0
- package/ref-monty/crates/monty/test_cases/ext_call__ext_exc.py +171 -0
- package/ref-monty/crates/monty/test_cases/ext_call__for.py +114 -0
- package/ref-monty/crates/monty/test_cases/ext_call__fstring.py +12 -0
- package/ref-monty/crates/monty/test_cases/ext_call__if.py +135 -0
- package/ref-monty/crates/monty/test_cases/ext_call__if_condition.py +37 -0
- package/ref-monty/crates/monty/test_cases/ext_call__in_closure.py +14 -0
- package/ref-monty/crates/monty/test_cases/ext_call__in_function.py +40 -0
- package/ref-monty/crates/monty/test_cases/ext_call__in_function_simple.py +7 -0
- package/ref-monty/crates/monty/test_cases/ext_call__literals.py +17 -0
- package/ref-monty/crates/monty/test_cases/ext_call__multi_in_func.py +32 -0
- package/ref-monty/crates/monty/test_cases/ext_call__name_lookup.py +69 -0
- package/ref-monty/crates/monty/test_cases/ext_call__name_lookup_undefined.py +4 -0
- package/ref-monty/crates/monty/test_cases/ext_call__nested_calls.py +14 -0
- package/ref-monty/crates/monty/test_cases/ext_call__recursion_bug.py +19 -0
- package/ref-monty/crates/monty/test_cases/ext_call__return.py +28 -0
- package/ref-monty/crates/monty/test_cases/ext_call__side_effects.py +25 -0
- package/ref-monty/crates/monty/test_cases/ext_call__subscript.py +7 -0
- package/ref-monty/crates/monty/test_cases/ext_call__ternary.py +28 -0
- package/ref-monty/crates/monty/test_cases/ext_call__try.py +280 -0
- package/ref-monty/crates/monty/test_cases/ext_call__try_simple.py +10 -0
- package/ref-monty/crates/monty/test_cases/ext_call__unary.py +13 -0
- package/ref-monty/crates/monty/test_cases/frozenset__ops.py +178 -0
- package/ref-monty/crates/monty/test_cases/fstring__all.py +236 -0
- package/ref-monty/crates/monty/test_cases/fstring__error_eq_align_on_str.py +3 -0
- package/ref-monty/crates/monty/test_cases/fstring__error_float_f_on_str.py +3 -0
- package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_float.py +3 -0
- package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_str.py +3 -0
- package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec.py +4 -0
- package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_dynamic.py +4 -0
- package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_str.py +4 -0
- package/ref-monty/crates/monty/test_cases/fstring__error_str_s_on_int.py +3 -0
- package/ref-monty/crates/monty/test_cases/function__call_duplicate_kwargs.py +6 -0
- package/ref-monty/crates/monty/test_cases/function__call_unpack.py +42 -0
- package/ref-monty/crates/monty/test_cases/function__defaults.py +117 -0
- package/ref-monty/crates/monty/test_cases/function__err_duplicate_arg.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_duplicate_first_arg.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_duplicate_kwarg_cleanup.py +9 -0
- package/ref-monty/crates/monty/test_cases/function__err_kwonly_as_positional.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_missing_all_posonly.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_missing_heap_cleanup.py +9 -0
- package/ref-monty/crates/monty/test_cases/function__err_missing_kwonly.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_missing_posonly_with_kwarg.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_missing_with_posonly.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_posonly_as_kwarg.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_posonly_first_as_kwarg.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_too_many_posonly.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_too_many_with_kwonly.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_cleanup.py +9 -0
- package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_quote.py +13 -0
- package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_simple.py +7 -0
- package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_arg.py +6 -0
- package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_heap.py +8 -0
- package/ref-monty/crates/monty/test_cases/function__err_unpack_int.py +6 -0
- package/ref-monty/crates/monty/test_cases/function__err_unpack_nonstring_key.py +6 -0
- package/ref-monty/crates/monty/test_cases/function__err_unpack_not_mapping.py +6 -0
- package/ref-monty/crates/monty/test_cases/function__kwargs_unpacking.py +173 -0
- package/ref-monty/crates/monty/test_cases/function__ops.py +294 -0
- package/ref-monty/crates/monty/test_cases/function__return_none.py +42 -0
- package/ref-monty/crates/monty/test_cases/function__signatures.py +47 -0
- package/ref-monty/crates/monty/test_cases/function__too_few_args_all.py +6 -0
- package/ref-monty/crates/monty/test_cases/function__too_few_args_one.py +6 -0
- package/ref-monty/crates/monty/test_cases/function__too_few_args_two.py +6 -0
- package/ref-monty/crates/monty/test_cases/function__too_many_args_one.py +6 -0
- package/ref-monty/crates/monty/test_cases/function__too_many_args_two.py +6 -0
- package/ref-monty/crates/monty/test_cases/function__too_many_args_zero.py +6 -0
- package/ref-monty/crates/monty/test_cases/global__error_assigned_before.py +7 -0
- package/ref-monty/crates/monty/test_cases/global__ops.py +163 -0
- package/ref-monty/crates/monty/test_cases/hash__dict_unhashable.py +2 -0
- package/ref-monty/crates/monty/test_cases/hash__list_unhashable.py +2 -0
- package/ref-monty/crates/monty/test_cases/hash__ops.py +153 -0
- package/ref-monty/crates/monty/test_cases/id__bytes_literals_distinct.py +3 -0
- package/ref-monty/crates/monty/test_cases/id__int_copy_distinct.py +5 -0
- package/ref-monty/crates/monty/test_cases/id__is_number_is_number.py +3 -0
- package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_distinct_types.py +10 -0
- package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_same_types.py +6 -0
- package/ref-monty/crates/monty/test_cases/id__ops.py +97 -0
- package/ref-monty/crates/monty/test_cases/id__str_literals_same.py +3 -0
- package/ref-monty/crates/monty/test_cases/if__elif_else.py +207 -0
- package/ref-monty/crates/monty/test_cases/if__raise_elif.py +11 -0
- package/ref-monty/crates/monty/test_cases/if__raise_else.py +13 -0
- package/ref-monty/crates/monty/test_cases/if__raise_if.py +9 -0
- package/ref-monty/crates/monty/test_cases/if__raise_in_elif_condition.py +18 -0
- package/ref-monty/crates/monty/test_cases/if__raise_in_if_condition.py +16 -0
- package/ref-monty/crates/monty/test_cases/if_else_expr__all.py +55 -0
- package/ref-monty/crates/monty/test_cases/import__error_cannot_import.py +9 -0
- package/ref-monty/crates/monty/test_cases/import__error_module_not_found.py +9 -0
- package/ref-monty/crates/monty/test_cases/import__local_scope.py +68 -0
- package/ref-monty/crates/monty/test_cases/import__os.py +25 -0
- package/ref-monty/crates/monty/test_cases/import__relative_error.py +9 -0
- package/ref-monty/crates/monty/test_cases/import__relative_no_module_error.py +9 -0
- package/ref-monty/crates/monty/test_cases/import__runtime_error_when_executed.py +14 -0
- package/ref-monty/crates/monty/test_cases/import__star_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/import__sys.py +47 -0
- package/ref-monty/crates/monty/test_cases/import__sys_monty.py +28 -0
- package/ref-monty/crates/monty/test_cases/import__type_checking_guard.py +37 -0
- package/ref-monty/crates/monty/test_cases/import__typing.py +25 -0
- package/ref-monty/crates/monty/test_cases/import__typing_type_ignore.py +4 -0
- package/ref-monty/crates/monty/test_cases/int__bigint.py +467 -0
- package/ref-monty/crates/monty/test_cases/int__bigint_errors.py +260 -0
- package/ref-monty/crates/monty/test_cases/int__ops.py +219 -0
- package/ref-monty/crates/monty/test_cases/int__overflow_division.py +84 -0
- package/ref-monty/crates/monty/test_cases/is_variant__all.py +36 -0
- package/ref-monty/crates/monty/test_cases/isinstance__arg2_list_error.py +2 -0
- package/ref-monty/crates/monty/test_cases/isinstance__arg2_type_error.py +2 -0
- package/ref-monty/crates/monty/test_cases/iter__dict_mutation.py +4 -0
- package/ref-monty/crates/monty/test_cases/iter__for.py +243 -0
- package/ref-monty/crates/monty/test_cases/iter__for_loop_unpacking.py +66 -0
- package/ref-monty/crates/monty/test_cases/iter__generator_expr.py +20 -0
- package/ref-monty/crates/monty/test_cases/iter__generator_expr_type.py +7 -0
- package/ref-monty/crates/monty/test_cases/iter__not_iterable.py +3 -0
- package/ref-monty/crates/monty/test_cases/lambda__all.py +145 -0
- package/ref-monty/crates/monty/test_cases/list__extend_not_iterable.py +7 -0
- package/ref-monty/crates/monty/test_cases/list__getitem_out_of_bounds.py +3 -0
- package/ref-monty/crates/monty/test_cases/list__index_not_found.py +9 -0
- package/ref-monty/crates/monty/test_cases/list__index_start_gt_end.py +10 -0
- package/ref-monty/crates/monty/test_cases/list__ops.py +473 -0
- package/ref-monty/crates/monty/test_cases/list__pop_empty.py +9 -0
- package/ref-monty/crates/monty/test_cases/list__pop_out_of_range.py +9 -0
- package/ref-monty/crates/monty/test_cases/list__pop_type_error.py +9 -0
- package/ref-monty/crates/monty/test_cases/list__remove_not_found.py +9 -0
- package/ref-monty/crates/monty/test_cases/list__setitem_dict_index.py +13 -0
- package/ref-monty/crates/monty/test_cases/list__setitem_huge_int_index.py +13 -0
- package/ref-monty/crates/monty/test_cases/list__setitem_index_error.py +10 -0
- package/ref-monty/crates/monty/test_cases/list__setitem_type_error.py +10 -0
- package/ref-monty/crates/monty/test_cases/list__unpack_type_error.py +2 -0
- package/ref-monty/crates/monty/test_cases/longint__index_error.py +3 -0
- package/ref-monty/crates/monty/test_cases/longint__repeat_error.py +3 -0
- package/ref-monty/crates/monty/test_cases/loop__break_continue.py +113 -0
- package/ref-monty/crates/monty/test_cases/loop__break_finally.py +69 -0
- package/ref-monty/crates/monty/test_cases/loop__break_in_function_error.py +13 -0
- package/ref-monty/crates/monty/test_cases/loop__break_in_if_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/loop__break_nested_except_clears.py +55 -0
- package/ref-monty/crates/monty/test_cases/loop__break_outside_error.py +9 -0
- package/ref-monty/crates/monty/test_cases/loop__continue_finally.py +81 -0
- package/ref-monty/crates/monty/test_cases/loop__continue_in_function_error.py +13 -0
- package/ref-monty/crates/monty/test_cases/loop__continue_in_if_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/loop__continue_nested_except_clears.py +60 -0
- package/ref-monty/crates/monty/test_cases/loop__continue_outside_error.py +9 -0
- package/ref-monty/crates/monty/test_cases/math__acos_domain_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__acosh_domain_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__asin_domain_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__atanh_domain_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__cos_inf_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__cosh_overflow_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__exp_overflow_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__factorial_float_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__factorial_negative_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__floor_inf_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__floor_nan_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__floor_str_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__fmod_inf_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__gamma_neg_int_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__gcd_float_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__isqrt_negative_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__ldexp_overflow_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__log1p_domain_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__log_base1_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__log_zero_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__module.py +1432 -0
- package/ref-monty/crates/monty/test_cases/math__pow_domain_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__sin_inf_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__sqrt_negative_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__tan_inf_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/math__trunc_str_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/method__args_kwargs_unpacking.py +259 -0
- package/ref-monty/crates/monty/test_cases/name_error__unbound_local_func.py +19 -0
- package/ref-monty/crates/monty/test_cases/name_error__unbound_local_module.py +12 -0
- package/ref-monty/crates/monty/test_cases/name_error__undefined_call_chained.py +9 -0
- package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_expr.py +9 -0
- package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_function.py +16 -0
- package/ref-monty/crates/monty/test_cases/name_error__undefined_call_with_args.py +9 -0
- package/ref-monty/crates/monty/test_cases/name_error__undefined_global.py +10 -0
- package/ref-monty/crates/monty/test_cases/namedtuple__missing_attr.py +11 -0
- package/ref-monty/crates/monty/test_cases/namedtuple__ops.py +34 -0
- package/ref-monty/crates/monty/test_cases/nonlocal__error_module_level.py +3 -0
- package/ref-monty/crates/monty/test_cases/nonlocal__ops.py +353 -0
- package/ref-monty/crates/monty/test_cases/os__environ.py +40 -0
- package/ref-monty/crates/monty/test_cases/os__getenv_key_list_error.py +5 -0
- package/ref-monty/crates/monty/test_cases/os__getenv_key_type_error.py +5 -0
- package/ref-monty/crates/monty/test_cases/parse_error__complex.py +3 -0
- package/ref-monty/crates/monty/test_cases/pathlib__import.py +11 -0
- package/ref-monty/crates/monty/test_cases/pathlib__os.py +136 -0
- package/ref-monty/crates/monty/test_cases/pathlib__os_read_error.py +12 -0
- package/ref-monty/crates/monty/test_cases/pathlib__pure.py +81 -0
- package/ref-monty/crates/monty/test_cases/pyobject__cycle_dict_self.py +5 -0
- package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_dict.py +6 -0
- package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_self.py +5 -0
- package/ref-monty/crates/monty/test_cases/pyobject__cycle_multiple_refs.py +6 -0
- package/ref-monty/crates/monty/test_cases/range__error_no_args.py +2 -0
- package/ref-monty/crates/monty/test_cases/range__error_step_zero.py +2 -0
- package/ref-monty/crates/monty/test_cases/range__error_too_many_args.py +2 -0
- package/ref-monty/crates/monty/test_cases/range__getitem_index_error.py +10 -0
- package/ref-monty/crates/monty/test_cases/range__ops.py +236 -0
- package/ref-monty/crates/monty/test_cases/re__basic.py +756 -0
- package/ref-monty/crates/monty/test_cases/re__grouping.py +241 -0
- package/ref-monty/crates/monty/test_cases/re__match.py +148 -0
- package/ref-monty/crates/monty/test_cases/recursion__deep_drop.py +26 -0
- package/ref-monty/crates/monty/test_cases/recursion__deep_eq.py +23 -0
- package/ref-monty/crates/monty/test_cases/recursion__deep_hash.py +46 -0
- package/ref-monty/crates/monty/test_cases/recursion__deep_repr.py +12 -0
- package/ref-monty/crates/monty/test_cases/recursion__function_depth.py +13 -0
- package/ref-monty/crates/monty/test_cases/refcount__cycle_mutual_reference.py +18 -0
- package/ref-monty/crates/monty/test_cases/refcount__cycle_self_reference.py +12 -0
- package/ref-monty/crates/monty/test_cases/refcount__dict_basic.py +5 -0
- package/ref-monty/crates/monty/test_cases/refcount__dict_get.py +5 -0
- package/ref-monty/crates/monty/test_cases/refcount__dict_keys_and.py +14 -0
- package/ref-monty/crates/monty/test_cases/refcount__dict_overwrite.py +6 -0
- package/ref-monty/crates/monty/test_cases/refcount__gather_cleanup.py +16 -0
- package/ref-monty/crates/monty/test_cases/refcount__gather_exception.py +18 -0
- package/ref-monty/crates/monty/test_cases/refcount__gather_nested_cancel.py +25 -0
- package/ref-monty/crates/monty/test_cases/refcount__immediate_skipped.py +4 -0
- package/ref-monty/crates/monty/test_cases/refcount__kwargs_unpacking.py +27 -0
- package/ref-monty/crates/monty/test_cases/refcount__list_append_multiple.py +6 -0
- package/ref-monty/crates/monty/test_cases/refcount__list_append_ref.py +5 -0
- package/ref-monty/crates/monty/test_cases/refcount__list_concat.py +5 -0
- package/ref-monty/crates/monty/test_cases/refcount__list_getitem.py +5 -0
- package/ref-monty/crates/monty/test_cases/refcount__list_iadd.py +5 -0
- package/ref-monty/crates/monty/test_cases/refcount__nested_list.py +4 -0
- package/ref-monty/crates/monty/test_cases/refcount__re_pattern_sub_error_paths.py +37 -0
- package/ref-monty/crates/monty/test_cases/refcount__re_search_match.py +34 -0
- package/ref-monty/crates/monty/test_cases/refcount__re_sub_error_paths.py +31 -0
- package/ref-monty/crates/monty/test_cases/refcount__shared_reference.py +4 -0
- package/ref-monty/crates/monty/test_cases/refcount__single_list.py +3 -0
- package/ref-monty/crates/monty/test_cases/repr__cycle_detection.py +24 -0
- package/ref-monty/crates/monty/test_cases/set__ops.py +191 -0
- package/ref-monty/crates/monty/test_cases/set__review_bugs.py +35 -0
- package/ref-monty/crates/monty/test_cases/set__unpack_type_error.py +2 -0
- package/ref-monty/crates/monty/test_cases/slice__invalid_indices.py +2 -0
- package/ref-monty/crates/monty/test_cases/slice__kwargs.py +9 -0
- package/ref-monty/crates/monty/test_cases/slice__no_args.py +9 -0
- package/ref-monty/crates/monty/test_cases/slice__ops.py +149 -0
- package/ref-monty/crates/monty/test_cases/slice__step_zero.py +9 -0
- package/ref-monty/crates/monty/test_cases/slice__step_zero_bytes.py +9 -0
- package/ref-monty/crates/monty/test_cases/slice__step_zero_range.py +9 -0
- package/ref-monty/crates/monty/test_cases/slice__step_zero_str.py +9 -0
- package/ref-monty/crates/monty/test_cases/slice__step_zero_tuple.py +9 -0
- package/ref-monty/crates/monty/test_cases/slice__too_many_args.py +9 -0
- package/ref-monty/crates/monty/test_cases/str__getitem_index_error.py +10 -0
- package/ref-monty/crates/monty/test_cases/str__index_not_found.py +9 -0
- package/ref-monty/crates/monty/test_cases/str__join_no_args.py +9 -0
- package/ref-monty/crates/monty/test_cases/str__join_non_string.py +9 -0
- package/ref-monty/crates/monty/test_cases/str__join_not_iterable.py +9 -0
- package/ref-monty/crates/monty/test_cases/str__join_too_many_args.py +9 -0
- package/ref-monty/crates/monty/test_cases/str__methods.py +327 -0
- package/ref-monty/crates/monty/test_cases/str__ops.py +162 -0
- package/ref-monty/crates/monty/test_cases/str__partition_empty.py +9 -0
- package/ref-monty/crates/monty/test_cases/str__rsplit_empty_sep.py +9 -0
- package/ref-monty/crates/monty/test_cases/str__split_empty_sep.py +9 -0
- package/ref-monty/crates/monty/test_cases/sys__types.py +7 -0
- package/ref-monty/crates/monty/test_cases/traceback__division_error.py +30 -0
- package/ref-monty/crates/monty/test_cases/traceback__index_error.py +17 -0
- package/ref-monty/crates/monty/test_cases/traceback__insert_as_int.py +10 -0
- package/ref-monty/crates/monty/test_cases/traceback__nested_call.py +29 -0
- package/ref-monty/crates/monty/test_cases/traceback__nonlocal_module_scope.py +10 -0
- package/ref-monty/crates/monty/test_cases/traceback__nonlocal_unbound.py +24 -0
- package/ref-monty/crates/monty/test_cases/traceback__range_as_int.py +9 -0
- package/ref-monty/crates/monty/test_cases/traceback__recursion_error.py +23 -0
- package/ref-monty/crates/monty/test_cases/traceback__set_mutation.py +11 -0
- package/ref-monty/crates/monty/test_cases/traceback__undefined_attr_call.py +16 -0
- package/ref-monty/crates/monty/test_cases/traceback__undefined_call.py +16 -0
- package/ref-monty/crates/monty/test_cases/traceback__undefined_raise.py +16 -0
- package/ref-monty/crates/monty/test_cases/try_except__all.py +472 -0
- package/ref-monty/crates/monty/test_cases/try_except__bare_raise_no_context.py +2 -0
- package/ref-monty/crates/monty/test_cases/try_except__invalid_type.py +5 -0
- package/ref-monty/crates/monty/test_cases/tuple__getitem_out_of_bounds.py +3 -0
- package/ref-monty/crates/monty/test_cases/tuple__index_not_found.py +9 -0
- package/ref-monty/crates/monty/test_cases/tuple__index_start_gt_end.py +10 -0
- package/ref-monty/crates/monty/test_cases/tuple__methods.py +19 -0
- package/ref-monty/crates/monty/test_cases/tuple__ops.py +133 -0
- package/ref-monty/crates/monty/test_cases/tuple__unpack_type_error.py +2 -0
- package/ref-monty/crates/monty/test_cases/type__builtin_attr_error.py +9 -0
- package/ref-monty/crates/monty/test_cases/type__bytes_negative.py +2 -0
- package/ref-monty/crates/monty/test_cases/type__cell_not_builtin.py +9 -0
- package/ref-monty/crates/monty/test_cases/type__exception_attr_error.py +11 -0
- package/ref-monty/crates/monty/test_cases/type__float_conversion_error.py +2 -0
- package/ref-monty/crates/monty/test_cases/type__float_repr_both_quotes.py +9 -0
- package/ref-monty/crates/monty/test_cases/type__float_repr_newline.py +9 -0
- package/ref-monty/crates/monty/test_cases/type__float_repr_single_quote.py +9 -0
- package/ref-monty/crates/monty/test_cases/type__int_conversion_error.py +2 -0
- package/ref-monty/crates/monty/test_cases/type__list_not_iterable.py +2 -0
- package/ref-monty/crates/monty/test_cases/type__non_builtin_name_error.py +9 -0
- package/ref-monty/crates/monty/test_cases/type__ops.py +200 -0
- package/ref-monty/crates/monty/test_cases/type__shadow_exc.py +3 -0
- package/ref-monty/crates/monty/test_cases/type__shadow_int.py +9 -0
- package/ref-monty/crates/monty/test_cases/type__shadow_len.py +3 -0
- package/ref-monty/crates/monty/test_cases/type__tuple_not_iterable.py +2 -0
- package/ref-monty/crates/monty/test_cases/type_error__int_add_list.py +2 -0
- package/ref-monty/crates/monty/test_cases/type_error__int_div_str.py +2 -0
- package/ref-monty/crates/monty/test_cases/type_error__int_floordiv_str.py +2 -0
- package/ref-monty/crates/monty/test_cases/type_error__int_iadd_str.py +3 -0
- package/ref-monty/crates/monty/test_cases/type_error__int_mod_str.py +2 -0
- package/ref-monty/crates/monty/test_cases/type_error__int_pow_str.py +2 -0
- package/ref-monty/crates/monty/test_cases/type_error__int_sub_str.py +2 -0
- package/ref-monty/crates/monty/test_cases/type_error__list_add_int.py +2 -0
- package/ref-monty/crates/monty/test_cases/type_error__list_add_str.py +2 -0
- package/ref-monty/crates/monty/test_cases/type_error__list_iadd_int.py +6 -0
- package/ref-monty/crates/monty/test_cases/type_error__str_add_int.py +2 -0
- package/ref-monty/crates/monty/test_cases/type_error__str_iadd_int.py +3 -0
- package/ref-monty/crates/monty/test_cases/type_error__unary_invert_str.py +3 -0
- package/ref-monty/crates/monty/test_cases/type_error__unary_minus_str.py +4 -0
- package/ref-monty/crates/monty/test_cases/type_error__unary_neg_str.py +3 -0
- package/ref-monty/crates/monty/test_cases/type_error__unary_plus_str.py +4 -0
- package/ref-monty/crates/monty/test_cases/typing__types.py +24 -0
- package/ref-monty/crates/monty/test_cases/unpack__nested.py +48 -0
- package/ref-monty/crates/monty/test_cases/unpack__non_sequence.py +9 -0
- package/ref-monty/crates/monty/test_cases/unpack__not_enough.py +9 -0
- package/ref-monty/crates/monty/test_cases/unpack__ops.py +153 -0
- package/ref-monty/crates/monty/test_cases/unpack__star_not_enough.py +9 -0
- package/ref-monty/crates/monty/test_cases/unpack__too_many.py +9 -0
- package/ref-monty/crates/monty/test_cases/version__cpython.py +4 -0
- package/ref-monty/crates/monty/test_cases/walrus__all.py +178 -0
- package/ref-monty/crates/monty/test_cases/while__all.py +206 -0
- package/ref-monty/crates/monty/tests/asyncio.rs +764 -0
- package/ref-monty/crates/monty/tests/binary_serde.rs +185 -0
- package/ref-monty/crates/monty/tests/bytecode_limits.rs +248 -0
- package/ref-monty/crates/monty/tests/datatest_runner.rs +2029 -0
- package/ref-monty/crates/monty/tests/inputs.rs +420 -0
- package/ref-monty/crates/monty/tests/json_serde.rs +250 -0
- package/ref-monty/crates/monty/tests/main.rs +71 -0
- package/ref-monty/crates/monty/tests/math_module.rs +114 -0
- package/ref-monty/crates/monty/tests/name_lookup.rs +482 -0
- package/ref-monty/crates/monty/tests/os_tests.rs +459 -0
- package/ref-monty/crates/monty/tests/parse_errors.rs +441 -0
- package/ref-monty/crates/monty/tests/print_writer.rs +238 -0
- package/ref-monty/crates/monty/tests/py_object.rs +121 -0
- package/ref-monty/crates/monty/tests/regex.rs +90 -0
- package/ref-monty/crates/monty/tests/repl.rs +344 -0
- package/ref-monty/crates/monty/tests/resource_limits.rs +1826 -0
- package/ref-monty/crates/monty/tests/try_from.rs +167 -0
- package/ref-monty/crates/monty-cli/Cargo.toml +25 -0
- package/ref-monty/crates/monty-cli/src/main.rs +541 -0
- package/ref-monty/crates/monty-js/.cargo/config.toml +2 -0
- package/ref-monty/crates/monty-js/.prettierignore +8 -0
- package/ref-monty/crates/monty-js/Cargo.toml +32 -0
- package/ref-monty/crates/monty-js/README.md +207 -0
- package/ref-monty/crates/monty-js/__test__/async.spec.ts +350 -0
- package/ref-monty/crates/monty-js/__test__/basic.spec.ts +114 -0
- package/ref-monty/crates/monty-js/__test__/exceptions.spec.ts +427 -0
- package/ref-monty/crates/monty-js/__test__/external.spec.ts +354 -0
- package/ref-monty/crates/monty-js/__test__/inputs.spec.ts +143 -0
- package/ref-monty/crates/monty-js/__test__/limits.spec.ts +162 -0
- package/ref-monty/crates/monty-js/__test__/package.json +3 -0
- package/ref-monty/crates/monty-js/__test__/print.spec.ts +229 -0
- package/ref-monty/crates/monty-js/__test__/repl.spec.ts +34 -0
- package/ref-monty/crates/monty-js/__test__/serialize.spec.ts +205 -0
- package/ref-monty/crates/monty-js/__test__/start.spec.ts +443 -0
- package/ref-monty/crates/monty-js/__test__/type_check.spec.ts +147 -0
- package/ref-monty/crates/monty-js/__test__/types.spec.ts +319 -0
- package/ref-monty/crates/monty-js/build.rs +61 -0
- package/ref-monty/crates/monty-js/index-header.d.ts +3 -0
- package/ref-monty/crates/monty-js/package-lock.json +4694 -0
- package/ref-monty/crates/monty-js/package.json +100 -0
- package/ref-monty/crates/monty-js/scripts/smoke-test.sh +69 -0
- package/ref-monty/crates/monty-js/smoke-test/package.json +17 -0
- package/ref-monty/crates/monty-js/smoke-test/test.ts +171 -0
- package/ref-monty/crates/monty-js/smoke-test/tsconfig.json +11 -0
- package/ref-monty/crates/monty-js/src/convert.rs +648 -0
- package/ref-monty/crates/monty-js/src/exceptions.rs +293 -0
- package/ref-monty/crates/monty-js/src/lib.rs +41 -0
- package/ref-monty/crates/monty-js/src/limits.rs +53 -0
- package/ref-monty/crates/monty-js/src/monty_cls.rs +1407 -0
- package/ref-monty/crates/monty-js/tsconfig.json +17 -0
- package/ref-monty/crates/monty-js/wrapper.ts +701 -0
- package/ref-monty/crates/monty-python/Cargo.toml +38 -0
- package/ref-monty/crates/monty-python/README.md +134 -0
- package/ref-monty/crates/monty-python/build.rs +4 -0
- package/ref-monty/crates/monty-python/example.py +40 -0
- package/ref-monty/crates/monty-python/exercise.py +46 -0
- package/ref-monty/crates/monty-python/pyproject.toml +57 -0
- package/ref-monty/crates/monty-python/python/pydantic_monty/__init__.py +281 -0
- package/ref-monty/crates/monty-python/python/pydantic_monty/_monty.pyi +677 -0
- package/ref-monty/crates/monty-python/python/pydantic_monty/os_access.py +933 -0
- package/ref-monty/crates/monty-python/python/pydantic_monty/py.typed +0 -0
- package/ref-monty/crates/monty-python/src/convert.rs +273 -0
- package/ref-monty/crates/monty-python/src/dataclass.rs +461 -0
- package/ref-monty/crates/monty-python/src/exceptions.rs +557 -0
- package/ref-monty/crates/monty-python/src/external.rs +165 -0
- package/ref-monty/crates/monty-python/src/lib.rs +77 -0
- package/ref-monty/crates/monty-python/src/limits.rs +142 -0
- package/ref-monty/crates/monty-python/src/monty_cls.rs +1650 -0
- package/ref-monty/crates/monty-python/src/repl.rs +470 -0
- package/ref-monty/crates/monty-python/src/serialization.rs +761 -0
- package/ref-monty/crates/monty-python/tests/test_async.py +1201 -0
- package/ref-monty/crates/monty-python/tests/test_basic.py +66 -0
- package/ref-monty/crates/monty-python/tests/test_dataclasses.py +971 -0
- package/ref-monty/crates/monty-python/tests/test_exceptions.py +361 -0
- package/ref-monty/crates/monty-python/tests/test_external.py +367 -0
- package/ref-monty/crates/monty-python/tests/test_inputs.py +126 -0
- package/ref-monty/crates/monty-python/tests/test_limits.py +257 -0
- package/ref-monty/crates/monty-python/tests/test_os_access.py +1286 -0
- package/ref-monty/crates/monty-python/tests/test_os_access_compat.py +731 -0
- package/ref-monty/crates/monty-python/tests/test_os_access_raw.py +483 -0
- package/ref-monty/crates/monty-python/tests/test_os_calls.py +819 -0
- package/ref-monty/crates/monty-python/tests/test_print.py +208 -0
- package/ref-monty/crates/monty-python/tests/test_re.py +170 -0
- package/ref-monty/crates/monty-python/tests/test_readme_examples.py +20 -0
- package/ref-monty/crates/monty-python/tests/test_repl.py +749 -0
- package/ref-monty/crates/monty-python/tests/test_serialize.py +284 -0
- package/ref-monty/crates/monty-python/tests/test_start.py +346 -0
- package/ref-monty/crates/monty-python/tests/test_threading.py +163 -0
- package/ref-monty/crates/monty-python/tests/test_type_check.py +344 -0
- package/ref-monty/crates/monty-python/tests/test_types.py +553 -0
- package/ref-monty/crates/monty-type-checking/Cargo.toml +32 -0
- package/ref-monty/crates/monty-type-checking/src/db.rs +116 -0
- package/ref-monty/crates/monty-type-checking/src/lib.rs +4 -0
- package/ref-monty/crates/monty-type-checking/src/type_check.rs +280 -0
- package/ref-monty/crates/monty-type-checking/tests/bad_types.py +109 -0
- package/ref-monty/crates/monty-type-checking/tests/bad_types_output.txt +21 -0
- package/ref-monty/crates/monty-type-checking/tests/good_types.py +475 -0
- package/ref-monty/crates/monty-type-checking/tests/main.rs +205 -0
- package/ref-monty/crates/monty-type-checking/tests/reveal_types.py +56 -0
- package/ref-monty/crates/monty-type-checking/tests/reveal_types_output.txt +41 -0
- package/ref-monty/crates/monty-typeshed/Cargo.toml +29 -0
- package/ref-monty/crates/monty-typeshed/README.md +11 -0
- package/ref-monty/crates/monty-typeshed/build.rs +101 -0
- package/ref-monty/crates/monty-typeshed/custom/README.md +1 -0
- package/ref-monty/crates/monty-typeshed/custom/asyncio.pyi +138 -0
- package/ref-monty/crates/monty-typeshed/custom/os.pyi +87 -0
- package/ref-monty/crates/monty-typeshed/custom/sys.pyi +33 -0
- package/ref-monty/crates/monty-typeshed/src/lib.rs +56 -0
- package/ref-monty/crates/monty-typeshed/update.py +321 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/source_commit.txt +1 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/VERSIONS +20 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_collections_abc.pyi +105 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_typeshed/__init__.pyi +394 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/asyncio.pyi +138 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/builtins.pyi +1434 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/__init__.pyi +527 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/abc.pyi +2 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/dataclasses.pyi +502 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/enum.pyi +376 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/math.pyi +149 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/os.pyi +87 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/__init__.pyi +395 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/types.pyi +8 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/re.pyi +337 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/sys.pyi +33 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/types.pyi +741 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing.pyi +1217 -0
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing_extensions.pyi +716 -0
- package/ref-monty/docs/usage-guide.md +117 -0
- package/ref-monty/examples/README.md +3 -0
- package/ref-monty/examples/expense_analysis/README.md +3 -0
- package/ref-monty/examples/expense_analysis/data.py +124 -0
- package/ref-monty/examples/expense_analysis/main.py +115 -0
- package/ref-monty/examples/sql_playground/README.md +20 -0
- package/ref-monty/examples/sql_playground/external_functions.py +129 -0
- package/ref-monty/examples/sql_playground/main.py +81 -0
- package/ref-monty/examples/sql_playground/sandbox_code.py +82 -0
- package/ref-monty/examples/sql_playground/type_stubs.pyi +14 -0
- package/ref-monty/examples/web_scraper/README.md +15 -0
- package/ref-monty/examples/web_scraper/browser.py +56 -0
- package/ref-monty/examples/web_scraper/example_code.py +59 -0
- package/ref-monty/examples/web_scraper/external_functions.py +324 -0
- package/ref-monty/examples/web_scraper/main.py +193 -0
- package/ref-monty/examples/web_scraper/sub_agent.py +79 -0
- package/ref-monty/monty-npm.md +235 -0
- package/ref-monty/pyproject.toml +162 -0
- package/ref-monty/scripts/check_imports.py +91 -0
- package/ref-monty/scripts/codecov_diff.py +412 -0
- package/ref-monty/scripts/complete_tests.py +146 -0
- package/ref-monty/scripts/flamegraph_to_text.py +208 -0
- package/ref-monty/scripts/iter_test_methods.py +540 -0
- package/ref-monty/scripts/run_traceback.py +180 -0
- package/ref-monty/scripts/startup_performance.py +130 -0
- package/ref-monty/uv.lock +1779 -0
- package/temp_resend_cli/repo/.github/scripts/pr-title-check.js +34 -0
- package/temp_resend_cli/repo/.github/workflows/ci.yml +67 -0
- package/temp_resend_cli/repo/.github/workflows/post-release.yml +51 -0
- package/temp_resend_cli/repo/.github/workflows/pr-title-check.yml +13 -0
- package/temp_resend_cli/repo/.github/workflows/release.yml +175 -0
- package/temp_resend_cli/repo/.github/workflows/test-install-unix.yml +34 -0
- package/temp_resend_cli/repo/.github/workflows/test-install-windows.yml +48 -0
- package/temp_resend_cli/repo/CHANGELOG.md +31 -0
- package/temp_resend_cli/repo/LICENSE +21 -0
- package/temp_resend_cli/repo/README.md +450 -0
- package/temp_resend_cli/repo/biome.json +36 -0
- package/temp_resend_cli/repo/install.ps1 +141 -0
- package/temp_resend_cli/repo/install.sh +301 -0
- package/temp_resend_cli/repo/package.json +61 -0
- package/temp_resend_cli/repo/pnpm-lock.yaml +2439 -0
- package/temp_resend_cli/repo/renovate.json +4 -0
- package/temp_resend_cli/repo/src/cli.ts +98 -0
- package/temp_resend_cli/repo/src/commands/api-keys/create.ts +114 -0
- package/temp_resend_cli/repo/src/commands/api-keys/delete.ts +47 -0
- package/temp_resend_cli/repo/src/commands/api-keys/index.ts +26 -0
- package/temp_resend_cli/repo/src/commands/api-keys/list.ts +35 -0
- package/temp_resend_cli/repo/src/commands/api-keys/utils.ts +8 -0
- package/temp_resend_cli/repo/src/commands/auth/index.ts +20 -0
- package/temp_resend_cli/repo/src/commands/auth/login.ts +234 -0
- package/temp_resend_cli/repo/src/commands/auth/logout.ts +105 -0
- package/temp_resend_cli/repo/src/commands/broadcasts/create.ts +196 -0
- package/temp_resend_cli/repo/src/commands/broadcasts/delete.ts +46 -0
- package/temp_resend_cli/repo/src/commands/broadcasts/get.ts +59 -0
- package/temp_resend_cli/repo/src/commands/broadcasts/index.ts +43 -0
- package/temp_resend_cli/repo/src/commands/broadcasts/list.ts +60 -0
- package/temp_resend_cli/repo/src/commands/broadcasts/send.ts +56 -0
- package/temp_resend_cli/repo/src/commands/broadcasts/update.ts +95 -0
- package/temp_resend_cli/repo/src/commands/broadcasts/utils.ts +35 -0
- package/temp_resend_cli/repo/src/commands/contact-properties/create.ts +118 -0
- package/temp_resend_cli/repo/src/commands/contact-properties/delete.ts +48 -0
- package/temp_resend_cli/repo/src/commands/contact-properties/get.ts +46 -0
- package/temp_resend_cli/repo/src/commands/contact-properties/index.ts +48 -0
- package/temp_resend_cli/repo/src/commands/contact-properties/list.ts +68 -0
- package/temp_resend_cli/repo/src/commands/contact-properties/update.ts +88 -0
- package/temp_resend_cli/repo/src/commands/contact-properties/utils.ts +17 -0
- package/temp_resend_cli/repo/src/commands/contacts/add-segment.ts +78 -0
- package/temp_resend_cli/repo/src/commands/contacts/create.ts +122 -0
- package/temp_resend_cli/repo/src/commands/contacts/delete.ts +49 -0
- package/temp_resend_cli/repo/src/commands/contacts/get.ts +53 -0
- package/temp_resend_cli/repo/src/commands/contacts/index.ts +58 -0
- package/temp_resend_cli/repo/src/commands/contacts/list.ts +57 -0
- package/temp_resend_cli/repo/src/commands/contacts/remove-segment.ts +48 -0
- package/temp_resend_cli/repo/src/commands/contacts/segments.ts +39 -0
- package/temp_resend_cli/repo/src/commands/contacts/topics.ts +45 -0
- package/temp_resend_cli/repo/src/commands/contacts/update-topics.ts +90 -0
- package/temp_resend_cli/repo/src/commands/contacts/update.ts +77 -0
- package/temp_resend_cli/repo/src/commands/contacts/utils.ts +119 -0
- package/temp_resend_cli/repo/src/commands/doctor.ts +216 -0
- package/temp_resend_cli/repo/src/commands/domains/create.ts +83 -0
- package/temp_resend_cli/repo/src/commands/domains/delete.ts +42 -0
- package/temp_resend_cli/repo/src/commands/domains/get.ts +47 -0
- package/temp_resend_cli/repo/src/commands/domains/index.ts +35 -0
- package/temp_resend_cli/repo/src/commands/domains/list.ts +53 -0
- package/temp_resend_cli/repo/src/commands/domains/update.ts +75 -0
- package/temp_resend_cli/repo/src/commands/domains/utils.ts +44 -0
- package/temp_resend_cli/repo/src/commands/domains/verify.ts +38 -0
- package/temp_resend_cli/repo/src/commands/emails/batch.ts +140 -0
- package/temp_resend_cli/repo/src/commands/emails/get.ts +44 -0
- package/temp_resend_cli/repo/src/commands/emails/index.ts +30 -0
- package/temp_resend_cli/repo/src/commands/emails/list.ts +84 -0
- package/temp_resend_cli/repo/src/commands/emails/receiving/attachment.ts +55 -0
- package/temp_resend_cli/repo/src/commands/emails/receiving/attachments.ts +68 -0
- package/temp_resend_cli/repo/src/commands/emails/receiving/get.ts +58 -0
- package/temp_resend_cli/repo/src/commands/emails/receiving/index.ts +28 -0
- package/temp_resend_cli/repo/src/commands/emails/receiving/list.ts +59 -0
- package/temp_resend_cli/repo/src/commands/emails/receiving/utils.ts +38 -0
- package/temp_resend_cli/repo/src/commands/emails/send.ts +189 -0
- package/temp_resend_cli/repo/src/commands/open.ts +27 -0
- package/temp_resend_cli/repo/src/commands/segments/create.ts +50 -0
- package/temp_resend_cli/repo/src/commands/segments/delete.ts +47 -0
- package/temp_resend_cli/repo/src/commands/segments/get.ts +38 -0
- package/temp_resend_cli/repo/src/commands/segments/index.ts +36 -0
- package/temp_resend_cli/repo/src/commands/segments/list.ts +58 -0
- package/temp_resend_cli/repo/src/commands/segments/utils.ts +7 -0
- package/temp_resend_cli/repo/src/commands/teams/index.ts +10 -0
- package/temp_resend_cli/repo/src/commands/teams/list.ts +35 -0
- package/temp_resend_cli/repo/src/commands/teams/remove.ts +86 -0
- package/temp_resend_cli/repo/src/commands/teams/switch.ts +76 -0
- package/temp_resend_cli/repo/src/commands/topics/create.ts +73 -0
- package/temp_resend_cli/repo/src/commands/topics/delete.ts +47 -0
- package/temp_resend_cli/repo/src/commands/topics/get.ts +42 -0
- package/temp_resend_cli/repo/src/commands/topics/index.ts +42 -0
- package/temp_resend_cli/repo/src/commands/topics/list.ts +34 -0
- package/temp_resend_cli/repo/src/commands/topics/update.ts +59 -0
- package/temp_resend_cli/repo/src/commands/topics/utils.ts +16 -0
- package/temp_resend_cli/repo/src/commands/webhooks/create.ts +128 -0
- package/temp_resend_cli/repo/src/commands/webhooks/delete.ts +49 -0
- package/temp_resend_cli/repo/src/commands/webhooks/get.ts +42 -0
- package/temp_resend_cli/repo/src/commands/webhooks/index.ts +42 -0
- package/temp_resend_cli/repo/src/commands/webhooks/list.ts +55 -0
- package/temp_resend_cli/repo/src/commands/webhooks/listen.ts +379 -0
- package/temp_resend_cli/repo/src/commands/webhooks/update.ts +83 -0
- package/temp_resend_cli/repo/src/commands/webhooks/utils.ts +36 -0
- package/temp_resend_cli/repo/src/commands/whoami.ts +71 -0
- package/temp_resend_cli/repo/src/lib/actions.ts +157 -0
- package/temp_resend_cli/repo/src/lib/client.ts +37 -0
- package/temp_resend_cli/repo/src/lib/config.ts +217 -0
- package/temp_resend_cli/repo/src/lib/files.ts +15 -0
- package/temp_resend_cli/repo/src/lib/help-text.ts +38 -0
- package/temp_resend_cli/repo/src/lib/output.ts +56 -0
- package/temp_resend_cli/repo/src/lib/pagination.ts +36 -0
- package/temp_resend_cli/repo/src/lib/prompts.ts +149 -0
- package/temp_resend_cli/repo/src/lib/spinner.ts +100 -0
- package/temp_resend_cli/repo/src/lib/table.ts +57 -0
- package/temp_resend_cli/repo/src/lib/tty.ts +28 -0
- package/temp_resend_cli/repo/src/lib/update-check.ts +169 -0
- package/temp_resend_cli/repo/src/lib/version.ts +4 -0
- package/temp_resend_cli/repo/tests/commands/api-keys/create.test.ts +196 -0
- package/temp_resend_cli/repo/tests/commands/api-keys/delete.test.ts +157 -0
- package/temp_resend_cli/repo/tests/commands/api-keys/list.test.ts +134 -0
- package/temp_resend_cli/repo/tests/commands/auth/login.test.ts +153 -0
- package/temp_resend_cli/repo/tests/commands/auth/logout.test.ts +153 -0
- package/temp_resend_cli/repo/tests/commands/broadcasts/create.test.ts +454 -0
- package/temp_resend_cli/repo/tests/commands/broadcasts/delete.test.ts +183 -0
- package/temp_resend_cli/repo/tests/commands/broadcasts/get.test.ts +147 -0
- package/temp_resend_cli/repo/tests/commands/broadcasts/list.test.ts +199 -0
- package/temp_resend_cli/repo/tests/commands/broadcasts/send.test.ts +162 -0
- package/temp_resend_cli/repo/tests/commands/broadcasts/update.test.ts +288 -0
- package/temp_resend_cli/repo/tests/commands/contact-properties/create.test.ts +251 -0
- package/temp_resend_cli/repo/tests/commands/contact-properties/delete.test.ts +184 -0
- package/temp_resend_cli/repo/tests/commands/contact-properties/get.test.ts +145 -0
- package/temp_resend_cli/repo/tests/commands/contact-properties/list.test.ts +181 -0
- package/temp_resend_cli/repo/tests/commands/contact-properties/update.test.ts +217 -0
- package/temp_resend_cli/repo/tests/commands/contacts/add-segment.test.ts +189 -0
- package/temp_resend_cli/repo/tests/commands/contacts/create.test.ts +271 -0
- package/temp_resend_cli/repo/tests/commands/contacts/delete.test.ts +193 -0
- package/temp_resend_cli/repo/tests/commands/contacts/get.test.ts +149 -0
- package/temp_resend_cli/repo/tests/commands/contacts/list.test.ts +176 -0
- package/temp_resend_cli/repo/tests/commands/contacts/remove-segment.test.ts +167 -0
- package/temp_resend_cli/repo/tests/commands/contacts/segments.test.ts +168 -0
- package/temp_resend_cli/repo/tests/commands/contacts/topics.test.ts +164 -0
- package/temp_resend_cli/repo/tests/commands/contacts/update-topics.test.ts +248 -0
- package/temp_resend_cli/repo/tests/commands/contacts/update.test.ts +206 -0
- package/temp_resend_cli/repo/tests/commands/doctor.test.ts +164 -0
- package/temp_resend_cli/repo/tests/commands/domains/create.test.ts +193 -0
- package/temp_resend_cli/repo/tests/commands/domains/delete.test.ts +157 -0
- package/temp_resend_cli/repo/tests/commands/domains/get.test.ts +138 -0
- package/temp_resend_cli/repo/tests/commands/domains/list.test.ts +165 -0
- package/temp_resend_cli/repo/tests/commands/domains/update.test.ts +224 -0
- package/temp_resend_cli/repo/tests/commands/domains/verify.test.ts +118 -0
- package/temp_resend_cli/repo/tests/commands/emails/batch.test.ts +324 -0
- package/temp_resend_cli/repo/tests/commands/emails/get.test.ts +132 -0
- package/temp_resend_cli/repo/tests/commands/emails/receiving/attachment.test.ts +141 -0
- package/temp_resend_cli/repo/tests/commands/emails/receiving/attachments.test.ts +169 -0
- package/temp_resend_cli/repo/tests/commands/emails/receiving/get.test.ts +141 -0
- package/temp_resend_cli/repo/tests/commands/emails/receiving/list.test.ts +182 -0
- package/temp_resend_cli/repo/tests/commands/emails/send.test.ts +312 -0
- package/temp_resend_cli/repo/tests/commands/segments/create.test.ts +164 -0
- package/temp_resend_cli/repo/tests/commands/segments/delete.test.ts +183 -0
- package/temp_resend_cli/repo/tests/commands/segments/get.test.ts +138 -0
- package/temp_resend_cli/repo/tests/commands/segments/list.test.ts +174 -0
- package/temp_resend_cli/repo/tests/commands/teams/list.test.ts +62 -0
- package/temp_resend_cli/repo/tests/commands/teams/remove.test.ts +110 -0
- package/temp_resend_cli/repo/tests/commands/teams/switch.test.ts +103 -0
- package/temp_resend_cli/repo/tests/commands/topics/create.test.ts +192 -0
- package/temp_resend_cli/repo/tests/commands/topics/delete.test.ts +157 -0
- package/temp_resend_cli/repo/tests/commands/topics/get.test.ts +126 -0
- package/temp_resend_cli/repo/tests/commands/topics/list.test.ts +125 -0
- package/temp_resend_cli/repo/tests/commands/topics/update.test.ts +178 -0
- package/temp_resend_cli/repo/tests/commands/webhooks/create.test.ts +225 -0
- package/temp_resend_cli/repo/tests/commands/webhooks/delete.test.ts +157 -0
- package/temp_resend_cli/repo/tests/commands/webhooks/get.test.ts +126 -0
- package/temp_resend_cli/repo/tests/commands/webhooks/list.test.ts +178 -0
- package/temp_resend_cli/repo/tests/commands/webhooks/update.test.ts +207 -0
- package/temp_resend_cli/repo/tests/commands/whoami.test.ts +98 -0
- package/temp_resend_cli/repo/tests/e2e/smoke.test.ts +93 -0
- package/temp_resend_cli/repo/tests/helpers.ts +86 -0
- package/temp_resend_cli/repo/tests/lib/client.test.ts +71 -0
- package/temp_resend_cli/repo/tests/lib/config.test.ts +451 -0
- package/temp_resend_cli/repo/tests/lib/files.test.ts +73 -0
- package/temp_resend_cli/repo/tests/lib/help-text.test.ts +97 -0
- package/temp_resend_cli/repo/tests/lib/output.test.ts +136 -0
- package/temp_resend_cli/repo/tests/lib/prompts.test.ts +185 -0
- package/temp_resend_cli/repo/tests/lib/spinner.test.ts +166 -0
- package/temp_resend_cli/repo/tests/lib/table.test.ts +63 -0
- package/temp_resend_cli/repo/tests/lib/tty.test.ts +89 -0
- package/temp_resend_cli/repo/tests/lib/update-check.test.ts +179 -0
- package/temp_resend_cli/repo/tsconfig.json +14 -0
- package/temp_resend_cli/repo/vitest.config.e2e.ts +8 -0
- package/temp_resend_cli/repo/vitest.config.ts +10 -0
- package/tests/test-mcp-browser-use-smoke.sh +28 -56
- package/tests/test-monty-smoke.sh +32 -0
- package/tests/test-resend-smoke.sh +36 -0
|
@@ -0,0 +1,1073 @@
|
|
|
1
|
+
use std::{
|
|
2
|
+
cell::Cell,
|
|
3
|
+
collections::hash_map::DefaultHasher,
|
|
4
|
+
hash::{Hash, Hasher},
|
|
5
|
+
mem::size_of,
|
|
6
|
+
vec,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
use smallvec::SmallVec;
|
|
10
|
+
|
|
11
|
+
// Re-export items moved to `heap_traits` so that `crate::heap::HeapGuard` etc. continue
|
|
12
|
+
// to resolve (used by the `defer_drop!` macros and throughout the codebase).
|
|
13
|
+
pub(crate) use crate::heap_data::HeapData;
|
|
14
|
+
pub(crate) use crate::heap_traits::{ContainsHeap, DropWithHeap, HeapGuard, ImmutableHeapGuard};
|
|
15
|
+
use crate::{
|
|
16
|
+
args::ArgValues,
|
|
17
|
+
asyncio::GatherItem,
|
|
18
|
+
bytecode::{CallResult, VM},
|
|
19
|
+
exception_private::{ExcType, RunResult},
|
|
20
|
+
heap_data::HeapDataMut,
|
|
21
|
+
intern::Interns,
|
|
22
|
+
resource::{ResourceError, ResourceTracker, check_mult_size, check_repeat_size},
|
|
23
|
+
types::{List, LongInt, PyTrait, Tuple, allocate_tuple},
|
|
24
|
+
value::{EitherStr, Value},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/// Unique identifier for values stored inside the heap arena.
|
|
28
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
|
|
29
|
+
pub struct HeapId(usize);
|
|
30
|
+
|
|
31
|
+
impl HeapId {
|
|
32
|
+
/// Returns the raw index value.
|
|
33
|
+
#[inline]
|
|
34
|
+
pub fn index(self) -> usize {
|
|
35
|
+
self.0
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// The empty tuple is a singleton which is allocated at startup.
|
|
40
|
+
const EMPTY_TUPLE_ID: HeapId = HeapId(0);
|
|
41
|
+
|
|
42
|
+
/// Hash caching state stored alongside each heap entry.
|
|
43
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
|
44
|
+
enum HashState {
|
|
45
|
+
/// Hash has not yet been computed but the value might be hashable.
|
|
46
|
+
Unknown,
|
|
47
|
+
/// Cached hash value for immutable types that have been hashed at least once.
|
|
48
|
+
Cached(u64),
|
|
49
|
+
/// Value is unhashable (mutable types or tuples containing unhashables).
|
|
50
|
+
Unhashable,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
impl HashState {
|
|
54
|
+
fn for_data(data: &HeapData) -> Self {
|
|
55
|
+
match data {
|
|
56
|
+
// Cells are hashable by identity (like all Python objects without __hash__ override)
|
|
57
|
+
// FrozenSet is immutable and hashable
|
|
58
|
+
// Range is immutable and hashable
|
|
59
|
+
// Slice is immutable and hashable (like in CPython)
|
|
60
|
+
// LongInt is immutable and hashable
|
|
61
|
+
// NamedTuple is immutable and hashable (like Tuple)
|
|
62
|
+
HeapData::Str(_)
|
|
63
|
+
| HeapData::Bytes(_)
|
|
64
|
+
| HeapData::Tuple(_)
|
|
65
|
+
| HeapData::NamedTuple(_)
|
|
66
|
+
| HeapData::FrozenSet(_)
|
|
67
|
+
| HeapData::Cell(_)
|
|
68
|
+
| HeapData::Closure(_)
|
|
69
|
+
| HeapData::FunctionDefaults(_)
|
|
70
|
+
| HeapData::Range(_)
|
|
71
|
+
| HeapData::Slice(_)
|
|
72
|
+
| HeapData::LongInt(_) => Self::Unknown,
|
|
73
|
+
// Dataclass hashability depends on the mutable flag
|
|
74
|
+
HeapData::Dataclass(dc) => {
|
|
75
|
+
if dc.is_frozen() {
|
|
76
|
+
Self::Unknown
|
|
77
|
+
} else {
|
|
78
|
+
Self::Unhashable
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Path is immutable and hashable
|
|
82
|
+
HeapData::Path(_) => Self::Unknown,
|
|
83
|
+
// ExtFunction is hashable (by identity, like closures)
|
|
84
|
+
HeapData::ExtFunction(_) => Self::Unknown,
|
|
85
|
+
// other types are unhashable
|
|
86
|
+
_ => Self::Unhashable,
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/// A single entry inside the heap arena, storing refcount, payload, and hash metadata.
|
|
92
|
+
///
|
|
93
|
+
/// The `hash_state` field tracks whether the heap entry is hashable and, if so,
|
|
94
|
+
/// caches the computed hash. Mutable types (List, Dict) start as `Unhashable` and
|
|
95
|
+
/// will raise TypeError if used as dict keys.
|
|
96
|
+
///
|
|
97
|
+
/// The `data` field is an Option to support temporary borrowing: when methods like
|
|
98
|
+
/// `with_entry_mut` or `call_attr` need mutable access to both the data and the heap,
|
|
99
|
+
/// they can `.take()` the data out (leaving `None`), pass `&mut Heap` to user code,
|
|
100
|
+
/// then restore the data. This avoids unsafe code while keeping `refcount` accessible
|
|
101
|
+
/// for `inc_ref`/`dec_ref` during the borrow.
|
|
102
|
+
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
|
103
|
+
pub struct HeapValue {
|
|
104
|
+
refcount: Cell<usize>,
|
|
105
|
+
/// The payload data. Temporarily `None` while borrowed via `with_entry_mut`/`call_attr`.
|
|
106
|
+
data: Option<HeapData>,
|
|
107
|
+
/// Current hashing status / cached hash value
|
|
108
|
+
hash_state: HashState,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/// Zero-size token returned by [`Heap::incr_recursion_depth`].
|
|
112
|
+
///
|
|
113
|
+
/// Represents one level of recursion depth that must be released when the
|
|
114
|
+
/// recursive operation completes. There are two ways to release the token:
|
|
115
|
+
///
|
|
116
|
+
/// - **`DropWithHeap`** — for `&mut Heap` paths (e.g., `py_eq`). Compatible with
|
|
117
|
+
/// `defer_drop!` and `HeapGuard` for automatic cleanup on all code paths.
|
|
118
|
+
/// - **`DropWithImmutableHeap`** — for `&Heap` paths (e.g., `py_repr_fmt`) where
|
|
119
|
+
/// only shared access is available. Compatible with `defer_drop_immutable_heap!`
|
|
120
|
+
/// and `ImmutableHeapGuard`.
|
|
121
|
+
#[derive(Debug)]
|
|
122
|
+
pub(crate) struct RecursionToken(());
|
|
123
|
+
|
|
124
|
+
impl DropWithHeap for RecursionToken {
|
|
125
|
+
#[inline]
|
|
126
|
+
fn drop_with_heap<H: ContainsHeap>(self, heap: &mut H) {
|
|
127
|
+
heap.heap().decr_recursion_depth();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/// Reference-counted arena that backs all heap-only runtime values.
|
|
132
|
+
///
|
|
133
|
+
/// Uses a free list to reuse slots from freed values, keeping memory usage
|
|
134
|
+
/// constant for long-running loops that repeatedly allocate and free values.
|
|
135
|
+
/// When an value is freed via `dec_ref`, its slot ID is added to the free list.
|
|
136
|
+
/// New allocations pop from the free list when available, otherwise append.
|
|
137
|
+
///
|
|
138
|
+
/// Generic over `T: ResourceTracker` to support different resource tracking strategies.
|
|
139
|
+
/// When `T = NoLimitTracker` (the default), all resource checks compile away to no-ops.
|
|
140
|
+
///
|
|
141
|
+
/// Serialization requires `T: Serialize` and `T: Deserialize`. Custom serde implementation
|
|
142
|
+
/// handles the Drop constraint by using `std::mem::take` during serialization.
|
|
143
|
+
#[derive(Debug)]
|
|
144
|
+
pub(crate) struct Heap<T: ResourceTracker> {
|
|
145
|
+
entries: Vec<Option<HeapValue>>,
|
|
146
|
+
/// IDs of freed slots available for reuse. Populated by `dec_ref`, consumed by `allocate`.
|
|
147
|
+
free_list: Vec<HeapId>,
|
|
148
|
+
/// Resource tracker for enforcing limits and scheduling GC.
|
|
149
|
+
tracker: T,
|
|
150
|
+
/// True if reference cycles may exist. Set when a container stores a Ref,
|
|
151
|
+
/// cleared after GC completes. When false, GC can skip mark-sweep entirely.
|
|
152
|
+
may_have_cycles: bool,
|
|
153
|
+
/// Number of GC applicable allocations since the last GC.
|
|
154
|
+
allocations_since_gc: u32,
|
|
155
|
+
/// Current recursion depth — incremented on function calls and data structure traversals.
|
|
156
|
+
///
|
|
157
|
+
/// Uses `Cell` for interior mutability so that methods with only `&Heap`
|
|
158
|
+
/// (like `py_repr_fmt`) can still increment/decrement the depth counter.
|
|
159
|
+
recursion_depth: Cell<usize>,
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
impl<T: ResourceTracker + serde::Serialize> serde::Serialize for Heap<T> {
|
|
163
|
+
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
164
|
+
use serde::ser::SerializeStruct;
|
|
165
|
+
let mut state = serializer.serialize_struct("Heap", 6)?;
|
|
166
|
+
state.serialize_field("entries", &self.entries)?;
|
|
167
|
+
state.serialize_field("free_list", &self.free_list)?;
|
|
168
|
+
state.serialize_field("tracker", &self.tracker)?;
|
|
169
|
+
state.serialize_field("may_have_cycles", &self.may_have_cycles)?;
|
|
170
|
+
state.serialize_field("allocations_since_gc", &self.allocations_since_gc)?;
|
|
171
|
+
state.end()
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
impl<'de, T: ResourceTracker + serde::Deserialize<'de>> serde::Deserialize<'de> for Heap<T> {
|
|
176
|
+
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
|
177
|
+
#[derive(serde::Deserialize)]
|
|
178
|
+
struct HeapFields<T> {
|
|
179
|
+
entries: Vec<Option<HeapValue>>,
|
|
180
|
+
free_list: Vec<HeapId>,
|
|
181
|
+
tracker: T,
|
|
182
|
+
may_have_cycles: bool,
|
|
183
|
+
allocations_since_gc: u32,
|
|
184
|
+
}
|
|
185
|
+
let fields = HeapFields::<T>::deserialize(deserializer)?;
|
|
186
|
+
Ok(Self {
|
|
187
|
+
entries: fields.entries,
|
|
188
|
+
free_list: fields.free_list,
|
|
189
|
+
tracker: fields.tracker,
|
|
190
|
+
may_have_cycles: fields.may_have_cycles,
|
|
191
|
+
allocations_since_gc: fields.allocations_since_gc,
|
|
192
|
+
recursion_depth: Cell::new(0),
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
macro_rules! take_data {
|
|
198
|
+
($self:ident, $id:expr, $func_name:literal) => {
|
|
199
|
+
$self
|
|
200
|
+
.entries
|
|
201
|
+
.get_mut($id.index())
|
|
202
|
+
.expect(concat!("Heap::", $func_name, ": slot missing"))
|
|
203
|
+
.as_mut()
|
|
204
|
+
.expect(concat!("Heap::", $func_name, ": object already freed"))
|
|
205
|
+
.data
|
|
206
|
+
.take()
|
|
207
|
+
.expect(concat!("Heap::", $func_name, ": data already borrowed"))
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
macro_rules! restore_data {
|
|
212
|
+
($self:ident, $id:expr, $new_data:expr, $func_name:literal) => {{
|
|
213
|
+
let entry = $self
|
|
214
|
+
.entries
|
|
215
|
+
.get_mut($id.index())
|
|
216
|
+
.expect(concat!("Heap::", $func_name, ": slot missing"))
|
|
217
|
+
.as_mut()
|
|
218
|
+
.expect(concat!("Heap::", $func_name, ": object already freed"));
|
|
219
|
+
entry.data = Some($new_data);
|
|
220
|
+
}};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/// GC interval - run GC every 100,000 applicable allocations.
|
|
224
|
+
///
|
|
225
|
+
/// This is intentionally infrequent to minimize overhead while still
|
|
226
|
+
/// eventually collecting reference cycles.
|
|
227
|
+
const GC_INTERVAL: u32 = 100_000;
|
|
228
|
+
|
|
229
|
+
impl<T: ResourceTracker> Heap<T> {
|
|
230
|
+
/// Creates a new heap with the given resource tracker.
|
|
231
|
+
///
|
|
232
|
+
/// Use this to create heaps with custom resource limits or GC scheduling.
|
|
233
|
+
pub fn new(capacity: usize, tracker: T) -> Self {
|
|
234
|
+
let mut this = Self {
|
|
235
|
+
entries: Vec::with_capacity(capacity),
|
|
236
|
+
free_list: Vec::new(),
|
|
237
|
+
tracker,
|
|
238
|
+
may_have_cycles: false,
|
|
239
|
+
allocations_since_gc: 0,
|
|
240
|
+
recursion_depth: Cell::new(0),
|
|
241
|
+
};
|
|
242
|
+
// TBC: should the empty tuple contribute to the resource limits?
|
|
243
|
+
// If not, can just place it in `entries` directly without going through `allocate()`.
|
|
244
|
+
let empty_tuple = this
|
|
245
|
+
.allocate(HeapData::Tuple(Tuple::default()))
|
|
246
|
+
.expect("Failed to allocate empty tuple singleton");
|
|
247
|
+
debug_assert_eq!(empty_tuple, EMPTY_TUPLE_ID);
|
|
248
|
+
this
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/// Returns a reference to the resource tracker.
|
|
252
|
+
pub fn tracker(&self) -> &T {
|
|
253
|
+
&self.tracker
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/// Returns a mutable reference to the resource tracker.
|
|
257
|
+
pub fn tracker_mut(&mut self) -> &mut T {
|
|
258
|
+
&mut self.tracker
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/// Checks whether the configured time limit has been exceeded.
|
|
262
|
+
///
|
|
263
|
+
/// Delegates to the resource tracker's `check_time()`. For `NoLimitTracker`,
|
|
264
|
+
/// this is inlined as a no-op with zero runtime cost. For `LimitTracker`,
|
|
265
|
+
/// it compares elapsed time against the configured `max_duration_secs`.
|
|
266
|
+
///
|
|
267
|
+
/// Call this inside Rust-side loops (builtins, sort, iterator collection)
|
|
268
|
+
/// that execute within a single bytecode instruction and would otherwise
|
|
269
|
+
/// bypass the VM's per-instruction timeout check.
|
|
270
|
+
#[inline]
|
|
271
|
+
pub fn check_time(&self) -> Result<(), ResourceError> {
|
|
272
|
+
self.tracker.check_time()
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/// Increments the recursion depth and checks the limit via the `ResourceTracker`.
|
|
276
|
+
///
|
|
277
|
+
/// Returns `Ok(RecursionToken)` if within limits. The caller must ensure the
|
|
278
|
+
/// token is released on all code paths — either via `defer_drop!`/`HeapGuard`
|
|
279
|
+
/// (for `&mut Heap` contexts) or via `RecursionToken::release()` (for `&Heap` contexts).
|
|
280
|
+
///
|
|
281
|
+
/// Returns `Err(ResourceError::Recursion)` if the limit would be exceeded.
|
|
282
|
+
#[inline]
|
|
283
|
+
pub fn incr_recursion_depth(&self) -> Result<RecursionToken, ResourceError> {
|
|
284
|
+
let depth = self.recursion_depth.get();
|
|
285
|
+
self.tracker.check_recursion_depth(depth)?;
|
|
286
|
+
self.recursion_depth.set(depth + 1);
|
|
287
|
+
Ok(RecursionToken(()))
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/// Increments the recursion depth, returning `Some(RecursionToken)` if within
|
|
291
|
+
/// limits, or `None` if the limit is exceeded.
|
|
292
|
+
///
|
|
293
|
+
/// Use this in repr-like contexts where exceeding the limit should produce
|
|
294
|
+
/// truncated output (e.g., `[...]`) rather than an error.
|
|
295
|
+
#[inline]
|
|
296
|
+
pub fn incr_recursion_depth_for_repr(&self) -> Option<RecursionToken> {
|
|
297
|
+
self.incr_recursion_depth().ok()
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/// Decrements the recursion depth.
|
|
301
|
+
///
|
|
302
|
+
/// Called internally by `RecursionToken` — prefer releasing the token
|
|
303
|
+
/// rather than calling this directly.
|
|
304
|
+
#[inline]
|
|
305
|
+
pub(crate) fn decr_recursion_depth(&self) {
|
|
306
|
+
let depth = self.recursion_depth.get();
|
|
307
|
+
debug_assert!(depth > 0, "decr_recursion_depth called when depth is 0");
|
|
308
|
+
self.recursion_depth.set(depth - 1);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/// Returns the current recursion depth.
|
|
312
|
+
///
|
|
313
|
+
/// Used during async task switching to compute a task's depth contribution
|
|
314
|
+
/// before adjusting the global counter.
|
|
315
|
+
pub(crate) fn get_recursion_depth(&self) -> usize {
|
|
316
|
+
self.recursion_depth.get()
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/// Sets the recursion depth to an explicit value.
|
|
320
|
+
///
|
|
321
|
+
/// Used after deserialization to restore the recursion depth to match
|
|
322
|
+
/// the number of active (non-global) namespace frames that were serialized.
|
|
323
|
+
/// Also used during async task switching to subtract/add a task's depth
|
|
324
|
+
/// contribution when switching away from/to that task.
|
|
325
|
+
pub(crate) fn set_recursion_depth(&self, depth: usize) {
|
|
326
|
+
self.recursion_depth.set(depth);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/// Number of entries in the heap
|
|
330
|
+
pub fn size(&self) -> usize {
|
|
331
|
+
self.entries.len()
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/// Marks that a reference cycle may exist in the heap.
|
|
335
|
+
///
|
|
336
|
+
/// Call this when a container (list, dict, tuple, etc.) stores a reference
|
|
337
|
+
/// to another heap object. This enables the GC to skip mark-sweep entirely
|
|
338
|
+
/// when no cycles are possible.
|
|
339
|
+
#[inline]
|
|
340
|
+
pub fn mark_potential_cycle(&mut self) {
|
|
341
|
+
self.may_have_cycles = true;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/// Returns the number of GC-tracked allocations since the last garbage collection.
|
|
345
|
+
///
|
|
346
|
+
/// This counter increments for each allocation of a GC-tracked type (List, Dict, etc.)
|
|
347
|
+
/// and resets to 0 when `collect_garbage` runs. Useful for testing GC behavior.
|
|
348
|
+
#[cfg(feature = "ref-count-return")]
|
|
349
|
+
pub fn get_allocations_since_gc(&self) -> u32 {
|
|
350
|
+
self.allocations_since_gc
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/// Allocates a new heap entry.
|
|
354
|
+
///
|
|
355
|
+
/// Returns `Err(ResourceError)` if allocation would exceed configured limits.
|
|
356
|
+
/// Use this when you need to handle resource limit errors gracefully.
|
|
357
|
+
///
|
|
358
|
+
/// Only GC-tracked types (containers that can hold references) count toward the
|
|
359
|
+
/// GC allocation threshold. Leaf types like strings don't trigger GC.
|
|
360
|
+
///
|
|
361
|
+
/// When allocating a container that contains heap references, marks potential
|
|
362
|
+
/// cycles to enable garbage collection.
|
|
363
|
+
pub fn allocate(&mut self, data: HeapData) -> Result<HeapId, ResourceError> {
|
|
364
|
+
self.tracker.on_allocate(|| data.py_estimate_size())?;
|
|
365
|
+
if data.is_gc_tracked() {
|
|
366
|
+
self.allocations_since_gc = self.allocations_since_gc.wrapping_add(1);
|
|
367
|
+
// Mark potential cycles if this container has heap references.
|
|
368
|
+
// This is essential for types like Dict where setitem doesn't call
|
|
369
|
+
// mark_potential_cycle() - the allocation is the only place to detect refs.
|
|
370
|
+
if data.has_refs() {
|
|
371
|
+
self.may_have_cycles = true;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
let hash_state = HashState::for_data(&data);
|
|
376
|
+
let new_entry = HeapValue {
|
|
377
|
+
refcount: Cell::new(1),
|
|
378
|
+
data: Some(data),
|
|
379
|
+
hash_state,
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
let id = if let Some(id) = self.free_list.pop() {
|
|
383
|
+
// Reuse a freed slot
|
|
384
|
+
self.entries[id.index()] = Some(new_entry);
|
|
385
|
+
id
|
|
386
|
+
} else {
|
|
387
|
+
// No free slots, append new entry
|
|
388
|
+
let id = self.entries.len();
|
|
389
|
+
self.entries.push(Some(new_entry));
|
|
390
|
+
HeapId(id)
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
Ok(id)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/// Returns the singleton empty tuple.
|
|
397
|
+
///
|
|
398
|
+
/// In Python, `() is ()` is always `True` because empty tuples are interned.
|
|
399
|
+
/// This method provides the same optimization by returning the same `HeapId`
|
|
400
|
+
/// for all empty tuple allocations.
|
|
401
|
+
///
|
|
402
|
+
/// The returned `Value` has its reference count incremented, so the caller
|
|
403
|
+
/// owns a reference and must call `dec_ref` when done.
|
|
404
|
+
pub fn get_empty_tuple(&mut self) -> Value {
|
|
405
|
+
// Return existing singleton with incremented refcount
|
|
406
|
+
self.inc_ref(EMPTY_TUPLE_ID);
|
|
407
|
+
Value::Ref(EMPTY_TUPLE_ID)
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/// Increments the reference count for an existing heap entry.
|
|
411
|
+
///
|
|
412
|
+
/// # Panics
|
|
413
|
+
/// Panics if the value ID is invalid or the value has already been freed.
|
|
414
|
+
pub fn inc_ref(&self, id: HeapId) {
|
|
415
|
+
let value = self
|
|
416
|
+
.entries
|
|
417
|
+
.get(id.index())
|
|
418
|
+
.expect("Heap::inc_ref: slot missing")
|
|
419
|
+
.as_ref()
|
|
420
|
+
.expect("Heap::inc_ref: object already freed");
|
|
421
|
+
value.refcount.update(|r| r + 1);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/// Decrements the reference count and frees the value (plus children) once it hits zero.
|
|
425
|
+
///
|
|
426
|
+
/// Uses an iterative work stack instead of recursion to avoid Rust stack overflow
|
|
427
|
+
/// when freeing deeply nested containers (e.g., a list nested 10,000 levels deep).
|
|
428
|
+
/// This is analogous to CPython's "trashcan" mechanism for safe deallocation.
|
|
429
|
+
///
|
|
430
|
+
/// # Panics
|
|
431
|
+
/// Panics if the value ID is invalid or the value has already been freed.
|
|
432
|
+
pub fn dec_ref(&mut self, id: HeapId) {
|
|
433
|
+
let mut current_id = id;
|
|
434
|
+
let mut work_stack = Vec::new();
|
|
435
|
+
loop {
|
|
436
|
+
let slot = self
|
|
437
|
+
.entries
|
|
438
|
+
.get_mut(current_id.index())
|
|
439
|
+
.expect("Heap::dec_ref: slot missing");
|
|
440
|
+
let entry = slot.as_mut().expect("Heap::dec_ref: object already freed");
|
|
441
|
+
if entry.refcount.get() > 1 {
|
|
442
|
+
entry.refcount.update(|r| r - 1);
|
|
443
|
+
} else if let Some(value) = slot.take() {
|
|
444
|
+
// refcount == 1, free the value and add slot to free list for reuse
|
|
445
|
+
self.free_list.push(current_id);
|
|
446
|
+
|
|
447
|
+
// Notify tracker of freed memory
|
|
448
|
+
if let Some(ref data) = value.data {
|
|
449
|
+
self.tracker.on_free(|| data.py_estimate_size());
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Collect child IDs and push onto work stack for iterative processing
|
|
453
|
+
if let Some(mut data) = value.data {
|
|
454
|
+
data.py_dec_ref_ids(&mut work_stack);
|
|
455
|
+
drop(data);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
let Some(next_id) = work_stack.pop() else {
|
|
460
|
+
break;
|
|
461
|
+
};
|
|
462
|
+
current_id = next_id;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/// Returns an immutable reference to the heap data stored at the given ID.
|
|
467
|
+
///
|
|
468
|
+
/// # Panics
|
|
469
|
+
/// Panics if the value ID is invalid, the value has already been freed,
|
|
470
|
+
/// or the data is currently borrowed via `with_entry_mut`/`call_attr`.
|
|
471
|
+
#[must_use]
|
|
472
|
+
pub fn get(&self, id: HeapId) -> &HeapData {
|
|
473
|
+
self.entries
|
|
474
|
+
.get(id.index())
|
|
475
|
+
.expect("Heap::get: slot missing")
|
|
476
|
+
.as_ref()
|
|
477
|
+
.expect("Heap::get: object already freed")
|
|
478
|
+
.data
|
|
479
|
+
.as_ref()
|
|
480
|
+
.expect("Heap::get: data currently borrowed")
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/// Returns a mutable reference to the heap data stored at the given ID.
|
|
484
|
+
///
|
|
485
|
+
/// # Panics
|
|
486
|
+
/// Panics if the value ID is invalid, the value has already been freed,
|
|
487
|
+
/// or the data is currently borrowed via `with_entry_mut`/`call_attr`.
|
|
488
|
+
pub fn get_mut(&mut self, id: HeapId) -> HeapDataMut<'_> {
|
|
489
|
+
self.entries
|
|
490
|
+
.get_mut(id.index())
|
|
491
|
+
.expect("Heap::get_mut: slot missing")
|
|
492
|
+
.as_mut()
|
|
493
|
+
.expect("Heap::get_mut: object already freed")
|
|
494
|
+
.data
|
|
495
|
+
.as_mut()
|
|
496
|
+
.expect("Heap::get_mut: data currently borrowed")
|
|
497
|
+
.to_mut()
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/// Returns or computes the hash for the heap entry at the given ID.
|
|
501
|
+
///
|
|
502
|
+
/// Hashes are computed lazily on first use and then cached. Returns
|
|
503
|
+
/// `Ok(Some(hash))` for immutable types, `Ok(None)` for mutable types,
|
|
504
|
+
/// or `Err(ResourceError::Recursion)` if the recursion limit is exceeded.
|
|
505
|
+
///
|
|
506
|
+
/// # Panics
|
|
507
|
+
/// Panics if the value ID is invalid or the value has already been freed.
|
|
508
|
+
pub fn get_or_compute_hash(&mut self, id: HeapId, interns: &Interns) -> Result<Option<u64>, ResourceError> {
|
|
509
|
+
let entry = self
|
|
510
|
+
.entries
|
|
511
|
+
.get_mut(id.index())
|
|
512
|
+
.expect("Heap::get_or_compute_hash: slot missing")
|
|
513
|
+
.as_mut()
|
|
514
|
+
.expect("Heap::get_or_compute_hash: object already freed");
|
|
515
|
+
|
|
516
|
+
match entry.hash_state {
|
|
517
|
+
HashState::Unhashable => return Ok(None),
|
|
518
|
+
HashState::Cached(hash) => return Ok(Some(hash)),
|
|
519
|
+
HashState::Unknown => {}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// Handle Cell specially - uses identity-based hashing (like Python cell objects)
|
|
523
|
+
if let Some(HeapData::Cell(_)) = &entry.data {
|
|
524
|
+
let mut hasher = DefaultHasher::new();
|
|
525
|
+
id.hash(&mut hasher);
|
|
526
|
+
let hash = hasher.finish();
|
|
527
|
+
entry.hash_state = HashState::Cached(hash);
|
|
528
|
+
return Ok(Some(hash));
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Compute hash lazily - need to temporarily take data to avoid borrow conflict.
|
|
532
|
+
// IMPORTANT: data must be restored to the entry on ALL paths (including errors)
|
|
533
|
+
// to avoid dropping HeapData containing Value::Ref without proper cleanup.
|
|
534
|
+
let mut data = entry.data.take().expect("Heap::get_or_compute_hash: data borrowed");
|
|
535
|
+
let hash = data.to_mut().compute_hash_if_immutable(self, interns);
|
|
536
|
+
|
|
537
|
+
// Restore data before handling the result
|
|
538
|
+
let entry = self
|
|
539
|
+
.entries
|
|
540
|
+
.get_mut(id.index())
|
|
541
|
+
.expect("Heap::get_or_compute_hash: slot missing after compute")
|
|
542
|
+
.as_mut()
|
|
543
|
+
.expect("Heap::get_or_compute_hash: object freed during compute");
|
|
544
|
+
entry.data = Some(data);
|
|
545
|
+
|
|
546
|
+
// Now handle the result and cache if successful
|
|
547
|
+
let hash = hash?;
|
|
548
|
+
entry.hash_state = match hash {
|
|
549
|
+
Some(value) => HashState::Cached(value),
|
|
550
|
+
None => HashState::Unhashable,
|
|
551
|
+
};
|
|
552
|
+
Ok(hash)
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/// Calls an attribute on the heap entry, returning an `CallResult` that may signal
|
|
556
|
+
/// OS, external, or method calls.
|
|
557
|
+
///
|
|
558
|
+
/// Temporarily takes ownership of the payload to avoid borrow conflicts when attribute
|
|
559
|
+
/// implementations also need mutable heap access (e.g. for refcounting).
|
|
560
|
+
///
|
|
561
|
+
/// Returns `CallResult` which may be:
|
|
562
|
+
/// - `Value(v)` - Method completed synchronously with value `v`
|
|
563
|
+
/// - `OsCall(func, args)` - Method needs OS operation; VM should yield to host
|
|
564
|
+
/// - `ExternalCall(id, args)` - Method needs external function call
|
|
565
|
+
/// - `MethodCall(name, args)` - Dataclass method call; VM should yield to host
|
|
566
|
+
pub fn call_attr(vm: &mut VM<'_, '_, T>, id: HeapId, attr: &EitherStr, args: ArgValues) -> RunResult<CallResult> {
|
|
567
|
+
// Take data out so the borrow of self.entries ends
|
|
568
|
+
let heap = &mut *vm.heap;
|
|
569
|
+
let mut data = take_data!(heap, id, "call_attr");
|
|
570
|
+
|
|
571
|
+
let result = data.py_call_attr(id, vm, attr, args);
|
|
572
|
+
|
|
573
|
+
// Restore data
|
|
574
|
+
let heap = &mut *vm.heap;
|
|
575
|
+
restore_data!(heap, id, data, "call_attr");
|
|
576
|
+
result
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/// Gives mutable access to a heap entry while allowing reentrant heap usage
|
|
580
|
+
/// inside the closure (e.g. to read other values or allocate results).
|
|
581
|
+
///
|
|
582
|
+
/// The data is temporarily taken from the heap entry, so the closure can safely
|
|
583
|
+
/// mutate both the entry data and the heap (e.g. to allocate new values).
|
|
584
|
+
/// The data is automatically restored after the closure completes.
|
|
585
|
+
pub fn with_entry_mut<'a, 'p, F, R>(vm: &mut VM<'a, 'p, T>, id: HeapId, f: F) -> R
|
|
586
|
+
where
|
|
587
|
+
F: FnOnce(&mut VM<'a, 'p, T>, HeapDataMut) -> R,
|
|
588
|
+
{
|
|
589
|
+
// Take data out in a block so the borrow of self.entries ends
|
|
590
|
+
let heap = &mut *vm.heap;
|
|
591
|
+
let mut data = take_data!(heap, id, "with_entry_mut");
|
|
592
|
+
|
|
593
|
+
let result = f(vm, data.to_mut());
|
|
594
|
+
|
|
595
|
+
// Restore data
|
|
596
|
+
let heap = &mut *vm.heap;
|
|
597
|
+
restore_data!(heap, id, data, "with_entry_mut");
|
|
598
|
+
result
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/// Temporarily takes ownership of two heap entries so their data can be borrowed
|
|
602
|
+
/// simultaneously while still permitting mutable access to the VM (e.g. to
|
|
603
|
+
/// allocate results). Automatically restores both entries after the closure
|
|
604
|
+
/// finishes executing.
|
|
605
|
+
///
|
|
606
|
+
/// This is a static method that takes `&mut VM` instead of `&mut self` so that
|
|
607
|
+
/// the closure receives `&mut VM` — matching the `with_entry_mut` pattern and
|
|
608
|
+
/// allowing the closure to call methods that need `vm` (e.g. `py_eq`).
|
|
609
|
+
pub fn with_two<'a, 'p, F, R>(vm: &mut VM<'a, 'p, T>, left: HeapId, right: HeapId, f: F) -> R
|
|
610
|
+
where
|
|
611
|
+
F: FnOnce(&mut VM<'a, 'p, T>, &HeapData, &HeapData) -> R,
|
|
612
|
+
{
|
|
613
|
+
if left == right {
|
|
614
|
+
// Same value - take data once and pass it twice
|
|
615
|
+
let heap = &mut *vm.heap;
|
|
616
|
+
let data = take_data!(heap, left, "with_two");
|
|
617
|
+
|
|
618
|
+
let result = f(vm, &data, &data);
|
|
619
|
+
|
|
620
|
+
let heap = &mut *vm.heap;
|
|
621
|
+
restore_data!(heap, left, data, "with_two");
|
|
622
|
+
result
|
|
623
|
+
} else {
|
|
624
|
+
// Different values - take both
|
|
625
|
+
let heap = &mut *vm.heap;
|
|
626
|
+
let left_data = take_data!(heap, left, "with_two (left)");
|
|
627
|
+
let right_data = take_data!(heap, right, "with_two (right)");
|
|
628
|
+
|
|
629
|
+
let result = f(vm, &left_data, &right_data);
|
|
630
|
+
|
|
631
|
+
// Restore in reverse order
|
|
632
|
+
let heap = &mut *vm.heap;
|
|
633
|
+
restore_data!(heap, right, right_data, "with_two (right)");
|
|
634
|
+
restore_data!(heap, left, left_data, "with_two (left)");
|
|
635
|
+
result
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/// Returns the reference count for the heap entry at the given ID.
|
|
640
|
+
///
|
|
641
|
+
/// This is primarily used for testing reference counting behavior.
|
|
642
|
+
///
|
|
643
|
+
/// # Panics
|
|
644
|
+
/// Panics if the value ID is invalid or the value has already been freed.
|
|
645
|
+
#[must_use]
|
|
646
|
+
#[cfg(feature = "ref-count-return")]
|
|
647
|
+
pub fn get_refcount(&self, id: HeapId) -> usize {
|
|
648
|
+
self.entries
|
|
649
|
+
.get(id.index())
|
|
650
|
+
.expect("Heap::get_refcount: slot missing")
|
|
651
|
+
.as_ref()
|
|
652
|
+
.expect("Heap::get_refcount: object already freed")
|
|
653
|
+
.refcount
|
|
654
|
+
.get()
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/// Returns the number of live (non-freed) values on the heap.
|
|
658
|
+
///
|
|
659
|
+
/// This is primarily used for testing to verify that all heap entries
|
|
660
|
+
/// are accounted for in reference count tests.
|
|
661
|
+
///
|
|
662
|
+
/// Excludes the empty tuple singleton since it's an internal optimization
|
|
663
|
+
/// detail that persists even when not explicitly used by user code.
|
|
664
|
+
#[must_use]
|
|
665
|
+
#[cfg(feature = "ref-count-return")]
|
|
666
|
+
pub fn entry_count(&self) -> usize {
|
|
667
|
+
// 1.. to skip index 0 which is the empty tuple singleton
|
|
668
|
+
self.entries[1..].iter().filter(|o| o.is_some()).count()
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/// Helper for List in-place add: extends the destination vec with items from a heap list.
|
|
672
|
+
///
|
|
673
|
+
/// This method exists to work around borrow checker limitations when List::py_iadd
|
|
674
|
+
/// needs to read from one heap entry while extending another. By keeping both
|
|
675
|
+
/// the read and the refcount increments within Heap's impl block, we can use the
|
|
676
|
+
/// take/restore pattern to avoid the lifetime propagation issues.
|
|
677
|
+
///
|
|
678
|
+
/// Returns `true` if successful, `false` if the source ID is not a List.
|
|
679
|
+
pub fn iadd_extend_list(&mut self, source_id: HeapId, dest: &mut Vec<Value>) -> bool {
|
|
680
|
+
if let HeapData::List(list) = self.get(source_id) {
|
|
681
|
+
let items: Vec<Value> = list.as_slice().iter().map(|v| v.clone_with_heap(self)).collect();
|
|
682
|
+
dest.extend(items);
|
|
683
|
+
true
|
|
684
|
+
} else {
|
|
685
|
+
false
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/// Multiplies a heap-allocated value by an `i64`.
|
|
690
|
+
///
|
|
691
|
+
/// If `id` refers to a `LongInt`, performs integer multiplication with a size
|
|
692
|
+
/// pre-check. Otherwise, treats `id` as a sequence and `int_val` as the repeat
|
|
693
|
+
/// count. This avoids multiple `heap.get()` calls by looking up the data once.
|
|
694
|
+
///
|
|
695
|
+
/// Returns `Ok(None)` if the heap entry is neither a LongInt nor a sequence type.
|
|
696
|
+
pub fn mult_ref_by_i64(&mut self, id: HeapId, int_val: i64) -> RunResult<Option<Value>> {
|
|
697
|
+
if let HeapData::LongInt(li) = self.get(id) {
|
|
698
|
+
check_mult_size(li.bits(), i64_bits(int_val), &self.tracker)?;
|
|
699
|
+
let result = LongInt::new(li.inner().clone()) * LongInt::from(int_val);
|
|
700
|
+
Ok(Some(result.into_value(self)?))
|
|
701
|
+
} else {
|
|
702
|
+
let count = i64_to_repeat_count(int_val)?;
|
|
703
|
+
self.mult_sequence(id, count)
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/// Multiplies two heap-allocated values.
|
|
708
|
+
///
|
|
709
|
+
/// Returns Ok(None) for unsupported type combinations.
|
|
710
|
+
pub fn mult_heap_values(&mut self, id1: HeapId, id2: HeapId) -> RunResult<Option<Value>> {
|
|
711
|
+
let (seq_id, count) = match (self.get(id1), self.get(id2)) {
|
|
712
|
+
(HeapData::LongInt(a), HeapData::LongInt(b)) => {
|
|
713
|
+
check_mult_size(a.bits(), b.bits(), &self.tracker)?;
|
|
714
|
+
let result = LongInt::new(a.inner() * b.inner());
|
|
715
|
+
return Ok(Some(result.into_value(self)?));
|
|
716
|
+
}
|
|
717
|
+
(HeapData::LongInt(li), _) => {
|
|
718
|
+
let count = longint_to_repeat_count(li)?;
|
|
719
|
+
(id2, count)
|
|
720
|
+
}
|
|
721
|
+
(_, HeapData::LongInt(li)) => {
|
|
722
|
+
let count = longint_to_repeat_count(li)?;
|
|
723
|
+
(id1, count)
|
|
724
|
+
}
|
|
725
|
+
_ => return Ok(None),
|
|
726
|
+
};
|
|
727
|
+
|
|
728
|
+
self.mult_sequence(seq_id, count)
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/// Multiplies (repeats) a sequence by an integer count.
|
|
732
|
+
///
|
|
733
|
+
/// This method handles sequence repetition for Python's `*` operator when applied
|
|
734
|
+
/// to sequences (str, bytes, list, tuple). It creates a new heap-allocated sequence
|
|
735
|
+
/// with the elements repeated `count` times.
|
|
736
|
+
///
|
|
737
|
+
/// # Arguments
|
|
738
|
+
/// * `id` - HeapId of the sequence to repeat
|
|
739
|
+
/// * `count` - Number of times to repeat (0 returns empty sequence)
|
|
740
|
+
///
|
|
741
|
+
/// # Returns
|
|
742
|
+
/// * `Ok(Some(Value))` - The new repeated sequence
|
|
743
|
+
/// * `Ok(None)` - If the heap entry is not a sequence type
|
|
744
|
+
/// * `Err` - If allocation fails due to resource limits
|
|
745
|
+
pub fn mult_sequence(&mut self, id: HeapId, count: usize) -> RunResult<Option<Value>> {
|
|
746
|
+
match self.get(id) {
|
|
747
|
+
HeapData::Str(s) => {
|
|
748
|
+
check_repeat_size(s.len(), count, &self.tracker)?;
|
|
749
|
+
Ok(Some(Value::Ref(
|
|
750
|
+
self.allocate(HeapData::Str(s.as_str().repeat(count).into()))?,
|
|
751
|
+
)))
|
|
752
|
+
}
|
|
753
|
+
HeapData::Bytes(b) => {
|
|
754
|
+
check_repeat_size(b.len(), count, &self.tracker)?;
|
|
755
|
+
Ok(Some(Value::Ref(
|
|
756
|
+
self.allocate(HeapData::Bytes(b.as_slice().repeat(count).into()))?,
|
|
757
|
+
)))
|
|
758
|
+
}
|
|
759
|
+
HeapData::List(list) => {
|
|
760
|
+
check_repeat_size(list.len().saturating_mul(size_of::<Value>()), count, &self.tracker)?;
|
|
761
|
+
let mut result = Vec::with_capacity(list.as_slice().len() * count);
|
|
762
|
+
for _ in 0..count {
|
|
763
|
+
result.extend(list.as_slice().iter().map(|v| v.clone_with_heap(self)));
|
|
764
|
+
self.check_time()?;
|
|
765
|
+
}
|
|
766
|
+
Ok(Some(Value::Ref(self.allocate(HeapData::List(List::new(result)))?)))
|
|
767
|
+
}
|
|
768
|
+
HeapData::Tuple(tuple) => {
|
|
769
|
+
if count == 0 {
|
|
770
|
+
return Ok(Some(self.get_empty_tuple()));
|
|
771
|
+
}
|
|
772
|
+
check_repeat_size(
|
|
773
|
+
tuple.as_slice().len().saturating_mul(size_of::<Value>()),
|
|
774
|
+
count,
|
|
775
|
+
&self.tracker,
|
|
776
|
+
)?;
|
|
777
|
+
let mut result = SmallVec::with_capacity(tuple.as_slice().len() * count);
|
|
778
|
+
for _ in 0..count {
|
|
779
|
+
result.extend(tuple.as_slice().iter().map(|v| v.clone_with_heap(self)));
|
|
780
|
+
self.check_time()?;
|
|
781
|
+
}
|
|
782
|
+
Ok(Some(allocate_tuple(result, self)?))
|
|
783
|
+
}
|
|
784
|
+
_ => Ok(None),
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/// Returns whether garbage collection should run.
|
|
789
|
+
///
|
|
790
|
+
/// True if reference cycles count exist in the heap
|
|
791
|
+
/// and the number of allocations since the last GC exceeds the interval.
|
|
792
|
+
#[inline]
|
|
793
|
+
pub fn should_gc(&self) -> bool {
|
|
794
|
+
self.may_have_cycles && self.allocations_since_gc >= GC_INTERVAL
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/// Runs mark-sweep garbage collection to free unreachable cycles.
|
|
798
|
+
///
|
|
799
|
+
/// This method takes a closure that provides an iterator of root HeapIds
|
|
800
|
+
/// (typically from the VM's globals and stack). It marks all reachable objects starting
|
|
801
|
+
/// from roots, then sweeps (frees) any unreachable objects.
|
|
802
|
+
///
|
|
803
|
+
/// This is necessary because reference counting alone cannot free cycles
|
|
804
|
+
/// where objects reference each other but are unreachable from the program.
|
|
805
|
+
///
|
|
806
|
+
/// # Caller Responsibility
|
|
807
|
+
/// The caller should check `should_gc()` before calling this method.
|
|
808
|
+
/// If no cycles are possible, the caller can skip GC entirely.
|
|
809
|
+
///
|
|
810
|
+
/// # Arguments
|
|
811
|
+
/// * `root` - HeapIds that are roots
|
|
812
|
+
pub fn collect_garbage(&mut self, root: Vec<HeapId>) {
|
|
813
|
+
// Mark phase: collect all reachable IDs using BFS
|
|
814
|
+
// Use Vec<bool> instead of HashSet for O(1) operations without hashing overhead
|
|
815
|
+
let mut reachable: Vec<bool> = vec![false; self.entries.len()];
|
|
816
|
+
let mut work_list: Vec<HeapId> = root;
|
|
817
|
+
|
|
818
|
+
while let Some(id) = work_list.pop() {
|
|
819
|
+
let idx = id.index();
|
|
820
|
+
// Skip if out of bounds or already visited
|
|
821
|
+
if idx >= reachable.len() || reachable[idx] {
|
|
822
|
+
continue;
|
|
823
|
+
}
|
|
824
|
+
reachable[idx] = true;
|
|
825
|
+
|
|
826
|
+
// Add children to work list
|
|
827
|
+
if let Some(Some(entry)) = self.entries.get(idx)
|
|
828
|
+
&& let Some(ref data) = entry.data
|
|
829
|
+
{
|
|
830
|
+
collect_child_ids(data, &mut work_list);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// Sweep phase: free unreachable values
|
|
835
|
+
for (id, value) in self.entries.iter_mut().enumerate() {
|
|
836
|
+
if reachable[id] {
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// This entry is unreachable - free it
|
|
841
|
+
if let Some(value) = value.take() {
|
|
842
|
+
// Notify tracker of freed memory
|
|
843
|
+
if let Some(ref data) = value.data {
|
|
844
|
+
self.tracker.on_free(|| data.py_estimate_size());
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
self.free_list.push(HeapId(id));
|
|
848
|
+
|
|
849
|
+
// Mark Values as Dereferenced when ref-count-panic is enabled
|
|
850
|
+
#[cfg(feature = "ref-count-panic")]
|
|
851
|
+
if let Some(mut data) = value.data {
|
|
852
|
+
data.py_dec_ref_ids(&mut Vec::new());
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// Reset cycle flag after GC - cycles have been collected
|
|
858
|
+
self.may_have_cycles = false;
|
|
859
|
+
self.allocations_since_gc = 0;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/// Computes the number of significant bits in an `i64`.
|
|
864
|
+
///
|
|
865
|
+
/// Returns 0 for zero, otherwise returns the position of the highest set bit
|
|
866
|
+
/// plus one. Uses unsigned absolute value to handle negative numbers correctly.
|
|
867
|
+
fn i64_bits(value: i64) -> u64 {
|
|
868
|
+
if value == 0 {
|
|
869
|
+
0
|
|
870
|
+
} else {
|
|
871
|
+
u64::from(64 - value.unsigned_abs().leading_zeros())
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/// Converts an `i64` repeat count to `usize` for sequence repetition.
|
|
876
|
+
///
|
|
877
|
+
/// Returns 0 for negative values (Python treats negative repeat counts as 0).
|
|
878
|
+
/// Returns `OverflowError` if the value exceeds `usize::MAX`.
|
|
879
|
+
fn i64_to_repeat_count(n: i64) -> RunResult<usize> {
|
|
880
|
+
if n <= 0 {
|
|
881
|
+
Ok(0)
|
|
882
|
+
} else {
|
|
883
|
+
usize::try_from(n).map_err(|_| ExcType::overflow_repeat_count().into())
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/// Converts a `LongInt` repeat count to `usize` for sequence repetition.
|
|
888
|
+
///
|
|
889
|
+
/// Returns 0 for negative values (Python treats negative repeat counts as 0).
|
|
890
|
+
/// Returns `OverflowError` if the value exceeds `usize::MAX`.
|
|
891
|
+
fn longint_to_repeat_count(li: &LongInt) -> RunResult<usize> {
|
|
892
|
+
if li.is_negative() {
|
|
893
|
+
Ok(0)
|
|
894
|
+
} else if let Some(count) = li.to_usize() {
|
|
895
|
+
Ok(count)
|
|
896
|
+
} else {
|
|
897
|
+
Err(ExcType::overflow_repeat_count().into())
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
/// Collects child HeapIds from a HeapData value for GC traversal.
|
|
902
|
+
fn collect_child_ids(data: &HeapData, work_list: &mut Vec<HeapId>) {
|
|
903
|
+
match data {
|
|
904
|
+
HeapData::List(list) => {
|
|
905
|
+
// Skip iteration if no refs - major GC optimization for lists of primitives
|
|
906
|
+
if !list.contains_refs() {
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
for value in list.as_slice() {
|
|
910
|
+
if let Value::Ref(id) = value {
|
|
911
|
+
work_list.push(*id);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
HeapData::Tuple(tuple) => {
|
|
916
|
+
// Skip iteration if no refs - GC optimization for tuples of primitives
|
|
917
|
+
if !tuple.contains_refs() {
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
for value in tuple.as_slice() {
|
|
921
|
+
if let Value::Ref(id) = value {
|
|
922
|
+
work_list.push(*id);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
HeapData::NamedTuple(nt) => {
|
|
927
|
+
// Skip iteration if no refs - GC optimization for namedtuples of primitives
|
|
928
|
+
if !nt.contains_refs() {
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
for value in nt.as_vec() {
|
|
932
|
+
if let Value::Ref(id) = value {
|
|
933
|
+
work_list.push(*id);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
HeapData::Dict(dict) => {
|
|
938
|
+
// Skip iteration if no refs - major GC optimization for dicts of primitives
|
|
939
|
+
if !dict.has_refs() {
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
for (k, v) in dict {
|
|
943
|
+
if let Value::Ref(id) = k {
|
|
944
|
+
work_list.push(*id);
|
|
945
|
+
}
|
|
946
|
+
if let Value::Ref(id) = v {
|
|
947
|
+
work_list.push(*id);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
HeapData::DictKeysView(view) => {
|
|
952
|
+
work_list.push(view.dict_id());
|
|
953
|
+
}
|
|
954
|
+
HeapData::DictItemsView(view) => {
|
|
955
|
+
work_list.push(view.dict_id());
|
|
956
|
+
}
|
|
957
|
+
HeapData::DictValuesView(view) => {
|
|
958
|
+
work_list.push(view.dict_id());
|
|
959
|
+
}
|
|
960
|
+
HeapData::Set(set) => {
|
|
961
|
+
for value in set.storage().iter() {
|
|
962
|
+
if let Value::Ref(id) = value {
|
|
963
|
+
work_list.push(*id);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
HeapData::FrozenSet(frozenset) => {
|
|
968
|
+
for value in frozenset.storage().iter() {
|
|
969
|
+
if let Value::Ref(id) = value {
|
|
970
|
+
work_list.push(*id);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
HeapData::Closure(closure) => {
|
|
975
|
+
// Add captured cells to work list
|
|
976
|
+
for cell_id in &closure.cells {
|
|
977
|
+
work_list.push(*cell_id);
|
|
978
|
+
}
|
|
979
|
+
// Add default values that are heap references
|
|
980
|
+
for default in &closure.defaults {
|
|
981
|
+
if let Value::Ref(id) = default {
|
|
982
|
+
work_list.push(*id);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
HeapData::FunctionDefaults(fd) => {
|
|
987
|
+
// Add default values that are heap references
|
|
988
|
+
for default in &fd.defaults {
|
|
989
|
+
if let Value::Ref(id) = default {
|
|
990
|
+
work_list.push(*id);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
HeapData::Cell(cell) => {
|
|
995
|
+
// Cell can contain a reference to another heap value
|
|
996
|
+
if let Value::Ref(id) = &cell.0 {
|
|
997
|
+
work_list.push(*id);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
HeapData::Dataclass(dc) => {
|
|
1001
|
+
// Dataclass attrs are stored in a Dict - iterate through entries
|
|
1002
|
+
for (k, v) in dc.attrs() {
|
|
1003
|
+
if let Value::Ref(id) = k {
|
|
1004
|
+
work_list.push(*id);
|
|
1005
|
+
}
|
|
1006
|
+
if let Value::Ref(id) = v {
|
|
1007
|
+
work_list.push(*id);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
HeapData::Iter(iter) => {
|
|
1012
|
+
// Iterator holds a reference to the iterable being iterated
|
|
1013
|
+
if let Value::Ref(id) = iter.value() {
|
|
1014
|
+
work_list.push(*id);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
HeapData::Module(m) => {
|
|
1018
|
+
// Module attrs can contain references to heap values
|
|
1019
|
+
if !m.has_refs() {
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
for (k, v) in m.attrs() {
|
|
1023
|
+
if let Value::Ref(id) = k {
|
|
1024
|
+
work_list.push(*id);
|
|
1025
|
+
}
|
|
1026
|
+
if let Value::Ref(id) = v {
|
|
1027
|
+
work_list.push(*id);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
HeapData::Coroutine(coro) => {
|
|
1032
|
+
// Add namespace values that are heap references
|
|
1033
|
+
for value in &coro.namespace {
|
|
1034
|
+
if let Value::Ref(id) = value {
|
|
1035
|
+
work_list.push(*id);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
HeapData::GatherFuture(gather) => {
|
|
1040
|
+
// Add coroutine HeapIds to work list
|
|
1041
|
+
for item in &gather.items {
|
|
1042
|
+
if let GatherItem::Coroutine(coro_id) = item {
|
|
1043
|
+
work_list.push(*coro_id);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
// Add result values that are heap references
|
|
1047
|
+
for result in gather.results.iter().flatten() {
|
|
1048
|
+
if let Value::Ref(id) = result {
|
|
1049
|
+
work_list.push(*id);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
// Leaf types with no heap references
|
|
1054
|
+
_ => {}
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/// Drop implementation for Heap that marks all contained Objects as Dereferenced
|
|
1059
|
+
/// before dropping to prevent panics when the `ref-count-panic` feature is enabled.
|
|
1060
|
+
#[cfg(feature = "ref-count-panic")]
|
|
1061
|
+
impl<T: ResourceTracker> Drop for Heap<T> {
|
|
1062
|
+
fn drop(&mut self) {
|
|
1063
|
+
// Mark all contained Objects as Dereferenced before dropping.
|
|
1064
|
+
// We use py_dec_ref_ids for this since it handles the marking
|
|
1065
|
+
// (we ignore the collected IDs since we're dropping everything anyway).
|
|
1066
|
+
let mut dummy_stack = Vec::new();
|
|
1067
|
+
for value in self.entries.iter_mut().flatten() {
|
|
1068
|
+
if let Some(data) = &mut value.data {
|
|
1069
|
+
data.py_dec_ref_ids(&mut dummy_stack);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|