shellsim 0.1.13__tar.gz → 0.1.15__tar.gz
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.
- {shellsim-0.1.13 → shellsim-0.1.15}/Cargo.lock +1 -1
- {shellsim-0.1.13 → shellsim-0.1.15}/Cargo.toml +1 -1
- {shellsim-0.1.13 → shellsim-0.1.15}/PKG-INFO +1 -1
- {shellsim-0.1.13 → shellsim-0.1.15}/python/native/Cargo.lock +2 -2
- {shellsim-0.1.13 → shellsim-0.1.15}/python/native/Cargo.toml +1 -1
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/protocol.rs +63 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/asyncio.py +269 -38
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/vm/calls.rs +14 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/LICENSE +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/README.md +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/pyproject.toml +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/python/native/src/lib.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/python/shellsim/__init__.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/python/shellsim/__main__.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/python/shellsim/_api.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/python/shellsim/_cli.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/python/shellsim/py.typed +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/python/shellsim/python.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/rust-toolchain.toml +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/bin/shellsim-python.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/clock.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/archives.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/awk/ast.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/awk/eval.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/awk/lexer.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/awk/parser.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/awk.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/builtins.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/dd.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/echo.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/find.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/fs.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/apply.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/commit.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/compare.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/config.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/conflict.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/diff.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/ignore.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/import.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/log.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/merge.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/mod.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/plumbing.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/rebase.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/refs.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/repo.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/stash.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/switch.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/git/worktree.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/hashing.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/makecmd.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/mod.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/net.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/options.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/patch.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/pkg.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/printf.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/proc.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/regex_compat.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/rgcmd.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/sed.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/sort.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/system.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/tarcmd.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/text.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/unavailable.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/util.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/commands/zipcmd.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/descriptors.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/exec.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/expand.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/harness.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/harness_manager.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/hashes.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/host_ingest.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/interp.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/jqcmd.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/lib.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/main.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/mcp.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/net.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/netcmd.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/process.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/pseudo_fs.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/ast.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/bytecode.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/compiler.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/filesystem.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/heap.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/http.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/lexer.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/mapping.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/mod.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/native.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/number.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/object_model.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/parser.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/process.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/slice.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/source.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/argparse.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/asyncio.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/base64.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/bisect.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/collections.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/core.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/dataclasses.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/enum.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/frozen.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/functools.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/hashlib.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/heapq.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/http.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/importlib.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/itertools.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/json.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/math.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/mod.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/numpy.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/os.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/pytest.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/re.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/abc.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/base64.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/cmath.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/codecs.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/collections.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/complex.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/copy.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/csv.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/datetime.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/glob.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/hashlib.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/http.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/http_client.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/importlib.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/io.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/json.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/logging.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/numpy_random.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/os.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/pathlib.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/pytest.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/random.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/shutil.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/statistics.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/struct.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/subprocess.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/tempfile.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/textwrap.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/urllib.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/urllib_error.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/urllib_request.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/uuid.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/zipfile.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/source/zlib.py +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/string.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/struct.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/subprocess.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/sys.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/time.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/typing.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/unittest.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/vfs.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/stdlib/zlib.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/string.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/token.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/vm/dispatch.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/vm/host.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/vm/iteration.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/vm/namespace.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/vm/native_runtime.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/vm/objects.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/vm/operations.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/python/vm.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/resources.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/sandbox.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/scenario.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/scheduler.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/shell.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/telemetry.rs +0 -0
- {shellsim-0.1.13 → shellsim-0.1.15}/src/vfs.rs +0 -0
|
@@ -406,7 +406,7 @@ dependencies = [
|
|
|
406
406
|
|
|
407
407
|
[[package]]
|
|
408
408
|
name = "shellsim"
|
|
409
|
-
version = "0.1.
|
|
409
|
+
version = "0.1.15"
|
|
410
410
|
dependencies = [
|
|
411
411
|
"base64",
|
|
412
412
|
"crc32fast",
|
|
@@ -427,7 +427,7 @@ dependencies = [
|
|
|
427
427
|
|
|
428
428
|
[[package]]
|
|
429
429
|
name = "shellsim-python-bindings"
|
|
430
|
-
version = "0.1.
|
|
430
|
+
version = "0.1.15"
|
|
431
431
|
dependencies = [
|
|
432
432
|
"pyo3",
|
|
433
433
|
"serde",
|
|
@@ -20,6 +20,25 @@ pub fn display(heap: &Heap, value: &Value) -> Result<String, String> {
|
|
|
20
20
|
if let Some((kind, message)) = exception_parts(heap, value)? {
|
|
21
21
|
return Ok(if message.is_empty() { kind } else { message });
|
|
22
22
|
}
|
|
23
|
+
if let Some((_, args)) = user_exception_parts(heap, value)? {
|
|
24
|
+
return match args.as_slice() {
|
|
25
|
+
[] => Ok(String::new()),
|
|
26
|
+
[only] => {
|
|
27
|
+
if let Some(value) = string_value(heap, only)? {
|
|
28
|
+
Ok(value)
|
|
29
|
+
} else {
|
|
30
|
+
repr(heap, only)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
_ => {
|
|
34
|
+
let values = args
|
|
35
|
+
.iter()
|
|
36
|
+
.map(|value| repr(heap, value))
|
|
37
|
+
.collect::<Result<Vec<_>, _>>()?;
|
|
38
|
+
Ok(format!("({})", values.join(", ")))
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
23
42
|
repr(heap, value)
|
|
24
43
|
}
|
|
25
44
|
|
|
@@ -100,6 +119,41 @@ pub fn exception_parts(heap: &Heap, value: &Value) -> Result<Option<(String, Str
|
|
|
100
119
|
})
|
|
101
120
|
}
|
|
102
121
|
|
|
122
|
+
fn user_exception_parts(
|
|
123
|
+
heap: &Heap,
|
|
124
|
+
value: &Value,
|
|
125
|
+
) -> Result<Option<(String, Vec<Value>)>, String> {
|
|
126
|
+
let Some(id) = value.object_id() else {
|
|
127
|
+
return Ok(None);
|
|
128
|
+
};
|
|
129
|
+
let Object::Instance { class, .. } = heap.get(id)? else {
|
|
130
|
+
return Ok(None);
|
|
131
|
+
};
|
|
132
|
+
let Object::Class {
|
|
133
|
+
name,
|
|
134
|
+
exception_base,
|
|
135
|
+
..
|
|
136
|
+
} = heap.get(*class)?
|
|
137
|
+
else {
|
|
138
|
+
return Ok(None);
|
|
139
|
+
};
|
|
140
|
+
if exception_base.is_none() {
|
|
141
|
+
return Ok(None);
|
|
142
|
+
}
|
|
143
|
+
let args = if let Some(symbol) = heap.symbol_id("args") {
|
|
144
|
+
heap.attribute_by_symbol(id, symbol)?
|
|
145
|
+
.and_then(|value| value.object_id())
|
|
146
|
+
.and_then(|args| match heap.get(args).ok()? {
|
|
147
|
+
Object::Tuple(values) => Some(values.clone()),
|
|
148
|
+
_ => None,
|
|
149
|
+
})
|
|
150
|
+
.unwrap_or_default()
|
|
151
|
+
} else {
|
|
152
|
+
Vec::new()
|
|
153
|
+
};
|
|
154
|
+
Ok(Some((name.clone(), args)))
|
|
155
|
+
}
|
|
156
|
+
|
|
103
157
|
fn bigint_value<'a>(heap: &'a Heap, value: &Value) -> Option<&'a BigInt> {
|
|
104
158
|
let id = value.object_id()?;
|
|
105
159
|
match heap.get(id).ok()? {
|
|
@@ -244,6 +298,15 @@ fn render(heap: &Heap, value: &Value, active: &mut BTreeSet<ObjectId>) -> Result
|
|
|
244
298
|
Object::Instance { class, payload, .. } => match payload {
|
|
245
299
|
InstancePayload::Int(value) => value.to_string(),
|
|
246
300
|
InstancePayload::Object => match heap.get(*class)? {
|
|
301
|
+
Object::Class {
|
|
302
|
+
name,
|
|
303
|
+
exception_base: Some(_),
|
|
304
|
+
..
|
|
305
|
+
} => {
|
|
306
|
+
let (_, args) = user_exception_parts(heap, value)?
|
|
307
|
+
.ok_or("exception instance lost its native base")?;
|
|
308
|
+
format!("{name}({})", render_values(heap, &args, active)?.join(", "))
|
|
309
|
+
}
|
|
247
310
|
Object::Class { name, .. } => format!("<{name} object>"),
|
|
248
311
|
_ => return Err("instance has an invalid class".into()),
|
|
249
312
|
},
|
|
@@ -33,6 +33,40 @@ class QueueFull(Exception):
|
|
|
33
33
|
pass
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
class InvalidStateError(Exception):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class Handle:
|
|
41
|
+
def __init__(self, callback, args):
|
|
42
|
+
self._callback = callback
|
|
43
|
+
self._args = args
|
|
44
|
+
self._cancelled = False
|
|
45
|
+
|
|
46
|
+
def cancel(self):
|
|
47
|
+
self._cancelled = True
|
|
48
|
+
|
|
49
|
+
def cancelled(self):
|
|
50
|
+
return self._cancelled
|
|
51
|
+
|
|
52
|
+
def _run(self):
|
|
53
|
+
if self._cancelled:
|
|
54
|
+
return
|
|
55
|
+
try:
|
|
56
|
+
self._callback(*self._args)
|
|
57
|
+
except Exception:
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TimerHandle(Handle):
|
|
62
|
+
def __init__(self, when, callback, args):
|
|
63
|
+
Handle.__init__(self, callback, args)
|
|
64
|
+
self._when = when
|
|
65
|
+
|
|
66
|
+
def when(self):
|
|
67
|
+
return self._when
|
|
68
|
+
|
|
69
|
+
|
|
36
70
|
class _Sleep:
|
|
37
71
|
def __init__(self, delay):
|
|
38
72
|
self.delay = delay
|
|
@@ -87,6 +121,100 @@ class _TimeoutWait:
|
|
|
87
121
|
self.timed_out = False
|
|
88
122
|
|
|
89
123
|
|
|
124
|
+
class Future:
|
|
125
|
+
def __init__(self, *, loop=None):
|
|
126
|
+
if loop is None:
|
|
127
|
+
loop = get_running_loop()
|
|
128
|
+
self._loop = loop
|
|
129
|
+
self._done = False
|
|
130
|
+
self._cancelled = False
|
|
131
|
+
self._result = None
|
|
132
|
+
self._exception = None
|
|
133
|
+
self._waiters = []
|
|
134
|
+
self._callbacks = []
|
|
135
|
+
|
|
136
|
+
def get_loop(self):
|
|
137
|
+
return self._loop
|
|
138
|
+
|
|
139
|
+
def done(self):
|
|
140
|
+
return self._done
|
|
141
|
+
|
|
142
|
+
def cancelled(self):
|
|
143
|
+
return self._cancelled
|
|
144
|
+
|
|
145
|
+
def result(self):
|
|
146
|
+
if not self._done:
|
|
147
|
+
raise InvalidStateError("Result is not ready")
|
|
148
|
+
if self._cancelled:
|
|
149
|
+
raise CancelledError()
|
|
150
|
+
if self._exception is not None:
|
|
151
|
+
raise self._exception
|
|
152
|
+
return self._result
|
|
153
|
+
|
|
154
|
+
def exception(self):
|
|
155
|
+
if not self._done:
|
|
156
|
+
raise InvalidStateError("Exception is not set")
|
|
157
|
+
if self._cancelled:
|
|
158
|
+
raise CancelledError()
|
|
159
|
+
return self._exception
|
|
160
|
+
|
|
161
|
+
def add_done_callback(self, callback, *, context=None):
|
|
162
|
+
if self._done:
|
|
163
|
+
self._loop.call_soon(callback, self)
|
|
164
|
+
else:
|
|
165
|
+
self._callbacks.append(callback)
|
|
166
|
+
|
|
167
|
+
def remove_done_callback(self, callback):
|
|
168
|
+
previous = len(self._callbacks)
|
|
169
|
+
self._callbacks = [item for item in self._callbacks if item is not callback]
|
|
170
|
+
return previous - len(self._callbacks)
|
|
171
|
+
|
|
172
|
+
def cancel(self, msg=None):
|
|
173
|
+
if self._done:
|
|
174
|
+
return False
|
|
175
|
+
self._done = True
|
|
176
|
+
self._cancelled = True
|
|
177
|
+
self._loop._run_done_callbacks(self)
|
|
178
|
+
self._loop._wake_waiters(self)
|
|
179
|
+
return True
|
|
180
|
+
|
|
181
|
+
def set_result(self, result):
|
|
182
|
+
if self._done:
|
|
183
|
+
raise InvalidStateError("invalid state")
|
|
184
|
+
self._done = True
|
|
185
|
+
self._result = result
|
|
186
|
+
self._loop._run_done_callbacks(self)
|
|
187
|
+
self._loop._wake_waiters(self)
|
|
188
|
+
|
|
189
|
+
def set_exception(self, exception):
|
|
190
|
+
if self._done:
|
|
191
|
+
raise InvalidStateError("invalid state")
|
|
192
|
+
if not isinstance(exception, BaseException):
|
|
193
|
+
raise TypeError("invalid exception object")
|
|
194
|
+
self._done = True
|
|
195
|
+
self._exception = exception
|
|
196
|
+
self._loop._run_done_callbacks(self)
|
|
197
|
+
self._loop._wake_waiters(self)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class _GatheringFuture(Future):
|
|
201
|
+
def __init__(self, children, *, loop):
|
|
202
|
+
Future.__init__(self, loop=loop)
|
|
203
|
+
self._children = children
|
|
204
|
+
self._cancel_requested = False
|
|
205
|
+
|
|
206
|
+
def cancel(self, msg=None):
|
|
207
|
+
if self._done:
|
|
208
|
+
return False
|
|
209
|
+
cancelled = False
|
|
210
|
+
for child in self._children:
|
|
211
|
+
if child.cancel(msg=msg):
|
|
212
|
+
cancelled = True
|
|
213
|
+
if cancelled:
|
|
214
|
+
self._cancel_requested = True
|
|
215
|
+
return cancelled
|
|
216
|
+
|
|
217
|
+
|
|
90
218
|
class Task:
|
|
91
219
|
def __init__(self, coroutine, loop, name=None):
|
|
92
220
|
if not _is_coroutine(coroutine):
|
|
@@ -145,7 +273,7 @@ class Task:
|
|
|
145
273
|
|
|
146
274
|
def add_done_callback(self, callback, context=None):
|
|
147
275
|
if self._done:
|
|
148
|
-
callback
|
|
276
|
+
self._loop.call_soon(callback, self)
|
|
149
277
|
else:
|
|
150
278
|
self._callbacks.append(callback)
|
|
151
279
|
|
|
@@ -583,6 +711,9 @@ class _Loop:
|
|
|
583
711
|
self._ready.append(task)
|
|
584
712
|
return task
|
|
585
713
|
|
|
714
|
+
def create_future(self):
|
|
715
|
+
return Future(loop=self)
|
|
716
|
+
|
|
586
717
|
def _create_awaited_task(self, coroutine, parent):
|
|
587
718
|
task = self.create_task(coroutine)
|
|
588
719
|
task._logical_task = parent._logical_task
|
|
@@ -591,6 +722,22 @@ class _Loop:
|
|
|
591
722
|
def time(self):
|
|
592
723
|
return _monotonic_ns() / 1000000000
|
|
593
724
|
|
|
725
|
+
def call_soon(self, callback, *args, context=None):
|
|
726
|
+
handle = Handle(callback, args)
|
|
727
|
+
self._ready.append(handle)
|
|
728
|
+
return handle
|
|
729
|
+
|
|
730
|
+
def call_soon_threadsafe(self, callback, *args, context=None):
|
|
731
|
+
return self.call_soon(callback, *args, context=context)
|
|
732
|
+
|
|
733
|
+
def call_at(self, when, callback, *args, context=None):
|
|
734
|
+
handle = TimerHandle(when, callback, args)
|
|
735
|
+
self._timers.append((int(when * 1000000000), handle))
|
|
736
|
+
return handle
|
|
737
|
+
|
|
738
|
+
def call_later(self, delay, callback, *args, context=None):
|
|
739
|
+
return self.call_at(self.time() + delay, callback, *args, context=context)
|
|
740
|
+
|
|
594
741
|
def _schedule(self, task, value):
|
|
595
742
|
if not task._done:
|
|
596
743
|
self._resource_waiters = [
|
|
@@ -608,6 +755,11 @@ class _Loop:
|
|
|
608
755
|
self._ready.append(task)
|
|
609
756
|
|
|
610
757
|
def _cancel(self, task):
|
|
758
|
+
dependency = task._waiting_on
|
|
759
|
+
if isinstance(dependency, (Task, Future)) and dependency.cancel():
|
|
760
|
+
return
|
|
761
|
+
if isinstance(dependency, _TimeoutWait) and dependency.child.cancel():
|
|
762
|
+
return
|
|
611
763
|
if not task._started:
|
|
612
764
|
task._done = True
|
|
613
765
|
task._cancelled = True
|
|
@@ -627,11 +779,15 @@ class _Loop:
|
|
|
627
779
|
now = _monotonic_ns()
|
|
628
780
|
pending = []
|
|
629
781
|
for timer_deadline, timer in self._timers:
|
|
782
|
+
if isinstance(timer, TimerHandle) and timer.cancelled():
|
|
783
|
+
continue
|
|
630
784
|
if timer_deadline <= now:
|
|
631
785
|
if isinstance(timer, _TimeoutWait):
|
|
632
786
|
if timer.parent._waiting_on is timer:
|
|
633
787
|
timer.timed_out = True
|
|
634
788
|
timer.child.cancel()
|
|
789
|
+
elif isinstance(timer, TimerHandle):
|
|
790
|
+
self._ready.append(timer)
|
|
635
791
|
else:
|
|
636
792
|
self._schedule(timer, None)
|
|
637
793
|
else:
|
|
@@ -639,10 +795,15 @@ class _Loop:
|
|
|
639
795
|
self._timers = pending
|
|
640
796
|
|
|
641
797
|
def _next_timer_token(self):
|
|
642
|
-
|
|
798
|
+
active = [
|
|
799
|
+
item
|
|
800
|
+
for item in self._timers
|
|
801
|
+
if not isinstance(item[1], TimerHandle) or not item[1].cancelled()
|
|
802
|
+
]
|
|
803
|
+
if not active:
|
|
643
804
|
return None
|
|
644
|
-
deadline =
|
|
645
|
-
for timer_deadline, timer in
|
|
805
|
+
deadline = active[0][0]
|
|
806
|
+
for timer_deadline, timer in active:
|
|
646
807
|
if timer_deadline < deadline:
|
|
647
808
|
deadline = timer_deadline
|
|
648
809
|
return ("timer", deadline)
|
|
@@ -661,31 +822,38 @@ class _Loop:
|
|
|
661
822
|
for task, token in waiters:
|
|
662
823
|
self._schedule(task, None)
|
|
663
824
|
|
|
664
|
-
def _wake_waiters(self,
|
|
665
|
-
waiters =
|
|
666
|
-
|
|
825
|
+
def _wake_waiters(self, future):
|
|
826
|
+
waiters = future._waiters
|
|
827
|
+
future._waiters = []
|
|
667
828
|
for waiter in waiters:
|
|
668
829
|
if isinstance(waiter, _TimeoutWait):
|
|
669
830
|
waiter.parent._waiting_on = None
|
|
670
831
|
if waiter.timed_out:
|
|
671
832
|
self._schedule_failure(waiter.parent, TimeoutError())
|
|
672
|
-
elif
|
|
673
|
-
self._schedule_failure(waiter.parent,
|
|
833
|
+
elif future._cancelled:
|
|
834
|
+
self._schedule_failure(waiter.parent, CancelledError())
|
|
835
|
+
elif future._exception is not None:
|
|
836
|
+
self._schedule_failure(waiter.parent, future._exception)
|
|
674
837
|
else:
|
|
675
|
-
self._schedule(waiter.parent,
|
|
676
|
-
elif
|
|
677
|
-
|
|
838
|
+
self._schedule(waiter.parent, future._result)
|
|
839
|
+
elif future._cancelled:
|
|
840
|
+
if waiter._waiting_on is future:
|
|
841
|
+
waiter._waiting_on = None
|
|
842
|
+
self._schedule_failure(waiter, CancelledError())
|
|
843
|
+
elif future._exception is not None:
|
|
844
|
+
if waiter._waiting_on is future:
|
|
845
|
+
waiter._waiting_on = None
|
|
846
|
+
self._schedule_failure(waiter, future._exception)
|
|
678
847
|
else:
|
|
679
|
-
|
|
848
|
+
if waiter._waiting_on is future:
|
|
849
|
+
waiter._waiting_on = None
|
|
850
|
+
self._schedule(waiter, future._result)
|
|
680
851
|
|
|
681
|
-
def _run_done_callbacks(self,
|
|
682
|
-
callbacks =
|
|
683
|
-
|
|
852
|
+
def _run_done_callbacks(self, future):
|
|
853
|
+
callbacks = future._callbacks
|
|
854
|
+
future._callbacks = []
|
|
684
855
|
for callback in callbacks:
|
|
685
|
-
|
|
686
|
-
callback(task)
|
|
687
|
-
except Exception:
|
|
688
|
-
pass
|
|
856
|
+
self.call_soon(callback, future)
|
|
689
857
|
|
|
690
858
|
def _finish(self, task, result):
|
|
691
859
|
task._done = True
|
|
@@ -700,18 +868,21 @@ class _Loop:
|
|
|
700
868
|
self._wake_waiters(task)
|
|
701
869
|
self._run_done_callbacks(task)
|
|
702
870
|
|
|
703
|
-
def
|
|
871
|
+
def _block_on_future(self, task, awaited):
|
|
704
872
|
if awaited._done:
|
|
705
|
-
if awaited.
|
|
873
|
+
if awaited._cancelled:
|
|
874
|
+
self._schedule_failure(task, CancelledError())
|
|
875
|
+
elif awaited._exception is not None:
|
|
706
876
|
self._schedule_failure(task, awaited._exception)
|
|
707
877
|
else:
|
|
708
878
|
self._schedule(task, awaited._result)
|
|
709
879
|
else:
|
|
880
|
+
task._waiting_on = awaited
|
|
710
881
|
awaited._waiters.append(task)
|
|
711
882
|
|
|
712
883
|
def _dispatch_yield(self, task, awaited):
|
|
713
|
-
if isinstance(awaited, Task):
|
|
714
|
-
self.
|
|
884
|
+
if isinstance(awaited, (Task, Future)):
|
|
885
|
+
self._block_on_future(task, awaited)
|
|
715
886
|
elif isinstance(awaited, _Sleep):
|
|
716
887
|
self._sleep(task, awaited.delay)
|
|
717
888
|
elif isinstance(awaited, _EventWait):
|
|
@@ -738,7 +909,7 @@ class _Loop:
|
|
|
738
909
|
awaited.condition._waiters.append(task)
|
|
739
910
|
elif isinstance(awaited, _WaitFor):
|
|
740
911
|
if awaited.task._done:
|
|
741
|
-
self.
|
|
912
|
+
self._block_on_future(task, awaited.task)
|
|
742
913
|
else:
|
|
743
914
|
timeout = _TimeoutWait(task, awaited.task)
|
|
744
915
|
task._waiting_on = timeout
|
|
@@ -749,7 +920,7 @@ class _Loop:
|
|
|
749
920
|
elif isinstance(awaited, _ResourceWait):
|
|
750
921
|
self._resource_waiters.append((task, awaited.token))
|
|
751
922
|
elif _is_coroutine(awaited):
|
|
752
|
-
self.
|
|
923
|
+
self._block_on_future(task, self._create_awaited_task(awaited, task))
|
|
753
924
|
else:
|
|
754
925
|
raise TypeError("object cannot be used in 'await' expression")
|
|
755
926
|
|
|
@@ -761,6 +932,9 @@ class _Loop:
|
|
|
761
932
|
if not self._ready:
|
|
762
933
|
self._wait_for_resources()
|
|
763
934
|
task = self._ready.pop(0)
|
|
935
|
+
if isinstance(task, Handle):
|
|
936
|
+
task._run()
|
|
937
|
+
continue
|
|
764
938
|
if task._done:
|
|
765
939
|
continue
|
|
766
940
|
task._started = True
|
|
@@ -783,6 +957,10 @@ def get_running_loop():
|
|
|
783
957
|
return _running_loop
|
|
784
958
|
|
|
785
959
|
|
|
960
|
+
def get_event_loop():
|
|
961
|
+
return get_running_loop()
|
|
962
|
+
|
|
963
|
+
|
|
786
964
|
def create_task(coroutine, name=None, context=None):
|
|
787
965
|
return get_running_loop().create_task(coroutine, name)
|
|
788
966
|
|
|
@@ -791,6 +969,10 @@ def ensure_future(awaitable):
|
|
|
791
969
|
return _ensure_task(awaitable)
|
|
792
970
|
|
|
793
971
|
|
|
972
|
+
def isfuture(value):
|
|
973
|
+
return isinstance(value, (Future, Task))
|
|
974
|
+
|
|
975
|
+
|
|
794
976
|
def current_task(loop=None):
|
|
795
977
|
if loop is None:
|
|
796
978
|
loop = get_running_loop()
|
|
@@ -806,7 +988,7 @@ def all_tasks(loop=None):
|
|
|
806
988
|
|
|
807
989
|
|
|
808
990
|
def _ensure_task(awaitable):
|
|
809
|
-
if isinstance(awaitable, Task):
|
|
991
|
+
if isinstance(awaitable, (Task, Future)):
|
|
810
992
|
return awaitable
|
|
811
993
|
return create_task(awaitable)
|
|
812
994
|
|
|
@@ -816,17 +998,50 @@ async def sleep(delay, result=None):
|
|
|
816
998
|
return result
|
|
817
999
|
|
|
818
1000
|
|
|
819
|
-
|
|
1001
|
+
def gather(*coroutines, return_exceptions=False):
|
|
820
1002
|
tasks = [_ensure_task(coroutine) for coroutine in coroutines]
|
|
821
|
-
|
|
1003
|
+
observed = []
|
|
822
1004
|
for task in tasks:
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
1005
|
+
if task not in observed:
|
|
1006
|
+
observed.append(task)
|
|
1007
|
+
loop = get_running_loop()
|
|
1008
|
+
outer = _GatheringFuture(observed, loop=loop)
|
|
1009
|
+
if not tasks:
|
|
1010
|
+
outer.set_result([])
|
|
1011
|
+
return outer
|
|
1012
|
+
|
|
1013
|
+
results = [None for task in tasks]
|
|
1014
|
+
completed = [False for task in tasks]
|
|
1015
|
+
|
|
1016
|
+
def child_completed(child):
|
|
1017
|
+
if outer.done():
|
|
1018
|
+
return
|
|
1019
|
+
if outer._cancel_requested:
|
|
1020
|
+
if all(task.done() for task in observed):
|
|
1021
|
+
outer.set_exception(CancelledError())
|
|
1022
|
+
return
|
|
1023
|
+
if child.cancelled():
|
|
1024
|
+
if not return_exceptions:
|
|
1025
|
+
outer.set_exception(CancelledError())
|
|
1026
|
+
return
|
|
1027
|
+
result = CancelledError()
|
|
1028
|
+
elif child.exception() is not None:
|
|
826
1029
|
if not return_exceptions:
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
1030
|
+
outer.set_exception(child.exception())
|
|
1031
|
+
return
|
|
1032
|
+
result = child.exception()
|
|
1033
|
+
else:
|
|
1034
|
+
result = child.result()
|
|
1035
|
+
for index in range(len(tasks)):
|
|
1036
|
+
if tasks[index] is child:
|
|
1037
|
+
completed[index] = True
|
|
1038
|
+
results[index] = result
|
|
1039
|
+
if all(completed):
|
|
1040
|
+
outer.set_result(results)
|
|
1041
|
+
|
|
1042
|
+
for task in observed:
|
|
1043
|
+
task.add_done_callback(child_completed)
|
|
1044
|
+
return outer
|
|
830
1045
|
|
|
831
1046
|
|
|
832
1047
|
async def wait_for(awaitable, timeout):
|
|
@@ -923,7 +1138,7 @@ async def wait(awaitables, timeout=None, return_when=ALL_COMPLETED):
|
|
|
923
1138
|
if not tasks:
|
|
924
1139
|
raise ValueError("Set of Tasks/Futures is empty")
|
|
925
1140
|
for task in tasks:
|
|
926
|
-
if not isinstance(task, Task):
|
|
1141
|
+
if not isinstance(task, (Task, Future)):
|
|
927
1142
|
raise TypeError("Passing coroutines is forbidden, use tasks explicitly")
|
|
928
1143
|
changed = Event()
|
|
929
1144
|
|
|
@@ -985,8 +1200,24 @@ def as_completed(awaitables, timeout=None):
|
|
|
985
1200
|
yield next_result()
|
|
986
1201
|
|
|
987
1202
|
|
|
988
|
-
|
|
989
|
-
|
|
1203
|
+
def shield(awaitable):
|
|
1204
|
+
inner = _ensure_task(awaitable)
|
|
1205
|
+
if inner.done():
|
|
1206
|
+
return inner
|
|
1207
|
+
outer = get_running_loop().create_future()
|
|
1208
|
+
|
|
1209
|
+
def inner_completed(completed):
|
|
1210
|
+
if outer.done():
|
|
1211
|
+
return
|
|
1212
|
+
if completed.cancelled():
|
|
1213
|
+
outer.cancel()
|
|
1214
|
+
elif completed.exception() is not None:
|
|
1215
|
+
outer.set_exception(completed.exception())
|
|
1216
|
+
else:
|
|
1217
|
+
outer.set_result(completed.result())
|
|
1218
|
+
|
|
1219
|
+
inner.add_done_callback(inner_completed)
|
|
1220
|
+
return outer
|
|
990
1221
|
|
|
991
1222
|
|
|
992
1223
|
async def create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None,
|
|
@@ -200,6 +200,7 @@ impl Vm<'_> {
|
|
|
200
200
|
name,
|
|
201
201
|
metaclass,
|
|
202
202
|
layout,
|
|
203
|
+
exception_base,
|
|
203
204
|
is_dataclass,
|
|
204
205
|
dataclass_fields,
|
|
205
206
|
enum_members,
|
|
@@ -339,6 +340,16 @@ impl Vm<'_> {
|
|
|
339
340
|
payload,
|
|
340
341
|
attributes: InstanceAttributes::default(),
|
|
341
342
|
})?;
|
|
343
|
+
if exception_base.is_some() {
|
|
344
|
+
let exception_args =
|
|
345
|
+
self.allocate_object(Object::Tuple(arguments.clone()))?;
|
|
346
|
+
self.state.heap.insert_attribute(
|
|
347
|
+
instance.object_id().expect("instances are heap objects"),
|
|
348
|
+
"args".into(),
|
|
349
|
+
exception_args,
|
|
350
|
+
&mut self.interp.resources,
|
|
351
|
+
)?;
|
|
352
|
+
}
|
|
342
353
|
if is_dataclass {
|
|
343
354
|
let mut values = Vec::new();
|
|
344
355
|
for (index, (field, default)) in dataclass_fields.iter().enumerate() {
|
|
@@ -428,7 +439,10 @@ impl Vm<'_> {
|
|
|
428
439
|
unreachable!("immediate initializer cannot suspend")
|
|
429
440
|
}
|
|
430
441
|
}
|
|
442
|
+
} else if exception_base.is_some() && !keyword_arguments.is_empty() {
|
|
443
|
+
return Err(format!("{name}() does not accept keyword arguments"));
|
|
431
444
|
} else if layout == ClassLayout::Object
|
|
445
|
+
&& exception_base.is_none()
|
|
432
446
|
&& (!arguments.is_empty() || !keyword_arguments.is_empty())
|
|
433
447
|
{
|
|
434
448
|
return Err(format!("{name}() takes no arguments"));
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|