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,933 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from pathlib import PurePosixPath
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Callable, Literal, NamedTuple, Protocol, Sequence, TypeAlias, TypeGuard
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
# Self is 3.11+, hence this
|
|
9
|
+
from typing import Self
|
|
10
|
+
|
|
11
|
+
__all__ = 'OsFunction', 'AbstractOS', 'AbstractFile', 'MemoryFile', 'CallbackFile', 'OSAccess', 'StatResult'
|
|
12
|
+
|
|
13
|
+
OsFunction = Literal[
|
|
14
|
+
'Path.exists',
|
|
15
|
+
'Path.is_file',
|
|
16
|
+
'Path.is_dir',
|
|
17
|
+
'Path.is_symlink',
|
|
18
|
+
'Path.read_text',
|
|
19
|
+
'Path.read_bytes',
|
|
20
|
+
'Path.write_text',
|
|
21
|
+
'Path.write_bytes',
|
|
22
|
+
'Path.mkdir',
|
|
23
|
+
'Path.unlink',
|
|
24
|
+
'Path.rmdir',
|
|
25
|
+
'Path.iterdir',
|
|
26
|
+
'Path.stat',
|
|
27
|
+
'Path.rename',
|
|
28
|
+
'Path.resolve',
|
|
29
|
+
'Path.absolute',
|
|
30
|
+
'os.getenv',
|
|
31
|
+
'os.environ',
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class StatResult(NamedTuple):
|
|
36
|
+
"""Equivalent to os.stat_result."""
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def file_stat(cls, size: int, mode: int = 0o644, mtime: float | None = None) -> Self:
|
|
40
|
+
"""Creates a stat_result namedtuple for a regular file.
|
|
41
|
+
|
|
42
|
+
Use this when responding to Path.stat() OS calls.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
size: File size in bytes
|
|
46
|
+
mode: File permissions as octal (e.g., 0o644) or full mode with file type
|
|
47
|
+
mtime: Modification time as Unix timestamp, defaults to Now.
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
import time
|
|
51
|
+
|
|
52
|
+
# If only permission bits provided (no file type), add regular file type
|
|
53
|
+
if mode < 0o1000:
|
|
54
|
+
mode = mode | 0o100_000
|
|
55
|
+
mtime = time.time() if mtime is None else mtime
|
|
56
|
+
return cls(mode, 0, 0, 1, 0, 0, size, mtime, mtime, mtime)
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def dir_stat(cls, mode: int = 0o755, mtime: float | None = None) -> Self:
|
|
60
|
+
"""Creates a stat_result namedtuple for a directory.
|
|
61
|
+
|
|
62
|
+
Use this when responding to Path.stat() OS calls on directories.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
mode: Directory permissions as octal (e.g., 0o755) or full mode with file type
|
|
66
|
+
mtime: Modification time as Unix timestamp, defaults to Now.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
A namedtuple with stat_result fields
|
|
70
|
+
"""
|
|
71
|
+
import time
|
|
72
|
+
|
|
73
|
+
# If only permission bits provided (no file type), add directory type
|
|
74
|
+
if mode < 0o1000:
|
|
75
|
+
mode = mode | 0o040_000
|
|
76
|
+
|
|
77
|
+
mtime = time.time() if mtime is None else mtime
|
|
78
|
+
return cls(mode, 0, 0, 2, 0, 0, 4096, mtime, mtime, mtime)
|
|
79
|
+
|
|
80
|
+
st_mode: int
|
|
81
|
+
"""protection bits"""
|
|
82
|
+
|
|
83
|
+
st_ino: int
|
|
84
|
+
"""inode"""
|
|
85
|
+
|
|
86
|
+
st_dev: int
|
|
87
|
+
"""device"""
|
|
88
|
+
|
|
89
|
+
st_nlink: int
|
|
90
|
+
"""number of hard links"""
|
|
91
|
+
|
|
92
|
+
st_uid: int
|
|
93
|
+
"""user ID of owner"""
|
|
94
|
+
|
|
95
|
+
st_gid: int
|
|
96
|
+
"""group ID of owner"""
|
|
97
|
+
|
|
98
|
+
st_size: int
|
|
99
|
+
"""total size, in bytes"""
|
|
100
|
+
|
|
101
|
+
st_atime: float
|
|
102
|
+
"""time of last access"""
|
|
103
|
+
|
|
104
|
+
st_mtime: float
|
|
105
|
+
"""time of last modification"""
|
|
106
|
+
|
|
107
|
+
st_ctime: float
|
|
108
|
+
"""time of last change"""
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class AbstractOS(ABC):
|
|
112
|
+
"""Abstract base class for implementing virtual filesystems and OS access.
|
|
113
|
+
|
|
114
|
+
Subclass this and implement the abstract methods to provide a custom
|
|
115
|
+
filesystem that Monty code can interact with via Path methods.
|
|
116
|
+
|
|
117
|
+
Pass an instance as the `os` parameter to `Monty.run()`.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
def __call__(self, function_name: OsFunction, args: tuple[Any, ...], kwargs: dict[str, Any] | None = None) -> Any:
|
|
121
|
+
"""Dispatch a filesystem operation to the appropriate method.
|
|
122
|
+
|
|
123
|
+
This is called by Monty when Monty code invokes Path methods.
|
|
124
|
+
You typically don't need to override this method.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
function_name: The Path method being called (e.g., 'Path.exists').
|
|
128
|
+
args: The arguments passed to the method.
|
|
129
|
+
kwargs: The keyword arguments passed to the method.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
The result of the filesystem operation.
|
|
133
|
+
"""
|
|
134
|
+
kwargs = kwargs or {}
|
|
135
|
+
match function_name:
|
|
136
|
+
case 'Path.exists':
|
|
137
|
+
return self.path_exists(*args)
|
|
138
|
+
case 'Path.is_file':
|
|
139
|
+
return self.path_is_file(*args)
|
|
140
|
+
case 'Path.is_dir':
|
|
141
|
+
return self.path_is_dir(*args)
|
|
142
|
+
case 'Path.is_symlink':
|
|
143
|
+
return self.path_is_symlink(*args)
|
|
144
|
+
case 'Path.read_text':
|
|
145
|
+
return self.path_read_text(*args)
|
|
146
|
+
case 'Path.read_bytes':
|
|
147
|
+
return self.path_read_bytes(*args)
|
|
148
|
+
case 'Path.write_text':
|
|
149
|
+
return self.path_write_text(*args)
|
|
150
|
+
case 'Path.write_bytes':
|
|
151
|
+
return self.path_write_bytes(*args)
|
|
152
|
+
case 'Path.mkdir':
|
|
153
|
+
assert len(kwargs) <= 2, f'Unexpected keyword arguments: {kwargs}'
|
|
154
|
+
parents = kwargs.get('parents', False)
|
|
155
|
+
exist_ok = kwargs.get('exist_ok', False)
|
|
156
|
+
return self.path_mkdir(*args, parents=parents, exist_ok=exist_ok)
|
|
157
|
+
case 'Path.unlink':
|
|
158
|
+
return self.path_unlink(*args)
|
|
159
|
+
case 'Path.rmdir':
|
|
160
|
+
return self.path_rmdir(*args)
|
|
161
|
+
case 'Path.iterdir':
|
|
162
|
+
return self.path_iterdir(*args)
|
|
163
|
+
case 'Path.stat':
|
|
164
|
+
return self.path_stat(*args)
|
|
165
|
+
case 'Path.rename':
|
|
166
|
+
return self.path_rename(*args)
|
|
167
|
+
case 'Path.resolve':
|
|
168
|
+
return self.path_resolve(*args)
|
|
169
|
+
case 'Path.absolute':
|
|
170
|
+
return self.path_absolute(*args)
|
|
171
|
+
case 'os.getenv':
|
|
172
|
+
return self.getenv(*args)
|
|
173
|
+
case 'os.environ':
|
|
174
|
+
return self.get_environ()
|
|
175
|
+
|
|
176
|
+
@abstractmethod
|
|
177
|
+
def path_exists(self, path: PurePosixPath) -> bool:
|
|
178
|
+
"""Check if a path exists.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
path: The path to check.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
True if the path exists, False otherwise.
|
|
185
|
+
"""
|
|
186
|
+
raise NotImplementedError
|
|
187
|
+
|
|
188
|
+
@abstractmethod
|
|
189
|
+
def path_is_file(self, path: PurePosixPath) -> bool:
|
|
190
|
+
"""Check if a path is a regular file.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
path: The path to check.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
True if the path is a regular file, False otherwise.
|
|
197
|
+
"""
|
|
198
|
+
raise NotImplementedError
|
|
199
|
+
|
|
200
|
+
@abstractmethod
|
|
201
|
+
def path_is_dir(self, path: PurePosixPath) -> bool:
|
|
202
|
+
"""Check if a path is a directory.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
path: The path to check.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
True if the path is a directory, False otherwise.
|
|
209
|
+
"""
|
|
210
|
+
raise NotImplementedError
|
|
211
|
+
|
|
212
|
+
@abstractmethod
|
|
213
|
+
def path_is_symlink(self, path: PurePosixPath) -> bool:
|
|
214
|
+
"""Check if a path is a symbolic link.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
path: The path to check.
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
True if the path is a symbolic link, False otherwise.
|
|
221
|
+
"""
|
|
222
|
+
raise NotImplementedError
|
|
223
|
+
|
|
224
|
+
@abstractmethod
|
|
225
|
+
def path_read_text(self, path: PurePosixPath) -> str:
|
|
226
|
+
"""Read the contents of a file as text.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
path: The path to the file.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
The file contents as a string.
|
|
233
|
+
|
|
234
|
+
Raises:
|
|
235
|
+
FileNotFoundError: If the file does not exist.
|
|
236
|
+
IsADirectoryError: If the path is a directory.
|
|
237
|
+
"""
|
|
238
|
+
raise NotImplementedError
|
|
239
|
+
|
|
240
|
+
@abstractmethod
|
|
241
|
+
def path_read_bytes(self, path: PurePosixPath) -> bytes:
|
|
242
|
+
"""Read the contents of a file as bytes.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
path: The path to the file.
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
The file contents as bytes.
|
|
249
|
+
|
|
250
|
+
Raises:
|
|
251
|
+
FileNotFoundError: If the file does not exist.
|
|
252
|
+
IsADirectoryError: If the path is a directory.
|
|
253
|
+
"""
|
|
254
|
+
raise NotImplementedError
|
|
255
|
+
|
|
256
|
+
@abstractmethod
|
|
257
|
+
def path_write_text(self, path: PurePosixPath, data: str) -> int:
|
|
258
|
+
"""Write text data to a file.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
path: The path to the file.
|
|
262
|
+
data: The text content to write.
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
The number of characters written.
|
|
266
|
+
|
|
267
|
+
Raises:
|
|
268
|
+
FileNotFoundError: If the parent directory does not exist.
|
|
269
|
+
IsADirectoryError: If the path is a directory.
|
|
270
|
+
"""
|
|
271
|
+
raise NotImplementedError
|
|
272
|
+
|
|
273
|
+
@abstractmethod
|
|
274
|
+
def path_write_bytes(self, path: PurePosixPath, data: bytes) -> int:
|
|
275
|
+
"""Write binary data to a file.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
path: The path to the file.
|
|
279
|
+
data: The binary content to write.
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
The number of bytes written.
|
|
283
|
+
|
|
284
|
+
Raises:
|
|
285
|
+
FileNotFoundError: If the parent directory does not exist.
|
|
286
|
+
IsADirectoryError: If the path is a directory.
|
|
287
|
+
"""
|
|
288
|
+
raise NotImplementedError
|
|
289
|
+
|
|
290
|
+
@abstractmethod
|
|
291
|
+
def path_mkdir(self, path: PurePosixPath, parents: bool, exist_ok: bool) -> None:
|
|
292
|
+
"""Create a directory.
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
path: The path of the directory to create.
|
|
296
|
+
parents: If True, create parent directories as needed.
|
|
297
|
+
exist_ok: If True, don't raise an error if the directory exists.
|
|
298
|
+
|
|
299
|
+
Raises:
|
|
300
|
+
FileNotFoundError: If parents is False and parent directory doesn't exist.
|
|
301
|
+
FileExistsError: If exist_ok is False and the directory already exists.
|
|
302
|
+
"""
|
|
303
|
+
raise NotImplementedError
|
|
304
|
+
|
|
305
|
+
@abstractmethod
|
|
306
|
+
def path_unlink(self, path: PurePosixPath) -> None:
|
|
307
|
+
"""Remove a file.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
path: The path to the file to remove.
|
|
311
|
+
|
|
312
|
+
Raises:
|
|
313
|
+
FileNotFoundError: If the file does not exist.
|
|
314
|
+
IsADirectoryError: If the path is a directory.
|
|
315
|
+
"""
|
|
316
|
+
raise NotImplementedError
|
|
317
|
+
|
|
318
|
+
@abstractmethod
|
|
319
|
+
def path_rmdir(self, path: PurePosixPath) -> None:
|
|
320
|
+
"""Remove an empty directory.
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
path: The path to the directory to remove.
|
|
324
|
+
|
|
325
|
+
Raises:
|
|
326
|
+
FileNotFoundError: If the directory does not exist.
|
|
327
|
+
NotADirectoryError: If the path is not a directory.
|
|
328
|
+
OSError: If the directory is not empty.
|
|
329
|
+
"""
|
|
330
|
+
raise NotImplementedError
|
|
331
|
+
|
|
332
|
+
@abstractmethod
|
|
333
|
+
def path_iterdir(self, path: PurePosixPath) -> list[PurePosixPath]:
|
|
334
|
+
"""List the contents of a directory.
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
path: The path to the directory.
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
A list of full paths (as PurePosixPath) for entries in the directory.
|
|
341
|
+
|
|
342
|
+
Raises:
|
|
343
|
+
FileNotFoundError: If the directory does not exist.
|
|
344
|
+
NotADirectoryError: If the path is not a directory.
|
|
345
|
+
"""
|
|
346
|
+
raise NotImplementedError
|
|
347
|
+
|
|
348
|
+
@abstractmethod
|
|
349
|
+
def path_stat(self, path: PurePosixPath) -> StatResult:
|
|
350
|
+
"""Get file status information.
|
|
351
|
+
|
|
352
|
+
Use file_stat(), dir_stat(), or symlink_stat() helpers to create the return value.
|
|
353
|
+
|
|
354
|
+
Args:
|
|
355
|
+
path: The path to stat.
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
A StatResult with file metadata.
|
|
359
|
+
|
|
360
|
+
Raises:
|
|
361
|
+
FileNotFoundError: If the path does not exist.
|
|
362
|
+
"""
|
|
363
|
+
raise NotImplementedError
|
|
364
|
+
|
|
365
|
+
@abstractmethod
|
|
366
|
+
def path_rename(self, path: PurePosixPath, target: PurePosixPath) -> None:
|
|
367
|
+
"""Rename a file or directory.
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
path: The current path.
|
|
371
|
+
target: The new path.
|
|
372
|
+
|
|
373
|
+
Raises:
|
|
374
|
+
FileNotFoundError: If the source path does not exist.
|
|
375
|
+
FileExistsError: If the target already exists (platform-dependent).
|
|
376
|
+
"""
|
|
377
|
+
raise NotImplementedError
|
|
378
|
+
|
|
379
|
+
@abstractmethod
|
|
380
|
+
def path_resolve(self, path: PurePosixPath) -> str:
|
|
381
|
+
"""Resolve a path to an absolute path, resolving any symlinks.
|
|
382
|
+
|
|
383
|
+
Args:
|
|
384
|
+
path: The path to resolve.
|
|
385
|
+
|
|
386
|
+
Returns:
|
|
387
|
+
The resolved absolute path with symlinks resolved.
|
|
388
|
+
"""
|
|
389
|
+
raise NotImplementedError
|
|
390
|
+
|
|
391
|
+
@abstractmethod
|
|
392
|
+
def path_absolute(self, path: PurePosixPath) -> str:
|
|
393
|
+
"""Convert a path to an absolute path without resolving symlinks.
|
|
394
|
+
|
|
395
|
+
Args:
|
|
396
|
+
path: The path to convert.
|
|
397
|
+
|
|
398
|
+
Returns:
|
|
399
|
+
The absolute path.
|
|
400
|
+
"""
|
|
401
|
+
raise NotImplementedError
|
|
402
|
+
|
|
403
|
+
@abstractmethod
|
|
404
|
+
def getenv(self, key: str, default: str | None = None) -> str | None:
|
|
405
|
+
"""Get an environment variable value.
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
key: The name of the environment variable.
|
|
409
|
+
default: The value to return if the environment variable is not set.
|
|
410
|
+
|
|
411
|
+
Returns:
|
|
412
|
+
The value of the environment variable, or `default` if not set.
|
|
413
|
+
"""
|
|
414
|
+
raise NotImplementedError
|
|
415
|
+
|
|
416
|
+
@abstractmethod
|
|
417
|
+
def get_environ(self) -> dict[str, str]:
|
|
418
|
+
"""Get the entire environment as a dictionary.
|
|
419
|
+
|
|
420
|
+
Returns:
|
|
421
|
+
A dictionary containing all environment variables.
|
|
422
|
+
"""
|
|
423
|
+
raise NotImplementedError
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
class AbstractFile(Protocol):
|
|
427
|
+
"""Protocol defining the interface for files used with OSAccess.
|
|
428
|
+
|
|
429
|
+
This protocol allows custom file implementations to be used with OSAccess.
|
|
430
|
+
The built-in implementations are:
|
|
431
|
+
|
|
432
|
+
- `MemoryFile`: Stores content in memory (recommended for sandboxed execution)
|
|
433
|
+
- `CallbackFile`: Delegates to custom callbacks (use with caution - see its docstring)
|
|
434
|
+
|
|
435
|
+
Security Note:
|
|
436
|
+
Custom implementations of this protocol run in the host Python environment.
|
|
437
|
+
The `read_content()` and `write_content()` methods can execute arbitrary code,
|
|
438
|
+
including accessing the real filesystem. Only use implementations you trust.
|
|
439
|
+
|
|
440
|
+
For sandboxed execution where Monty code should not access real files,
|
|
441
|
+
use `MemoryFile` which stores all content in memory.
|
|
442
|
+
|
|
443
|
+
Attributes:
|
|
444
|
+
path: The virtual path of the file within the OSAccess filesystem.
|
|
445
|
+
name: The filename (basename) extracted from path.
|
|
446
|
+
permissions: Unix-style permission bits (e.g., 0o644).
|
|
447
|
+
deleted: Whether the file has been marked as deleted.
|
|
448
|
+
"""
|
|
449
|
+
|
|
450
|
+
path: PurePosixPath
|
|
451
|
+
name: str
|
|
452
|
+
permissions: int
|
|
453
|
+
deleted: bool
|
|
454
|
+
|
|
455
|
+
def read_content(self) -> str | bytes:
|
|
456
|
+
"""Read and return the file's content."""
|
|
457
|
+
...
|
|
458
|
+
|
|
459
|
+
def write_content(self, content: str | bytes) -> None:
|
|
460
|
+
"""Write content to the file."""
|
|
461
|
+
...
|
|
462
|
+
|
|
463
|
+
def delete(self) -> None:
|
|
464
|
+
"""Mark the file as deleted."""
|
|
465
|
+
...
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
Tree: TypeAlias = 'dict[str, AbstractFile | Tree]'
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def _is_file(entry: None | AbstractFile | Tree) -> TypeGuard[AbstractFile]:
|
|
472
|
+
return hasattr(entry, 'path')
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def _is_dir(entry: None | AbstractFile | Tree) -> TypeGuard[Tree]:
|
|
476
|
+
return isinstance(entry, dict)
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
class MemoryFile:
|
|
480
|
+
"""An in-memory virtual file for use with OSAccess.
|
|
481
|
+
|
|
482
|
+
This is the recommended file type for sandboxed Monty execution. Content is
|
|
483
|
+
stored entirely in Python memory with no access to the real filesystem.
|
|
484
|
+
|
|
485
|
+
When Monty code reads from this file, it receives the stored content.
|
|
486
|
+
When Monty code writes to this file, the content attribute is updated.
|
|
487
|
+
|
|
488
|
+
Example::
|
|
489
|
+
|
|
490
|
+
from pydantic_monty import Monty, OSAccess, MemoryFile
|
|
491
|
+
|
|
492
|
+
fs = OSAccess(
|
|
493
|
+
[
|
|
494
|
+
MemoryFile('/config.json', '{"debug": true}'),
|
|
495
|
+
MemoryFile('/data.bin', b'\\x00\\x01\\x02'),
|
|
496
|
+
]
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
result = Monty('''
|
|
500
|
+
from pathlib import Path
|
|
501
|
+
Path('/config.json').read_text()
|
|
502
|
+
''').run(os=fs)
|
|
503
|
+
# result == '{"debug": true}'
|
|
504
|
+
|
|
505
|
+
Attributes:
|
|
506
|
+
path: The virtual path of the file within the OSAccess filesystem.
|
|
507
|
+
name: The filename (basename) extracted from path.
|
|
508
|
+
content: The file content (str for text, bytes for binary).
|
|
509
|
+
permissions: Unix-style permission bits (default: 0o644).
|
|
510
|
+
deleted: Whether the file has been marked as deleted.
|
|
511
|
+
"""
|
|
512
|
+
|
|
513
|
+
path: PurePosixPath
|
|
514
|
+
name: str
|
|
515
|
+
content: str | bytes
|
|
516
|
+
permissions: int = 0o644
|
|
517
|
+
deleted: bool
|
|
518
|
+
|
|
519
|
+
def __init__(self, path: str | PurePosixPath, content: str | bytes, *, permissions: int = 0o644) -> None:
|
|
520
|
+
"""Create an in-memory virtual file.
|
|
521
|
+
|
|
522
|
+
Args:
|
|
523
|
+
path: The virtual path for this file in the OSAccess filesystem.
|
|
524
|
+
content: The initial file content (str for text, bytes for binary).
|
|
525
|
+
permissions: Unix-style permission bits (default: 0o644).
|
|
526
|
+
"""
|
|
527
|
+
self.path = PurePosixPath(path)
|
|
528
|
+
self.name = self.path.name
|
|
529
|
+
self.content = content
|
|
530
|
+
self.permissions = permissions
|
|
531
|
+
self.deleted = False
|
|
532
|
+
|
|
533
|
+
def read_content(self) -> str | bytes:
|
|
534
|
+
"""Return the stored content."""
|
|
535
|
+
return self.content
|
|
536
|
+
|
|
537
|
+
def write_content(self, content: str | bytes) -> None:
|
|
538
|
+
"""Update the stored content."""
|
|
539
|
+
self.content = content
|
|
540
|
+
|
|
541
|
+
def delete(self) -> None:
|
|
542
|
+
"""Mark the file as deleted."""
|
|
543
|
+
self.deleted = True
|
|
544
|
+
|
|
545
|
+
def __repr__(self) -> str:
|
|
546
|
+
repr_content = "'...'" if isinstance(self.content, str) else "b'...'"
|
|
547
|
+
return f'MemoryFile(path={self.path}, content={repr_content}, permissions={self.permissions})'
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
_type_check_memory_file: AbstractFile = MemoryFile('test.txt', '')
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
class CallbackFile:
|
|
554
|
+
"""A virtual file backed by custom read/write callbacks.
|
|
555
|
+
|
|
556
|
+
This class allows you to create files whose content is dynamically generated
|
|
557
|
+
or persisted through custom logic. When Monty code reads or writes to this file,
|
|
558
|
+
the provided callbacks are invoked.
|
|
559
|
+
|
|
560
|
+
Security Warning:
|
|
561
|
+
The callbacks execute in the host Python environment with FULL access to
|
|
562
|
+
the real filesystem, network, and all system resources. A callback that
|
|
563
|
+
accesses the real filesystem effectively breaks the Monty sandbox.
|
|
564
|
+
|
|
565
|
+
Example of UNSAFE usage that breaks the sandbox::
|
|
566
|
+
|
|
567
|
+
# DON'T DO THIS - allows Monty to read real files!
|
|
568
|
+
CallbackFile(
|
|
569
|
+
'/config.txt',
|
|
570
|
+
read=lambda p: open('/etc/passwd').read(),
|
|
571
|
+
write=lambda p, c: open('/tmp/out', 'w').write(c),
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
For sandboxed execution, use `MemoryFile` instead, which stores content
|
|
575
|
+
purely in memory with no external access.
|
|
576
|
+
|
|
577
|
+
Safe use cases for CallbackFile:
|
|
578
|
+
- Returning dynamically computed content (e.g., current timestamp)
|
|
579
|
+
- Logging writes without persisting them
|
|
580
|
+
- Validating/transforming content before storage in memory
|
|
581
|
+
- Integration testing with controlled external resources
|
|
582
|
+
|
|
583
|
+
Attributes:
|
|
584
|
+
path: The virtual path of the file within the OSAccess filesystem.
|
|
585
|
+
name: The filename (basename) extracted from path.
|
|
586
|
+
read: Callback invoked when the file is read. Receives the path and
|
|
587
|
+
must return str or bytes.
|
|
588
|
+
write: Callback invoked when the file is written. Receives the path
|
|
589
|
+
and content (str or bytes).
|
|
590
|
+
permissions: Unix-style permission bits (default: 0o644).
|
|
591
|
+
deleted: Whether the file has been marked as deleted.
|
|
592
|
+
"""
|
|
593
|
+
|
|
594
|
+
path: PurePosixPath
|
|
595
|
+
name: str
|
|
596
|
+
read: Callable[[PurePosixPath], str | bytes]
|
|
597
|
+
write: Callable[[PurePosixPath, str | bytes], None]
|
|
598
|
+
permissions: int = 0o644
|
|
599
|
+
deleted: bool
|
|
600
|
+
|
|
601
|
+
def __init__(
|
|
602
|
+
self,
|
|
603
|
+
path: str | PurePosixPath,
|
|
604
|
+
read: Callable[[PurePosixPath], str | bytes],
|
|
605
|
+
write: Callable[[PurePosixPath, str | bytes], None],
|
|
606
|
+
*,
|
|
607
|
+
permissions: int = 0o644,
|
|
608
|
+
) -> None:
|
|
609
|
+
"""Create a callback-backed virtual file.
|
|
610
|
+
|
|
611
|
+
Args:
|
|
612
|
+
path: The virtual path for this file in the OSAccess filesystem.
|
|
613
|
+
read: Callback to generate content when the file is read.
|
|
614
|
+
write: Callback to handle content when the file is written.
|
|
615
|
+
permissions: Unix-style permission bits (default: 0o644).
|
|
616
|
+
"""
|
|
617
|
+
self.path = PurePosixPath(path)
|
|
618
|
+
self.name = self.path.name
|
|
619
|
+
self.read = read
|
|
620
|
+
self.write = write
|
|
621
|
+
self.permissions = permissions
|
|
622
|
+
self.deleted = False
|
|
623
|
+
|
|
624
|
+
def read_content(self) -> str | bytes:
|
|
625
|
+
"""Read content by invoking the read callback."""
|
|
626
|
+
return self.read(self.path)
|
|
627
|
+
|
|
628
|
+
def write_content(self, content: str | bytes) -> None:
|
|
629
|
+
"""Write content by invoking the write callback."""
|
|
630
|
+
self.write(self.path, content)
|
|
631
|
+
|
|
632
|
+
def delete(self) -> None:
|
|
633
|
+
"""Mark the file as deleted."""
|
|
634
|
+
self.deleted = True
|
|
635
|
+
|
|
636
|
+
def __repr__(self) -> str:
|
|
637
|
+
return f'CallbackFile(path={self.path}, read={self.read}, write={self.write}, permissions={self.permissions})'
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
_type_check_callback_file: AbstractFile = CallbackFile('test.txt', lambda _: '', lambda _, __: None)
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
class OSAccess(AbstractOS):
|
|
644
|
+
"""In-memory virtual filesystem for sandboxed Monty execution.
|
|
645
|
+
|
|
646
|
+
OSAccess provides a complete virtual filesystem that Monty code can interact
|
|
647
|
+
with via `pathlib.Path` methods. Files exist only in memory (when using
|
|
648
|
+
`MemoryFile`) and cannot access the real filesystem.
|
|
649
|
+
|
|
650
|
+
Security Model:
|
|
651
|
+
When using `MemoryFile` objects, OSAccess is fully sandboxed:
|
|
652
|
+
|
|
653
|
+
- Monty code can only access files explicitly registered with OSAccess
|
|
654
|
+
- Path traversal (e.g., `../../etc/passwd`) cannot escape to real files
|
|
655
|
+
- All file content is stored in Python memory, not on disk
|
|
656
|
+
- Environment variables are isolated to the provided `environ` dict
|
|
657
|
+
|
|
658
|
+
However, if `CallbackFile` is used, the callbacks run in the host
|
|
659
|
+
environment and CAN access real resources. See `CallbackFile` docstring.
|
|
660
|
+
|
|
661
|
+
Attributes:
|
|
662
|
+
files: List of AbstractFile objects registered with this filesystem.
|
|
663
|
+
environ: Dictionary of environment variables accessible via os.getenv().
|
|
664
|
+
"""
|
|
665
|
+
|
|
666
|
+
files: list[AbstractFile]
|
|
667
|
+
environ: dict[str, str]
|
|
668
|
+
_tree: Tree
|
|
669
|
+
|
|
670
|
+
def __init__(
|
|
671
|
+
self,
|
|
672
|
+
files: Sequence[AbstractFile] | None = None,
|
|
673
|
+
environ: dict[str, str] | None = None,
|
|
674
|
+
*,
|
|
675
|
+
root_dir: str | PurePosixPath = '/',
|
|
676
|
+
):
|
|
677
|
+
"""Create a virtual filesystem with the given files.
|
|
678
|
+
|
|
679
|
+
Args:
|
|
680
|
+
files: Files to register in the virtual filesystem. Use `MemoryFile`
|
|
681
|
+
for sandboxed in-memory files, or `CallbackFile` for custom logic
|
|
682
|
+
(with security caveats - see its docstring).
|
|
683
|
+
environ: Environment variables accessible to Monty code via os.getenv().
|
|
684
|
+
Isolated from the real environment.
|
|
685
|
+
root_dir: Base directory for normalizing relative file paths. Relative
|
|
686
|
+
paths in files will be prefixed with this. Default is '/'.
|
|
687
|
+
|
|
688
|
+
Raises:
|
|
689
|
+
AssertionError: If root_dir is not an absolute path.
|
|
690
|
+
ValueError: If a file path conflicts with another file (e.g., trying
|
|
691
|
+
to create a file inside another file's path).
|
|
692
|
+
"""
|
|
693
|
+
self.files = list(files) if files else []
|
|
694
|
+
self.environ = environ or {}
|
|
695
|
+
# Initialize tree with root directory - / is always present
|
|
696
|
+
self._tree = {'/': {}}
|
|
697
|
+
root_dir = PurePosixPath(root_dir)
|
|
698
|
+
assert root_dir.is_absolute(), f'Root directory must be absolute, got {root_dir}'
|
|
699
|
+
for file in self.files:
|
|
700
|
+
if not file.path.is_absolute():
|
|
701
|
+
file.path = root_dir / file.path
|
|
702
|
+
|
|
703
|
+
subtree = self._tree
|
|
704
|
+
*dir_parts, name = file.path.parts
|
|
705
|
+
for part in dir_parts:
|
|
706
|
+
entry = subtree.setdefault(part, {})
|
|
707
|
+
if _is_dir(entry):
|
|
708
|
+
subtree = entry
|
|
709
|
+
else:
|
|
710
|
+
raise ValueError(f'Cannot put file {file} within sub-directory of file {entry}')
|
|
711
|
+
|
|
712
|
+
subtree[name] = file
|
|
713
|
+
|
|
714
|
+
def __repr__(self) -> str:
|
|
715
|
+
return f'OSAccess(files={self.files}, environ={self.environ})'
|
|
716
|
+
|
|
717
|
+
def path_exists(self, path: PurePosixPath) -> bool:
|
|
718
|
+
return self._get_entry(path) is not None
|
|
719
|
+
|
|
720
|
+
def path_is_file(self, path: PurePosixPath) -> bool:
|
|
721
|
+
return _is_file(self._get_entry(path))
|
|
722
|
+
|
|
723
|
+
def path_is_dir(self, path: PurePosixPath) -> bool:
|
|
724
|
+
return _is_dir(self._get_entry(path))
|
|
725
|
+
|
|
726
|
+
def path_is_symlink(self, path: PurePosixPath) -> bool:
|
|
727
|
+
return False
|
|
728
|
+
|
|
729
|
+
def path_read_text(self, path: PurePosixPath) -> str:
|
|
730
|
+
file = self._get_file(path)
|
|
731
|
+
content = file.read_content()
|
|
732
|
+
return content if isinstance(content, str) else content.decode()
|
|
733
|
+
|
|
734
|
+
def path_read_bytes(self, path: PurePosixPath) -> bytes:
|
|
735
|
+
file = self._get_file(path)
|
|
736
|
+
content = file.read_content()
|
|
737
|
+
return content if isinstance(content, bytes) else content.encode()
|
|
738
|
+
|
|
739
|
+
def path_write_text(self, path: PurePosixPath, data: str) -> int:
|
|
740
|
+
self._write_file(path, data)
|
|
741
|
+
return len(data)
|
|
742
|
+
|
|
743
|
+
def path_write_bytes(self, path: PurePosixPath, data: bytes) -> int:
|
|
744
|
+
self._write_file(path, data)
|
|
745
|
+
return len(data)
|
|
746
|
+
|
|
747
|
+
def _write_file(self, path: PurePosixPath, data: bytes | str) -> None:
|
|
748
|
+
entry = self._get_entry(path)
|
|
749
|
+
if _is_file(entry):
|
|
750
|
+
entry.write_content(data)
|
|
751
|
+
return
|
|
752
|
+
elif _is_dir(entry):
|
|
753
|
+
raise IsADirectoryError(f'[Errno 21] Is a directory: {str(path)!r}')
|
|
754
|
+
|
|
755
|
+
# write a new file if the parent directory exists
|
|
756
|
+
parent_entry = self._parent_entry(path)
|
|
757
|
+
if _is_dir(parent_entry):
|
|
758
|
+
file_path = PurePosixPath(path)
|
|
759
|
+
parent_entry[file_path.name] = new_file = MemoryFile(file_path, data)
|
|
760
|
+
self.files.append(new_file)
|
|
761
|
+
else:
|
|
762
|
+
raise FileNotFoundError(f'[Errno 2] No such file or directory: {str(path)!r}')
|
|
763
|
+
|
|
764
|
+
def path_mkdir(self, path: PurePosixPath, parents: bool, exist_ok: bool) -> None:
|
|
765
|
+
entry = self._get_entry(path)
|
|
766
|
+
if _is_file(entry):
|
|
767
|
+
raise FileExistsError(f'[Errno 17] File exists: {str(path)!r}')
|
|
768
|
+
elif _is_dir(entry):
|
|
769
|
+
if exist_ok:
|
|
770
|
+
return
|
|
771
|
+
else:
|
|
772
|
+
raise FileExistsError(f'[Errno 17] File exists: {str(path)!r}')
|
|
773
|
+
|
|
774
|
+
parent_entry = self._parent_entry(path)
|
|
775
|
+
if _is_dir(parent_entry):
|
|
776
|
+
parent_entry[PurePosixPath(path).name] = {}
|
|
777
|
+
return
|
|
778
|
+
elif _is_file(parent_entry):
|
|
779
|
+
raise NotADirectoryError(f'[Errno 20] Not a directory: {str(path)!r}')
|
|
780
|
+
elif parents:
|
|
781
|
+
subtree = self._tree
|
|
782
|
+
for part in PurePosixPath(path).parts:
|
|
783
|
+
entry = subtree.setdefault(part, {})
|
|
784
|
+
if _is_dir(entry):
|
|
785
|
+
subtree = entry
|
|
786
|
+
else:
|
|
787
|
+
raise NotADirectoryError(f'[Errno 20] Not a directory: {str(path)!r}')
|
|
788
|
+
else:
|
|
789
|
+
raise FileNotFoundError(f'[Errno 2] No such file or directory: {str(path)!r}')
|
|
790
|
+
|
|
791
|
+
def path_unlink(self, path: PurePosixPath) -> None:
|
|
792
|
+
file = self._get_file(path)
|
|
793
|
+
file.delete()
|
|
794
|
+
# remove from parent
|
|
795
|
+
parent_dir = self._parent_entry(path)
|
|
796
|
+
assert _is_dir(parent_dir), f'Expected parent of a file to always be a directory, got {parent_dir}'
|
|
797
|
+
del parent_dir[file.name]
|
|
798
|
+
|
|
799
|
+
def path_rmdir(self, path: PurePosixPath) -> None:
|
|
800
|
+
dir = self._get_dir(path)
|
|
801
|
+
if dir:
|
|
802
|
+
raise OSError(f'[Errno 39] Directory not empty: {str(path)!r}')
|
|
803
|
+
# remove from parent
|
|
804
|
+
parent_dir = self._parent_entry(path)
|
|
805
|
+
assert _is_dir(parent_dir), f'Expected parent of a file to always be a directory, got {parent_dir}'
|
|
806
|
+
del parent_dir[PurePosixPath(path).name]
|
|
807
|
+
|
|
808
|
+
def path_iterdir(self, path: PurePosixPath) -> list[PurePosixPath]:
|
|
809
|
+
# Return full paths as PurePosixPath objects (will be converted to MontyObject::Path)
|
|
810
|
+
dir_path = PurePosixPath(path)
|
|
811
|
+
return [dir_path / name for name in self._get_dir(path).keys()]
|
|
812
|
+
|
|
813
|
+
def path_stat(self, path: PurePosixPath) -> StatResult:
|
|
814
|
+
entry = self._get_entry_exists(path)
|
|
815
|
+
if _is_file(entry):
|
|
816
|
+
content = entry.read_content()
|
|
817
|
+
size = len(content) if isinstance(content, bytes) else len(content.encode())
|
|
818
|
+
return StatResult.file_stat(size=size, mode=entry.permissions)
|
|
819
|
+
else:
|
|
820
|
+
return StatResult.dir_stat()
|
|
821
|
+
|
|
822
|
+
def path_rename(self, path: PurePosixPath, target: PurePosixPath) -> None:
|
|
823
|
+
src_entry = self._get_entry(path)
|
|
824
|
+
if src_entry is None:
|
|
825
|
+
raise FileNotFoundError(f'[Errno 2] No such file or directory: {str(path)!r} -> {str(target)!r}')
|
|
826
|
+
|
|
827
|
+
parent_dir = self._parent_entry(path)
|
|
828
|
+
assert _is_dir(parent_dir), f'Expected parent of a file to always be a directory, got {parent_dir}'
|
|
829
|
+
|
|
830
|
+
target_parent = self._parent_entry(target)
|
|
831
|
+
if not _is_dir(target_parent):
|
|
832
|
+
raise FileNotFoundError(f'[Errno 2] No such file or directory: {str(path)!r} -> {str(target)!r}')
|
|
833
|
+
target_entry = self._get_entry(target)
|
|
834
|
+
|
|
835
|
+
if _is_file(src_entry):
|
|
836
|
+
if _is_dir(target_entry):
|
|
837
|
+
raise IsADirectoryError(f'[Errno 21] Is a directory: {str(path)!r} -> {str(target)!r}')
|
|
838
|
+
if _is_file(target_entry):
|
|
839
|
+
# need to mark the target as deleted as it'll be overwritten
|
|
840
|
+
target_entry.delete()
|
|
841
|
+
|
|
842
|
+
src_name = src_entry.path.name
|
|
843
|
+
target_name = PurePosixPath(target).name
|
|
844
|
+
# remove it from the old directory
|
|
845
|
+
del parent_dir[src_name]
|
|
846
|
+
# and put it in the new directory
|
|
847
|
+
target_parent[target_name] = src_entry
|
|
848
|
+
else:
|
|
849
|
+
assert _is_dir(src_entry), 'src path must be a directory here'
|
|
850
|
+
if _is_file(target_entry):
|
|
851
|
+
raise NotADirectoryError(f'[Errno 20] Not a directory: {str(path)!r} -> {str(target)!r}')
|
|
852
|
+
elif _is_dir(target_entry) and target_entry:
|
|
853
|
+
raise OSError(f'[Errno 66] Directory not empty: {str(path)!r} -> {str(target)!r}')
|
|
854
|
+
|
|
855
|
+
src_name = PurePosixPath(path).name
|
|
856
|
+
target_name = PurePosixPath(target).name
|
|
857
|
+
# remove it from the old directory
|
|
858
|
+
del parent_dir[src_name]
|
|
859
|
+
# and put it in the new directory
|
|
860
|
+
target_parent[target_name] = src_entry
|
|
861
|
+
|
|
862
|
+
# Update paths for all files in the renamed directory
|
|
863
|
+
self._update_paths_recursive(src_entry, PurePosixPath(path), PurePosixPath(target))
|
|
864
|
+
|
|
865
|
+
def path_resolve(self, path: PurePosixPath) -> str:
|
|
866
|
+
# No symlinks in OSAccess, so resolve is same as absolute with normalization
|
|
867
|
+
return self.path_absolute(path)
|
|
868
|
+
|
|
869
|
+
def path_absolute(self, path: PurePosixPath) -> str:
|
|
870
|
+
p = PurePosixPath(path)
|
|
871
|
+
if p.is_absolute():
|
|
872
|
+
return str(p)
|
|
873
|
+
# In this virtual filesystem, we treat '/' as the working directory
|
|
874
|
+
return str(PurePosixPath('/') / p)
|
|
875
|
+
|
|
876
|
+
def getenv(self, key: str, default: str | None = None) -> str | None:
|
|
877
|
+
return self.environ.get(key, default)
|
|
878
|
+
|
|
879
|
+
def get_environ(self) -> dict[str, str]:
|
|
880
|
+
return self.environ
|
|
881
|
+
|
|
882
|
+
def _get_entry(self, path: PurePosixPath) -> Tree | AbstractFile | None:
|
|
883
|
+
dir = self._tree
|
|
884
|
+
|
|
885
|
+
*dir_parts, name = PurePosixPath(path).parts
|
|
886
|
+
|
|
887
|
+
for part in dir_parts:
|
|
888
|
+
entry = dir.get(part)
|
|
889
|
+
if _is_dir(entry):
|
|
890
|
+
dir = entry
|
|
891
|
+
else:
|
|
892
|
+
return None
|
|
893
|
+
|
|
894
|
+
return dir.get(name)
|
|
895
|
+
|
|
896
|
+
def _get_entry_exists(self, path: PurePosixPath) -> Tree | AbstractFile:
|
|
897
|
+
entry = self._get_entry(path)
|
|
898
|
+
if entry is None:
|
|
899
|
+
raise FileNotFoundError(f'[Errno 2] No such file or directory: {str(path)!r}')
|
|
900
|
+
else:
|
|
901
|
+
return entry
|
|
902
|
+
|
|
903
|
+
def _get_file(self, path: PurePosixPath) -> AbstractFile:
|
|
904
|
+
entry = self._get_entry_exists(path)
|
|
905
|
+
if _is_file(entry):
|
|
906
|
+
return entry
|
|
907
|
+
else:
|
|
908
|
+
raise IsADirectoryError(f'[Errno 21] Is a directory: {str(path)!r}')
|
|
909
|
+
|
|
910
|
+
def _get_dir(self, path: PurePosixPath) -> Tree:
|
|
911
|
+
entry = self._get_entry_exists(path)
|
|
912
|
+
if _is_dir(entry):
|
|
913
|
+
return entry
|
|
914
|
+
else:
|
|
915
|
+
raise NotADirectoryError(f'[Errno 20] Not a directory: {str(path)!r}')
|
|
916
|
+
|
|
917
|
+
def _parent_entry(self, path: PurePosixPath) -> Tree | AbstractFile | None:
|
|
918
|
+
return self._get_entry(PurePosixPath(path).parent)
|
|
919
|
+
|
|
920
|
+
def _update_paths_recursive(self, tree: Tree, old_prefix: PurePosixPath, new_prefix: PurePosixPath) -> None:
|
|
921
|
+
"""Update path attributes for all files in a tree after directory rename.
|
|
922
|
+
|
|
923
|
+
When a directory is renamed, the internal tree structure is moved but
|
|
924
|
+
AbstractFile objects still have their old paths. This method recursively
|
|
925
|
+
updates all file paths by replacing old_prefix with new_prefix.
|
|
926
|
+
"""
|
|
927
|
+
for entry in tree.values():
|
|
928
|
+
if _is_file(entry):
|
|
929
|
+
# Replace old prefix with new prefix in file path
|
|
930
|
+
relative = entry.path.relative_to(old_prefix)
|
|
931
|
+
entry.path = new_prefix / relative
|
|
932
|
+
elif _is_dir(entry):
|
|
933
|
+
self._update_paths_recursive(entry, old_prefix, new_prefix)
|