wasm-action 0.0.7__tar.gz → 0.0.9__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.
- {wasm_action-0.0.7 → wasm_action-0.0.9}/PKG-INFO +4 -2
- {wasm_action-0.0.7 → wasm_action-0.0.9}/README.md +2 -1
- {wasm_action-0.0.7 → wasm_action-0.0.9}/pyproject.toml +2 -1
- wasm_action-0.0.9/src/wasm_action/cache.py +58 -0
- wasm_action-0.0.9/src/wasm_action/cli.py +156 -0
- wasm_action-0.0.9/src/wasm_action/python.py +108 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/wasm_action/util.py +48 -0
- wasm_action-0.0.9/src/wasm_action/wasm/__init__.py +0 -0
- wasm_action-0.0.9/src/wasm_action/wasm/expression.py +96 -0
- wasm_action-0.0.9/src/wasm_action/wasm/runtime.py +145 -0
- wasm_action-0.0.7/src/wasm_action/cli.py +0 -89
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/__init__.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/api/__init__.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/api/content_api.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/api/fetch_api.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/api/ledger_api.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/api/monitor_api.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/api/package_api.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/api/proof_api.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/api_client.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/api_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/configuration.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/exceptions.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/__init__.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/bundle_failure_error.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/checkpoint.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/checkpoint_verification_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/content_sources_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/envelope_body.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/error.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/fetch_logs404_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/fetch_logs_id_not_found_error.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/fetch_logs_log_length_not_found_error.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/fetch_logs_request.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/fetch_logs_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/fetch_names404_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/fetch_package_names_request.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/fetch_package_names_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/fetch_warning.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/get_content_sources404_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/get_package_record404_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/http_get.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/http_upload.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/http_upload_headers.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/incorrect_proof_error.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/ledger_sources_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/ledger_sources_response_sources_inner.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/missing_content.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/package_not_included_error.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/package_record.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/processing_record.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/prove_consistency404_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/prove_consistency_request.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/prove_consistency_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/prove_inclusion404_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/prove_inclusion422_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/prove_inclusion_request.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/prove_inclusion_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/publish_package_record404_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/publish_package_record409_response.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/publish_package_record_request.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/published_record.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/published_record_envelope.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/rejected_record.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/signature.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/signed_checkpoint.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/sourcing_record.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/timestamped_checkpoint.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/py.typed +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/rest.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/wasm_action/__init__.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/wasm_action/lib.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/wasm_action/registry.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/wasm_action/warg/__init__.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/wasm_action/warg/actions.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/wasm_action/warg/client.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/wasm_action/warg/crypto.py +0 -0
- {wasm_action-0.0.7 → wasm_action-0.0.9}/src/wasm_action/warg/proto.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: wasm-action
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.9
|
|
4
4
|
Summary: Interact with WebAssembly registries.
|
|
5
5
|
Requires-Dist: click>=8.2.1
|
|
6
6
|
Requires-Dist: cryptography>=45.0.6
|
|
@@ -12,6 +12,7 @@ Requires-Dist: requests>=2.32.4
|
|
|
12
12
|
Requires-Dist: semver>=3.0.4
|
|
13
13
|
Requires-Dist: urllib3>=1.25.3
|
|
14
14
|
Requires-Dist: validators>=0.35.0
|
|
15
|
+
Requires-Dist: wasmtime>=40.0.0
|
|
15
16
|
Requires-Python: >=3.10
|
|
16
17
|
Project-URL: Repository, https://github.com/xelato/wasm-action
|
|
17
18
|
Description-Content-Type: text/markdown
|
|
@@ -26,6 +27,7 @@ Description-Content-Type: text/markdown
|
|
|
26
27
|
* Supported artifact types: wasm
|
|
27
28
|
* Supported actions: push, pull
|
|
28
29
|
* Supports Python 3.10+ on Linux, MacOS and Windows
|
|
30
|
+
* Python sandbox using wasm build of cpython 3.14
|
|
29
31
|
|
|
30
32
|
#### Planned
|
|
31
33
|
* OCI registry support (a.k.a. Docker registry)
|
|
@@ -84,7 +86,7 @@ To pull a private package, define your [token](https://wa.dev/account/credential
|
|
|
84
86
|
### Key generation
|
|
85
87
|
New [token](https://wa.dev/account/credentials/new) registration and push to wa.dev require generation and configuration of a private/public key pair which can be facilitated with:
|
|
86
88
|
```
|
|
87
|
-
$
|
|
89
|
+
$ uvx wasm-action key
|
|
88
90
|
{
|
|
89
91
|
"private": "ecdsa-p256:9y5nigLvFp3KZZQtuvN9DchpGIMUB4bwGAtkIoOCla4=",
|
|
90
92
|
"public": "ecdsa-p256:AvspSQWBK65ItTou/uVCi5qC4P+HBCi4R34OIPb3ILRl",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* Supported artifact types: wasm
|
|
9
9
|
* Supported actions: push, pull
|
|
10
10
|
* Supports Python 3.10+ on Linux, MacOS and Windows
|
|
11
|
+
* Python sandbox using wasm build of cpython 3.14
|
|
11
12
|
|
|
12
13
|
#### Planned
|
|
13
14
|
* OCI registry support (a.k.a. Docker registry)
|
|
@@ -66,7 +67,7 @@ To pull a private package, define your [token](https://wa.dev/account/credential
|
|
|
66
67
|
### Key generation
|
|
67
68
|
New [token](https://wa.dev/account/credentials/new) registration and push to wa.dev require generation and configuration of a private/public key pair which can be facilitated with:
|
|
68
69
|
```
|
|
69
|
-
$
|
|
70
|
+
$ uvx wasm-action key
|
|
70
71
|
{
|
|
71
72
|
"private": "ecdsa-p256:9y5nigLvFp3KZZQtuvN9DchpGIMUB4bwGAtkIoOCla4=",
|
|
72
73
|
"public": "ecdsa-p256:AvspSQWBK65ItTou/uVCi5qC4P+HBCi4R34OIPb3ILRl",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "wasm-action"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.9"
|
|
4
4
|
description = "Interact with WebAssembly registries."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -15,6 +15,7 @@ dependencies = [
|
|
|
15
15
|
"semver>=3.0.4",
|
|
16
16
|
"urllib3>=1.25.3",
|
|
17
17
|
"validators>=0.35.0",
|
|
18
|
+
"wasmtime>=40.0.0",
|
|
18
19
|
]
|
|
19
20
|
|
|
20
21
|
[project.urls]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
|
|
2
|
+
import os
|
|
3
|
+
import hashlib
|
|
4
|
+
|
|
5
|
+
CACHE = os.path.join(os.environ['HOME'], '.cache', 'wasm-action')
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def fetch(content_hash: str) -> bytes:
|
|
9
|
+
"""Fetch object from cache"""
|
|
10
|
+
if not os.path.exists(CACHE):
|
|
11
|
+
os.makedirs(CACHE)
|
|
12
|
+
|
|
13
|
+
filename = os.path.join(CACHE, content_hash)
|
|
14
|
+
if not os.path.exists(filename):
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
with open(filename, 'rb') as f:
|
|
18
|
+
content = f.read()
|
|
19
|
+
|
|
20
|
+
computed_hash = hashlib.sha256(content).hexdigest()
|
|
21
|
+
if computed_hash != content_hash:
|
|
22
|
+
raise ValueError('content with hash has been tempered: {}'.format(content_hash))
|
|
23
|
+
return content
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def store(content: bytes):
|
|
27
|
+
"""Store object in cache"""
|
|
28
|
+
if not os.path.exists(CACHE):
|
|
29
|
+
os.makedirs(CACHE)
|
|
30
|
+
|
|
31
|
+
content_hash = hashlib.sha256(content).hexdigest()
|
|
32
|
+
filename = os.path.join(CACHE, content_hash)
|
|
33
|
+
with open(filename, 'wb') as f:
|
|
34
|
+
f.write(content)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def exists(content_hash: str) -> bool:
|
|
38
|
+
"""Check if object exists"""
|
|
39
|
+
if not os.path.exists(CACHE):
|
|
40
|
+
os.makedirs(CACHE)
|
|
41
|
+
|
|
42
|
+
filename = os.path.join(CACHE, content_hash)
|
|
43
|
+
return os.path.exists(filename)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def compute_hash(content: bytes) -> str:
|
|
47
|
+
"""Compute hash without storing the object"""
|
|
48
|
+
return hashlib.sha256(content).hexdigest()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def size(content_hash: str) -> int:
|
|
52
|
+
"""Return size of stored object"""
|
|
53
|
+
if not os.path.exists(CACHE):
|
|
54
|
+
os.makedirs(CACHE)
|
|
55
|
+
filename = os.path.join(CACHE, content_hash)
|
|
56
|
+
if not os.path.exists(filename):
|
|
57
|
+
return 0
|
|
58
|
+
return os.stat(filename).st_size
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import click
|
|
4
|
+
import importlib.metadata
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
from . import lib
|
|
8
|
+
from . import python
|
|
9
|
+
from .warg.crypto import generate_key
|
|
10
|
+
from .wasm import runtime
|
|
11
|
+
from .util import cli_error_handler
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.group()
|
|
15
|
+
def cli():
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@cli.command(help="Print version")
|
|
20
|
+
def version():
|
|
21
|
+
try:
|
|
22
|
+
version = importlib.metadata.version("wasm-action")
|
|
23
|
+
except importlib.metadata.PackageNotFoundError:
|
|
24
|
+
version = "0.0.0"
|
|
25
|
+
print(version)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@cli.command(help="Push to registry")
|
|
29
|
+
@click.option('-r', '--registry', required=True, help="registry domain name")
|
|
30
|
+
@click.option('-p', '--package', required=True, help="package spec")
|
|
31
|
+
@click.option('--path', required=True, help="filename")
|
|
32
|
+
@click.option('--warg-token', required=False, envvar='WARG_TOKEN', help="warg token (or $WARG_TOKEN)")
|
|
33
|
+
@click.option('--warg-private-key', required=False, envvar='WARG_PRIVATE_KEY', help="warg private key (or $WARG_PRIVATE_KEY)")
|
|
34
|
+
@cli_error_handler
|
|
35
|
+
def push(registry, package, path, warg_token, warg_private_key):
|
|
36
|
+
lib.push_file(
|
|
37
|
+
registry=registry,
|
|
38
|
+
package=package,
|
|
39
|
+
path=path,
|
|
40
|
+
warg_token=warg_token,
|
|
41
|
+
warg_private_key=warg_private_key,
|
|
42
|
+
cli=True,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@cli.command(help="Pull from registry")
|
|
47
|
+
@click.option('-r', '--registry', required=True, help="registry domain name")
|
|
48
|
+
@click.option('-p', '--package', required=True, help="package spec")
|
|
49
|
+
@click.option('--path', required=False, help="filename")
|
|
50
|
+
@click.option('--warg-token', required=False, envvar='WARG_TOKEN', help="warg token (or $WARG_TOKEN)")
|
|
51
|
+
@cli_error_handler
|
|
52
|
+
def pull(registry, package, path=None, warg_token=None):
|
|
53
|
+
lib.pull_file(
|
|
54
|
+
registry=registry,
|
|
55
|
+
package=package,
|
|
56
|
+
path=path,
|
|
57
|
+
warg_token=warg_token,
|
|
58
|
+
cli=True,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@cli.command(help="Generate private key or read one from stdin")
|
|
63
|
+
@cli_error_handler
|
|
64
|
+
def key():
|
|
65
|
+
"""Generate key in json format.
|
|
66
|
+
|
|
67
|
+
Either:
|
|
68
|
+
- generate a new key
|
|
69
|
+
- read a private key from standard input
|
|
70
|
+
"""
|
|
71
|
+
if sys.stdin.isatty():
|
|
72
|
+
data = generate_key()
|
|
73
|
+
else:
|
|
74
|
+
# read private key from standard input
|
|
75
|
+
private_key = sys.stdin.read()
|
|
76
|
+
data = generate_key(private_key)
|
|
77
|
+
del data['private']
|
|
78
|
+
print(json.dumps(data, indent=4))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@cli.command('x', help="Run a WebAssembly file")
|
|
82
|
+
@click.argument('filename', required=True)
|
|
83
|
+
@click.argument('func', required=False)
|
|
84
|
+
@click.argument('args', nargs=-1)
|
|
85
|
+
@cli_error_handler
|
|
86
|
+
def run(filename, func, args):
|
|
87
|
+
"""Run a WebAssembly file"""
|
|
88
|
+
|
|
89
|
+
print(runtime
|
|
90
|
+
.module_file(filename)
|
|
91
|
+
.instance()
|
|
92
|
+
.function(func)
|
|
93
|
+
.call(*args)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@cli.command('eval', help="""Expression evaluator
|
|
98
|
+
|
|
99
|
+
Expression(s) specified in EXPRESSION or STDIN will be evaluated against the specified WebAssembly module.
|
|
100
|
+
The input must conform to a subset of Python's syntax that includes literals, tuples and function calls.
|
|
101
|
+
The latter are resolved to a valid function present in the exports of the WebAssembly module.
|
|
102
|
+
Example:
|
|
103
|
+
If calc.wasm exports `add` and `mul`, then the following is a valid expression in such context:
|
|
104
|
+
"mul(2, 3), add(mul(4, 5), 3)"
|
|
105
|
+
""")
|
|
106
|
+
@click.argument('filename', required=True)
|
|
107
|
+
@click.argument('expression', required=False)
|
|
108
|
+
@cli_error_handler
|
|
109
|
+
def evaluate(filename, expression):
|
|
110
|
+
"""Evaluates an expression against a wasm module instance.
|
|
111
|
+
|
|
112
|
+
Any function calls are intercepted and resolved to a valid function
|
|
113
|
+
from the exports of the wasm module.
|
|
114
|
+
|
|
115
|
+
Expression syntax follows a subset of Python syntax.
|
|
116
|
+
|
|
117
|
+
"""
|
|
118
|
+
instance = (runtime
|
|
119
|
+
.module_file(filename)
|
|
120
|
+
.instance()
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
expression = sys.stdin.read() if not sys.stdin.isatty() else expression
|
|
124
|
+
|
|
125
|
+
if expression:
|
|
126
|
+
for result in instance.evaluate(expression):
|
|
127
|
+
print(result)
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
if not sys.stdin.isatty():
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
# repl mode
|
|
134
|
+
import readline
|
|
135
|
+
prompt = "{} >>> ".format(os.path.basename(filename))
|
|
136
|
+
while True:
|
|
137
|
+
expression = input(prompt)
|
|
138
|
+
try:
|
|
139
|
+
for result in instance.evaluate(expression):
|
|
140
|
+
print(result)
|
|
141
|
+
except Exception as e:
|
|
142
|
+
print(e)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@cli.command('python', help="Python in a sandbox", add_help_option=False, context_settings=dict(
|
|
146
|
+
ignore_unknown_options=True,
|
|
147
|
+
))
|
|
148
|
+
@click.argument('args', nargs=-1, type=click.UNPROCESSED)
|
|
149
|
+
@cli_error_handler
|
|
150
|
+
def run_python(args):
|
|
151
|
+
"""Run a WASI-compiled wasm build of cpython"""
|
|
152
|
+
python.run_python(args)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
if __name__ == "__main__":
|
|
156
|
+
cli()
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
|
|
2
|
+
"""
|
|
3
|
+
Python in a sandbox using WASM/WASI.
|
|
4
|
+
|
|
5
|
+
uvx --python 3.14 wasm-action python
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
import tempfile
|
|
11
|
+
import shutil
|
|
12
|
+
|
|
13
|
+
from . import cache
|
|
14
|
+
from . import lib
|
|
15
|
+
from .wasm import runtime
|
|
16
|
+
|
|
17
|
+
PYTHON = {
|
|
18
|
+
|
|
19
|
+
'3.14': {
|
|
20
|
+
'registry': 'wa.dev',
|
|
21
|
+
'package': 'xelato:python314',
|
|
22
|
+
'version': '26.2.6',
|
|
23
|
+
'sha256': '6a9e23d3db2ea0883fb74bfe9540bcb27bd167be1dab39546a5376112f4beea0',
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def run_python(args):
|
|
30
|
+
v = sys.version_info
|
|
31
|
+
version = "{}.{}".format(v.major, v.minor)
|
|
32
|
+
python = PYTHON.get(version) or PYTHON['3.14']
|
|
33
|
+
|
|
34
|
+
if cache.exists(python['sha256']):
|
|
35
|
+
print("Found object in cache")
|
|
36
|
+
content = cache.fetch(python['sha256'])
|
|
37
|
+
else:
|
|
38
|
+
print("Downloading python build")
|
|
39
|
+
download = lib.pull(
|
|
40
|
+
registry=python['registry'],
|
|
41
|
+
package="{}@{}".format(python['package'], python['version'])
|
|
42
|
+
)
|
|
43
|
+
if download.digest != "sha256:{}".format(python['sha256']):
|
|
44
|
+
raise ValueError('unexpected digest while downloading build')
|
|
45
|
+
|
|
46
|
+
cache.store(download.content)
|
|
47
|
+
print("Stored object in local cache")
|
|
48
|
+
content = download.content
|
|
49
|
+
|
|
50
|
+
# Lib folder
|
|
51
|
+
# Reusing the host Python installation
|
|
52
|
+
python_lib = os.path.dirname(os.__file__)
|
|
53
|
+
print("Using python lib {}".format(python_lib))
|
|
54
|
+
|
|
55
|
+
argv = ['python']
|
|
56
|
+
argv.extend(args)
|
|
57
|
+
|
|
58
|
+
tmp = tempfile.mkdtemp('py')
|
|
59
|
+
|
|
60
|
+
instance = (runtime
|
|
61
|
+
.module(content)
|
|
62
|
+
.wasi()
|
|
63
|
+
# pass all cli arguments to the wasm "process"
|
|
64
|
+
.argv(argv)
|
|
65
|
+
|
|
66
|
+
# configure python lib
|
|
67
|
+
.env('PYTHONPATH', '/lib:/build')
|
|
68
|
+
.mount(python_lib, '/lib', readonly=True)
|
|
69
|
+
|
|
70
|
+
# todo: ModuleNotFoundError: No module named '_sysconfigdata__wasi_wasm32-wasi'
|
|
71
|
+
#.mount('{}/github/python/cpython/builddir/wasi/build/lib.wasi-wasm32-3.14'.format(os.environ['HOME']), '/build')
|
|
72
|
+
|
|
73
|
+
# provide a /tmp folder
|
|
74
|
+
.mount(tmp, '/tmp', readonly=False)
|
|
75
|
+
|
|
76
|
+
# Get access to CWD for running user code.
|
|
77
|
+
# note: it may be preferable to set this to a subdir of /
|
|
78
|
+
.mount(os.getcwd(), "/", readonly=True)
|
|
79
|
+
|
|
80
|
+
.instance()
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# todo: exit code?
|
|
84
|
+
try:
|
|
85
|
+
instance.function('_start')()
|
|
86
|
+
finally:
|
|
87
|
+
# clean-up tmp dir
|
|
88
|
+
shutil.rmtree(tmp)
|
|
89
|
+
|
|
90
|
+
"""
|
|
91
|
+
https://github.com/python/cpython/blob/main/Modules/getpath.py
|
|
92
|
+
Could not find platform independent libraries <prefix>
|
|
93
|
+
Could not find platform dependent libraries <exec_prefix>
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
# 3.14
|
|
97
|
+
"""
|
|
98
|
+
Installations of Python now contain a new file, :file:`build-details.json`.
|
|
99
|
+
This is a static JSON document containing build details for CPython,
|
|
100
|
+
to allow for introspection without needing to run code.
|
|
101
|
+
This is helpful for use-cases such as Python launchers, cross-compilation,
|
|
102
|
+
and so on.
|
|
103
|
+
|
|
104
|
+
:file:`build-details.json` must be installed in the platform-independent
|
|
105
|
+
standard library directory. This corresponds to the :ref:`'stdlib'
|
|
106
|
+
<installation_paths>` :mod:`sysconfig` installation path,
|
|
107
|
+
which can be found by running ``sysconfig.get_path('stdlib')``.
|
|
108
|
+
"""
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import os
|
|
3
3
|
import re
|
|
4
4
|
import sys
|
|
5
|
+
import datetime
|
|
6
|
+
import functools
|
|
5
7
|
import requests
|
|
6
8
|
import semver
|
|
7
9
|
|
|
@@ -73,6 +75,52 @@ def parse_package(package):
|
|
|
73
75
|
if not re.match(r"[\w-]+", name):
|
|
74
76
|
raise ValueError("invalid package name")
|
|
75
77
|
if version:
|
|
78
|
+
# evaluate any calver specifiers
|
|
79
|
+
version = CalVer(version).version()
|
|
76
80
|
# throws on failed validation
|
|
77
81
|
semver.Version.parse(version)
|
|
78
82
|
return namespace, name, version
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class CalVer:
|
|
86
|
+
"""Calendar Versioning according to https://calver.org (zero-padded formats excluded)"""
|
|
87
|
+
|
|
88
|
+
SPEC = {
|
|
89
|
+
'YYYY': lambda d: str(d.year),
|
|
90
|
+
'YY': lambda d: str(d.year % 100),
|
|
91
|
+
'MM': lambda d: str(d.month),
|
|
92
|
+
'WW': lambda d: str(d.isocalendar().week),
|
|
93
|
+
'DD': lambda d: str(d.day),
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
def __init__(self, pattern):
|
|
97
|
+
self.pattern = pattern
|
|
98
|
+
|
|
99
|
+
def now(self) -> datetime.datetime:
|
|
100
|
+
if not hasattr(datetime, 'UTC'):
|
|
101
|
+
# 3.10
|
|
102
|
+
return datetime.datetime.utcnow()
|
|
103
|
+
return datetime.datetime.now(datetime.UTC)
|
|
104
|
+
|
|
105
|
+
def version(self, at: datetime.datetime=None):
|
|
106
|
+
when = at or self.now()
|
|
107
|
+
return ".".join([
|
|
108
|
+
self.SPEC[part.upper()](when)
|
|
109
|
+
if part.upper() in self.SPEC else part
|
|
110
|
+
for part in self.pattern.split('.')
|
|
111
|
+
])
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class cli_error_handler(object):
|
|
115
|
+
"""Decorator for CLI error handling"""
|
|
116
|
+
|
|
117
|
+
def __init__(self, func):
|
|
118
|
+
self.func = func
|
|
119
|
+
functools.update_wrapper(self, func)
|
|
120
|
+
|
|
121
|
+
def __call__(self, *args, **kwargs):
|
|
122
|
+
try:
|
|
123
|
+
return self.func(*args, **kwargs)
|
|
124
|
+
except Exception as e:
|
|
125
|
+
# print error and return 1
|
|
126
|
+
sys.exit(e)
|
|
File without changes
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Expression evaluator.
|
|
3
|
+
|
|
4
|
+
Expressions are evaluated against a WebAssembly module instance.
|
|
5
|
+
Expressions allow to combine zero or more function invocations into one go.
|
|
6
|
+
An expression may consist of the following constituents:
|
|
7
|
+
* Literals
|
|
8
|
+
Simple types that can be represented in WA types.
|
|
9
|
+
1, 0x23, true, false, 3.14
|
|
10
|
+
* Function invocations
|
|
11
|
+
Refer to functions that must be present in the exports section (what about allowing to call imports?).
|
|
12
|
+
sum(2, 3)
|
|
13
|
+
* Tuples for structure and multiple instructions.
|
|
14
|
+
Tuples - allow multiple invocations in one.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
Example:
|
|
18
|
+
Suppose the file calculator.wasm provides the following exports:
|
|
19
|
+
- sum, mul
|
|
20
|
+
Then the following expressions can be constructed:
|
|
21
|
+
sum(2, 3)
|
|
22
|
+
sum(2, mul(3, 5))
|
|
23
|
+
sum(1, sum(2, sum(3, sum(4, 5))))
|
|
24
|
+
(1, sum(2, 3)) -> (1, 5)
|
|
25
|
+
|
|
26
|
+
Implementation takes a shortcut by using Python's ast module.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
import ast
|
|
30
|
+
|
|
31
|
+
ALLOWED_SYNTAX = {
|
|
32
|
+
ast.Module,
|
|
33
|
+
ast.Expr,
|
|
34
|
+
ast.Constant,
|
|
35
|
+
ast.Tuple,
|
|
36
|
+
ast.Call,
|
|
37
|
+
ast.Name,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def parse(value: str) -> ast.AST:
|
|
42
|
+
"""Parse an expression into an ast syntax tree."""
|
|
43
|
+
node = ast.parse(value)
|
|
44
|
+
for x in ast.walk(node):
|
|
45
|
+
if isinstance(x, ast.Load):
|
|
46
|
+
# ignored
|
|
47
|
+
continue
|
|
48
|
+
if x.__class__ not in ALLOWED_SYNTAX:
|
|
49
|
+
raise SyntaxError("{} not allowed in expression".format(x.__class__.__name__))
|
|
50
|
+
return node
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def evaluate(expression, obj):
|
|
54
|
+
node = parse(expression)
|
|
55
|
+
return Evaluator(obj).evaluate(node)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class Evaluator:
|
|
59
|
+
|
|
60
|
+
def __init__(self, obj):
|
|
61
|
+
self.obj= obj
|
|
62
|
+
|
|
63
|
+
def evaluate(self, node: ast.AST) -> object:
|
|
64
|
+
if isinstance(node, ast.Module):
|
|
65
|
+
for sub in node.body:
|
|
66
|
+
yield from self.evaluate(sub)
|
|
67
|
+
|
|
68
|
+
elif isinstance(node, ast.Expr):
|
|
69
|
+
yield self.compute(node)
|
|
70
|
+
|
|
71
|
+
else:
|
|
72
|
+
raise Exception("value not allowed: {}".format(node))
|
|
73
|
+
|
|
74
|
+
def compute(self, node):
|
|
75
|
+
"""Evaluate a single expression"""
|
|
76
|
+
if isinstance(node, ast.Expr):
|
|
77
|
+
return self.compute(node.value)
|
|
78
|
+
|
|
79
|
+
elif isinstance(node, ast.Tuple):
|
|
80
|
+
return tuple(self.compute(x) for x in node.elts)
|
|
81
|
+
|
|
82
|
+
elif isinstance(node, ast.Constant):
|
|
83
|
+
return node.value
|
|
84
|
+
|
|
85
|
+
elif isinstance(node, ast.Call):
|
|
86
|
+
assert isinstance(node.func, ast.Name)
|
|
87
|
+
name = node.func.id
|
|
88
|
+
func = getattr(self.obj, name)
|
|
89
|
+
args = [self.compute(x) for x in node.args]
|
|
90
|
+
return func(*args)
|
|
91
|
+
|
|
92
|
+
elif isinstance(node, ast.Name):
|
|
93
|
+
return getattr(self.obj, node.id)
|
|
94
|
+
|
|
95
|
+
else:
|
|
96
|
+
raise Exception("value not allowed: {}".format(node))
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
|
|
2
|
+
import os
|
|
3
|
+
import wasmtime
|
|
4
|
+
|
|
5
|
+
from . import expression
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def module_file(filename):
|
|
9
|
+
if not os.path.exists(filename) or not os.path.isfile(filename):
|
|
10
|
+
raise Exception('file not found: {}'.format(filename))
|
|
11
|
+
|
|
12
|
+
with open(filename, 'rb') as f:
|
|
13
|
+
module_bytes = f.read()
|
|
14
|
+
return module(module_bytes)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def module(module_bytes):
|
|
18
|
+
return Module(module_bytes)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Module:
|
|
22
|
+
|
|
23
|
+
def __init__(self, module_bytes):
|
|
24
|
+
self._store = wasmtime.Store()
|
|
25
|
+
self._module = wasmtime.Module(self._store.engine, module_bytes)
|
|
26
|
+
|
|
27
|
+
def wasi(self):
|
|
28
|
+
return WASI(store=self._store, module=self._module)
|
|
29
|
+
|
|
30
|
+
def instance(self):
|
|
31
|
+
return Instance(store=self._store, module=self._module)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Instance:
|
|
35
|
+
|
|
36
|
+
def __init__(self, store, module, instance=None):
|
|
37
|
+
self._store = store
|
|
38
|
+
self._module = module
|
|
39
|
+
if instance:
|
|
40
|
+
assert isinstance(instance, wasmtime.Instance)
|
|
41
|
+
self._instance = instance
|
|
42
|
+
self._imports = []
|
|
43
|
+
|
|
44
|
+
def __getattr__(self, name):
|
|
45
|
+
"""Ususally called by the evaluator to resolve function names."""
|
|
46
|
+
return self.function(name)
|
|
47
|
+
|
|
48
|
+
def function(self, name):
|
|
49
|
+
if not self._instance:
|
|
50
|
+
self._instance = wasmtime.Instance(self._store, self._module, self._imports)
|
|
51
|
+
exports = self._instance.exports(self._store)
|
|
52
|
+
if name not in exports.keys():
|
|
53
|
+
print('defined functions:', list(exports.keys()))
|
|
54
|
+
assert False, "function not found: {}".format(name)
|
|
55
|
+
return Function(store=self._store, func=exports[name], name=name)
|
|
56
|
+
|
|
57
|
+
def evaluate(self, text):
|
|
58
|
+
"""Evaluate an expression against functions exported in the instance."""
|
|
59
|
+
return expression.evaluate(text or '', obj=self)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class WASI:
|
|
63
|
+
|
|
64
|
+
def __init__(self, store, module):
|
|
65
|
+
self._store = store
|
|
66
|
+
self._module = module
|
|
67
|
+
|
|
68
|
+
self.linker = wasmtime.Linker(self._store.engine)
|
|
69
|
+
self.linker.define_wasi()
|
|
70
|
+
|
|
71
|
+
self._wasi = wasmtime.WasiConfig()
|
|
72
|
+
self._wasi.inherit_stdin()
|
|
73
|
+
self._wasi.inherit_stdout()
|
|
74
|
+
self._wasi.inherit_stderr()
|
|
75
|
+
|
|
76
|
+
self._environ = {}
|
|
77
|
+
|
|
78
|
+
def mount(self, host_path, guest_path, readonly=True):
|
|
79
|
+
"""Bind mount `host_path` as `guest_path` in the WASM instance."""
|
|
80
|
+
self._wasi.preopen_dir(
|
|
81
|
+
host_path,
|
|
82
|
+
guest_path,
|
|
83
|
+
dir_perms=wasmtime.DirPerms.READ_ONLY if readonly else wasmtime.DirPerms.READ_WRITE,
|
|
84
|
+
file_perms=wasmtime.FilePerms.READ_ONLY if readonly else wasmtime.FilePerms.READ_WRITE,
|
|
85
|
+
)
|
|
86
|
+
return self
|
|
87
|
+
|
|
88
|
+
def argv(self, argv):
|
|
89
|
+
self._wasi.argv = argv
|
|
90
|
+
return self
|
|
91
|
+
|
|
92
|
+
def env(self, key, value):
|
|
93
|
+
"""Configure an environment variable in the WASM instance"""
|
|
94
|
+
self._environ[key] = value
|
|
95
|
+
return self
|
|
96
|
+
|
|
97
|
+
def instance(self):
|
|
98
|
+
self._wasi.env = [
|
|
99
|
+
(k, v) for (k, v) in self._environ.items()
|
|
100
|
+
]
|
|
101
|
+
self._store.set_wasi(self._wasi)
|
|
102
|
+
instance = self.linker.instantiate(self._store, self._module)
|
|
103
|
+
return Instance(store=self._store, module=self._module, instance=instance)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class Function:
|
|
107
|
+
|
|
108
|
+
_types = {
|
|
109
|
+
"i32": int,
|
|
110
|
+
"i64": int,
|
|
111
|
+
"f32": float,
|
|
112
|
+
"f64": float,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
def __init__(self, store, func, name):
|
|
116
|
+
self._store = store
|
|
117
|
+
self._func = func
|
|
118
|
+
self._func_type = self._func.type(self._store)
|
|
119
|
+
self.name = name
|
|
120
|
+
|
|
121
|
+
def call(self, *args):
|
|
122
|
+
return self(*args)
|
|
123
|
+
|
|
124
|
+
def __call__(self, *args):
|
|
125
|
+
# convert to expected types before function call
|
|
126
|
+
typed_args = []
|
|
127
|
+
for param, arg in zip(self._func_type.params, args):
|
|
128
|
+
type = self._types.get(str(param))
|
|
129
|
+
arg = type(arg) if type else arg
|
|
130
|
+
typed_args.append(arg)
|
|
131
|
+
try:
|
|
132
|
+
result = self._func(self._store, *typed_args)
|
|
133
|
+
except Exception as e:
|
|
134
|
+
message = "Error calling {}({}): {}".format(
|
|
135
|
+
self.name,
|
|
136
|
+
", ".join([str(x) for x in typed_args]),
|
|
137
|
+
str(e),
|
|
138
|
+
)
|
|
139
|
+
raise Exception(message)
|
|
140
|
+
return result
|
|
141
|
+
|
|
142
|
+
def __str__(self):
|
|
143
|
+
return "{}({})".format(self.name, ", ".join([
|
|
144
|
+
str(p) for p in self._func_type.params
|
|
145
|
+
]))
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
import click
|
|
3
|
-
import importlib.metadata
|
|
4
|
-
import json
|
|
5
|
-
|
|
6
|
-
from . import lib
|
|
7
|
-
from .warg.crypto import generate_key
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@click.group()
|
|
11
|
-
def cli():
|
|
12
|
-
pass
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@cli.command(help="Print version")
|
|
16
|
-
def version():
|
|
17
|
-
try:
|
|
18
|
-
version = importlib.metadata.version("wasm-action")
|
|
19
|
-
except importlib.metadata.PackageNotFoundError:
|
|
20
|
-
version = "0.0.0"
|
|
21
|
-
print(version)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@cli.command(help="Push to registry")
|
|
25
|
-
@click.option('--registry', required=True, help="registry domain name")
|
|
26
|
-
@click.option('--package', required=True, help="package spec")
|
|
27
|
-
@click.option('--path', required=True, help="filename")
|
|
28
|
-
@click.option('--warg-token', required=False, envvar='WARG_TOKEN', help="warg token (or $WARG_TOKEN)")
|
|
29
|
-
@click.option('--warg-private-key', required=False, envvar='WARG_PRIVATE_KEY', help="warg private key (or $WARG_PRIVATE_KEY)")
|
|
30
|
-
def push(registry, package, path, warg_token, warg_private_key):
|
|
31
|
-
|
|
32
|
-
try:
|
|
33
|
-
|
|
34
|
-
lib.push_file(
|
|
35
|
-
registry=registry,
|
|
36
|
-
package=package,
|
|
37
|
-
path=path,
|
|
38
|
-
warg_token=warg_token,
|
|
39
|
-
warg_private_key=warg_private_key,
|
|
40
|
-
cli=True,
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
except Exception as e:
|
|
44
|
-
print(e)
|
|
45
|
-
sys.exit(1)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@cli.command(help="Pull from registry")
|
|
49
|
-
@click.option('--registry', required=True, help="registry domain name")
|
|
50
|
-
@click.option('--package', required=True, help="package spec")
|
|
51
|
-
@click.option('--path', required=False, help="filename")
|
|
52
|
-
@click.option('--warg-token', required=False, envvar='WARG_TOKEN', help="warg token (or $WARG_TOKEN)")
|
|
53
|
-
def pull(registry, package, path=None, warg_token=None):
|
|
54
|
-
|
|
55
|
-
try:
|
|
56
|
-
|
|
57
|
-
lib.pull_file(
|
|
58
|
-
registry=registry,
|
|
59
|
-
package=package,
|
|
60
|
-
path=path,
|
|
61
|
-
warg_token=warg_token,
|
|
62
|
-
cli=True,
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
except Exception as e:
|
|
66
|
-
print(e)
|
|
67
|
-
sys.exit(1)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
@cli.command(help="Generate private key or read one from stdin")
|
|
71
|
-
def key():
|
|
72
|
-
"""Generate key in json format.
|
|
73
|
-
|
|
74
|
-
Either:
|
|
75
|
-
- generate a new key
|
|
76
|
-
- read a private key from standard input
|
|
77
|
-
"""
|
|
78
|
-
if sys.stdin.isatty():
|
|
79
|
-
data = generate_key()
|
|
80
|
-
else:
|
|
81
|
-
# read private key from standard input
|
|
82
|
-
private_key = sys.stdin.read()
|
|
83
|
-
data = generate_key(private_key)
|
|
84
|
-
del data['private']
|
|
85
|
-
print(json.dumps(data, indent=4))
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if __name__ == "__main__":
|
|
89
|
-
cli()
|
|
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
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/checkpoint_verification_response.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/fetch_logs_id_not_found_error.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/fetch_package_names_request.py
RENAMED
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/fetch_package_names_response.py
RENAMED
|
File without changes
|
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/get_content_sources404_response.py
RENAMED
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/get_package_record404_response.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/package_not_included_error.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/prove_consistency404_response.py
RENAMED
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/prove_consistency_request.py
RENAMED
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/prove_consistency_response.py
RENAMED
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/prove_inclusion404_response.py
RENAMED
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/prove_inclusion422_response.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/publish_package_record_request.py
RENAMED
|
File without changes
|
|
File without changes
|
{wasm_action-0.0.7 → wasm_action-0.0.9}/src/warg_openapi/models/published_record_envelope.py
RENAMED
|
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
|