dryv-compiler 0.0.1__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.
- dryv_compiler-0.0.1/.gitignore +28 -0
- dryv_compiler-0.0.1/PKG-INFO +120 -0
- dryv_compiler-0.0.1/README.md +110 -0
- dryv_compiler-0.0.1/pyproject.toml +69 -0
- dryv_compiler-0.0.1/src/dryv_compiler/__init__.py +21 -0
- dryv_compiler-0.0.1/src/dryv_compiler/__main__.py +3 -0
- dryv_compiler-0.0.1/src/dryv_compiler/cli.py +159 -0
- dryv_compiler-0.0.1/src/dryv_compiler/compatibility.py +64 -0
- dryv_compiler-0.0.1/src/dryv_compiler/execution/__init__.py +23 -0
- dryv_compiler-0.0.1/src/dryv_compiler/execution/bootstrap.py +106 -0
- dryv_compiler-0.0.1/src/dryv_compiler/execution/entrypoint.py +63 -0
- dryv_compiler-0.0.1/src/dryv_compiler/execution/environment.py +123 -0
- dryv_compiler-0.0.1/src/dryv_compiler/execution/project.py +245 -0
- dryv_compiler-0.0.1/src/dryv_compiler/mapping/__init__.py +4 -0
- dryv_compiler-0.0.1/src/dryv_compiler/mapping/compile.py +90 -0
- dryv_compiler-0.0.1/src/dryv_compiler/mapping/encode.py +277 -0
- dryv_compiler-0.0.1/src/dryv_compiler/mapping/index.py +174 -0
- dryv_compiler-0.0.1/src/dryv_compiler/protocol/__init__.py +42 -0
- dryv_compiler-0.0.1/src/dryv_compiler/protocol/contracts.py +180 -0
- dryv_compiler-0.0.1/src/dryv_compiler/protocol/encoding.py +127 -0
- dryv_compiler-0.0.1/src/dryv_compiler/protocol/parsing.py +81 -0
- dryv_compiler-0.0.1/src/dryv_compiler/protocol/records.py +102 -0
- dryv_compiler-0.0.1/src/dryv_compiler/protocol/session.py +237 -0
- dryv_compiler-0.0.1/src/dryv_compiler/version.py +18 -0
- dryv_compiler-0.0.1/tests/fixtures/faidibiz_app.py +511 -0
- dryv_compiler-0.0.1/tests/test_compatibility.py +27 -0
- dryv_compiler-0.0.1/tests/test_compiler.py +283 -0
- dryv_compiler-0.0.1/tests/test_execution.py +102 -0
- dryv_compiler-0.0.1/tests/test_protocol.py +151 -0
- dryv_compiler-0.0.1/uv.lock +623 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.mypy_cache/
|
|
7
|
+
.ruff_cache/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
build/
|
|
11
|
+
dist/
|
|
12
|
+
generated/
|
|
13
|
+
# Node / editors
|
|
14
|
+
node_modules/
|
|
15
|
+
.vscode-test/
|
|
16
|
+
.idea
|
|
17
|
+
|
|
18
|
+
# Environment
|
|
19
|
+
.env
|
|
20
|
+
.env.*
|
|
21
|
+
!.env.example
|
|
22
|
+
|
|
23
|
+
# OS
|
|
24
|
+
.DS_Store
|
|
25
|
+
Thumbs.db
|
|
26
|
+
|
|
27
|
+
# Dryv local cache and materialized resources
|
|
28
|
+
.dryv/
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: dryv-compiler
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Runnable Python authoring compiler/provider for Dryv
|
|
5
|
+
License: Apache-2.0
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Requires-Dist: dryv-author<0.1,>=0.0.1
|
|
8
|
+
Requires-Dist: packaging<26,>=24
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# dryv-compiler
|
|
12
|
+
|
|
13
|
+
`dryv-compiler` is the Python Author compiler/provider for Dryv.
|
|
14
|
+
|
|
15
|
+
It captures the typed `AuthorState` snapshot from the project's `dryv.app(...)` (in the project's own Python, via `execution/bootstrap.py`), resolves author handles to canonical JSON Pointers, and lowers the states into `dryv.ir/v1alpha1`. The engine's contract models and `validate_runtime_ir` are the final authority; the compiler never accepts IR the engine rejects.
|
|
16
|
+
|
|
17
|
+
## Commands
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
dryv-py doctor ./dryv.py
|
|
21
|
+
dryv-py compile ./dryv.py
|
|
22
|
+
dryv-py stdio
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`stdio` uses the canonical Dryv Authoring Protocol.
|
|
26
|
+
|
|
27
|
+
Request example:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{"type":"compile-request","session_id":"build-1","entrypoint":"./dryv.py","protocol_versions":["dryv.authoring/v1alpha1"],"runtime_ir_versions":["dryv.ir/v1alpha1"],"batch_size":64}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Provider messages use canonical types such as:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
provider-hello
|
|
37
|
+
begin
|
|
38
|
+
batch
|
|
39
|
+
diagnostic
|
|
40
|
+
end
|
|
41
|
+
error
|
|
42
|
+
cancelled
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## How lowering works
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
dryv.app(...).snapshot() typed AuthorState (dryv_author.state)
|
|
49
|
+
↓ mapping/index.py identities → canonical names and pointers
|
|
50
|
+
↓ mapping/encode.py states → canonical JSON; query "*" expansion;
|
|
51
|
+
projection selections → canonical projection fields
|
|
52
|
+
↓ mapping/compile.py DryvIR.model_validate + validate_runtime_ir
|
|
53
|
+
↓ protocol/records.py one record per registry entry, with author origins
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Author states mirror canonical shapes, so lowering is structural. Registry names are group-qualified (`group.Name`). The app itself is emitted as the application named by its key.
|
|
57
|
+
|
|
58
|
+
Parity: `tests/test_compiler.py` compiles `tests/fixtures/faidibiz_app.py` (a port of the TypeScript faidibiz example) and, when `bun` is available, asserts the same semantic digest as the TypeScript compiler.
|
|
59
|
+
|
|
60
|
+
## Canonical naming
|
|
61
|
+
|
|
62
|
+
The compiler must normalize Dryv-owned wire vocabulary regardless of Python Author implementation details:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
Dryv-owned object keys -> lower_snake_case
|
|
66
|
+
Dryv-owned fixed values -> lower-kebab-case
|
|
67
|
+
Authored identifiers -> preserve exactly
|
|
68
|
+
Reserved/external tokens -> preserve governing spelling
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Canonical examples include:
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
session_id
|
|
75
|
+
runtime_ir_version
|
|
76
|
+
property-primitive
|
|
77
|
+
property-generic
|
|
78
|
+
provider-hello
|
|
79
|
+
$ref
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The compiler must never apply a blind recursive case converter because authored names and standards-owned values are opaque.
|
|
83
|
+
|
|
84
|
+
See `.docs/reference/ir/naming.md` and `.docs/reference/ir/properties.md`.
|
|
85
|
+
|
|
86
|
+
## Responsibility boundary
|
|
87
|
+
|
|
88
|
+
The compiler may:
|
|
89
|
+
|
|
90
|
+
- validate Author/compiler compatibility;
|
|
91
|
+
- inspect and execute the Python authoring environment;
|
|
92
|
+
- validate Python Author state;
|
|
93
|
+
- resolve symbolic relationships;
|
|
94
|
+
- classify implementation-specific declarations into canonical concepts;
|
|
95
|
+
- normalize canonical key/value spelling;
|
|
96
|
+
- compile to Runtime-owned IR contracts;
|
|
97
|
+
- stream deterministic Authoring Protocol records;
|
|
98
|
+
- preserve source/provenance diagnostics.
|
|
99
|
+
|
|
100
|
+
It must not:
|
|
101
|
+
|
|
102
|
+
- create a competing semantic model;
|
|
103
|
+
- generate application source code;
|
|
104
|
+
- select template packs;
|
|
105
|
+
- choose output paths;
|
|
106
|
+
- write generated project files;
|
|
107
|
+
- own persisted Runtime serialization.
|
|
108
|
+
|
|
109
|
+
Equivalent Python and TypeScript authored meaning must converge on equivalent canonical Runtime IR.
|
|
110
|
+
|
|
111
|
+
## Development
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
uv sync
|
|
115
|
+
uv run ruff format .
|
|
116
|
+
uv run ruff check --fix .
|
|
117
|
+
uv run mypy
|
|
118
|
+
uv run pytest
|
|
119
|
+
uv build
|
|
120
|
+
```
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# dryv-compiler
|
|
2
|
+
|
|
3
|
+
`dryv-compiler` is the Python Author compiler/provider for Dryv.
|
|
4
|
+
|
|
5
|
+
It captures the typed `AuthorState` snapshot from the project's `dryv.app(...)` (in the project's own Python, via `execution/bootstrap.py`), resolves author handles to canonical JSON Pointers, and lowers the states into `dryv.ir/v1alpha1`. The engine's contract models and `validate_runtime_ir` are the final authority; the compiler never accepts IR the engine rejects.
|
|
6
|
+
|
|
7
|
+
## Commands
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
dryv-py doctor ./dryv.py
|
|
11
|
+
dryv-py compile ./dryv.py
|
|
12
|
+
dryv-py stdio
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`stdio` uses the canonical Dryv Authoring Protocol.
|
|
16
|
+
|
|
17
|
+
Request example:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{"type":"compile-request","session_id":"build-1","entrypoint":"./dryv.py","protocol_versions":["dryv.authoring/v1alpha1"],"runtime_ir_versions":["dryv.ir/v1alpha1"],"batch_size":64}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Provider messages use canonical types such as:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
provider-hello
|
|
27
|
+
begin
|
|
28
|
+
batch
|
|
29
|
+
diagnostic
|
|
30
|
+
end
|
|
31
|
+
error
|
|
32
|
+
cancelled
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## How lowering works
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
dryv.app(...).snapshot() typed AuthorState (dryv_author.state)
|
|
39
|
+
↓ mapping/index.py identities → canonical names and pointers
|
|
40
|
+
↓ mapping/encode.py states → canonical JSON; query "*" expansion;
|
|
41
|
+
projection selections → canonical projection fields
|
|
42
|
+
↓ mapping/compile.py DryvIR.model_validate + validate_runtime_ir
|
|
43
|
+
↓ protocol/records.py one record per registry entry, with author origins
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Author states mirror canonical shapes, so lowering is structural. Registry names are group-qualified (`group.Name`). The app itself is emitted as the application named by its key.
|
|
47
|
+
|
|
48
|
+
Parity: `tests/test_compiler.py` compiles `tests/fixtures/faidibiz_app.py` (a port of the TypeScript faidibiz example) and, when `bun` is available, asserts the same semantic digest as the TypeScript compiler.
|
|
49
|
+
|
|
50
|
+
## Canonical naming
|
|
51
|
+
|
|
52
|
+
The compiler must normalize Dryv-owned wire vocabulary regardless of Python Author implementation details:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
Dryv-owned object keys -> lower_snake_case
|
|
56
|
+
Dryv-owned fixed values -> lower-kebab-case
|
|
57
|
+
Authored identifiers -> preserve exactly
|
|
58
|
+
Reserved/external tokens -> preserve governing spelling
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Canonical examples include:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
session_id
|
|
65
|
+
runtime_ir_version
|
|
66
|
+
property-primitive
|
|
67
|
+
property-generic
|
|
68
|
+
provider-hello
|
|
69
|
+
$ref
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The compiler must never apply a blind recursive case converter because authored names and standards-owned values are opaque.
|
|
73
|
+
|
|
74
|
+
See `.docs/reference/ir/naming.md` and `.docs/reference/ir/properties.md`.
|
|
75
|
+
|
|
76
|
+
## Responsibility boundary
|
|
77
|
+
|
|
78
|
+
The compiler may:
|
|
79
|
+
|
|
80
|
+
- validate Author/compiler compatibility;
|
|
81
|
+
- inspect and execute the Python authoring environment;
|
|
82
|
+
- validate Python Author state;
|
|
83
|
+
- resolve symbolic relationships;
|
|
84
|
+
- classify implementation-specific declarations into canonical concepts;
|
|
85
|
+
- normalize canonical key/value spelling;
|
|
86
|
+
- compile to Runtime-owned IR contracts;
|
|
87
|
+
- stream deterministic Authoring Protocol records;
|
|
88
|
+
- preserve source/provenance diagnostics.
|
|
89
|
+
|
|
90
|
+
It must not:
|
|
91
|
+
|
|
92
|
+
- create a competing semantic model;
|
|
93
|
+
- generate application source code;
|
|
94
|
+
- select template packs;
|
|
95
|
+
- choose output paths;
|
|
96
|
+
- write generated project files;
|
|
97
|
+
- own persisted Runtime serialization.
|
|
98
|
+
|
|
99
|
+
Equivalent Python and TypeScript authored meaning must converge on equivalent canonical Runtime IR.
|
|
100
|
+
|
|
101
|
+
## Development
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
uv sync
|
|
105
|
+
uv run ruff format .
|
|
106
|
+
uv run ruff check --fix .
|
|
107
|
+
uv run mypy
|
|
108
|
+
uv run pytest
|
|
109
|
+
uv build
|
|
110
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dryv-compiler"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "Runnable Python authoring compiler/provider for Dryv"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = { text = "Apache-2.0" }
|
|
12
|
+
dependencies = [
|
|
13
|
+
"dryv-author>=0.0.1,<0.1",
|
|
14
|
+
"packaging>=24,<26",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.scripts]
|
|
18
|
+
dryv-py = "dryv_compiler.cli:main"
|
|
19
|
+
|
|
20
|
+
[dependency-groups]
|
|
21
|
+
dev = [
|
|
22
|
+
# The engine validates compiled IR in tests only; the published compiler doesn't need it.
|
|
23
|
+
"dryv",
|
|
24
|
+
"mypy>=1.17",
|
|
25
|
+
"pytest>=8.4",
|
|
26
|
+
"ruff>=0.12",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[tool.uv.sources]
|
|
30
|
+
dryv-author = { path = "../author", editable = true }
|
|
31
|
+
dryv = { path = "../../../../engine/python/engine", editable = true }
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.wheel]
|
|
34
|
+
packages = ["src/dryv_compiler"]
|
|
35
|
+
|
|
36
|
+
[tool.ruff]
|
|
37
|
+
target-version = "py311"
|
|
38
|
+
line-length = 100
|
|
39
|
+
src = ["src", "tests"]
|
|
40
|
+
|
|
41
|
+
[tool.ruff.lint]
|
|
42
|
+
select = ["E4", "E7", "E9", "F", "I", "UP", "B", "SIM", "RUF"]
|
|
43
|
+
|
|
44
|
+
[tool.ruff.format]
|
|
45
|
+
quote-style = "double"
|
|
46
|
+
indent-style = "space"
|
|
47
|
+
line-ending = "lf"
|
|
48
|
+
docstring-code-format = true
|
|
49
|
+
|
|
50
|
+
[tool.mypy]
|
|
51
|
+
python_version = "3.11"
|
|
52
|
+
strict = true
|
|
53
|
+
plugins = ["pydantic.mypy"]
|
|
54
|
+
mypy_path = "../../../../engine/python/engine/src:../author/src"
|
|
55
|
+
files = ["src", "tests"]
|
|
56
|
+
pretty = true
|
|
57
|
+
show_error_codes = true
|
|
58
|
+
warn_unreachable = true
|
|
59
|
+
|
|
60
|
+
[tool.pydantic-mypy]
|
|
61
|
+
init_forbid_extra = true
|
|
62
|
+
init_typed = true
|
|
63
|
+
warn_required_dynamic_aliases = true
|
|
64
|
+
warn_untyped_fields = true
|
|
65
|
+
|
|
66
|
+
[tool.pytest.ini_options]
|
|
67
|
+
pythonpath = ["src", "../author/src", "../../../../engine/python/engine/src"]
|
|
68
|
+
testpaths = ["tests"]
|
|
69
|
+
addopts = ["--strict-config", "--strict-markers", "-ra"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .compatibility import AuthorCompatibilityError, validate_author_compatibility
|
|
2
|
+
from .mapping import compile_app, compile_ir
|
|
3
|
+
from .version import (
|
|
4
|
+
AUTHOR_COMPATIBILITY,
|
|
5
|
+
COMPILER_VERSION,
|
|
6
|
+
SUPPORTED_AUTHORING_PROTOCOLS,
|
|
7
|
+
SUPPORTED_RUNTIME_IR_VERSIONS,
|
|
8
|
+
__version__,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"AUTHOR_COMPATIBILITY",
|
|
13
|
+
"COMPILER_VERSION",
|
|
14
|
+
"SUPPORTED_AUTHORING_PROTOCOLS",
|
|
15
|
+
"SUPPORTED_RUNTIME_IR_VERSIONS",
|
|
16
|
+
"AuthorCompatibilityError",
|
|
17
|
+
"__version__",
|
|
18
|
+
"compile_app",
|
|
19
|
+
"compile_ir",
|
|
20
|
+
"validate_author_compatibility",
|
|
21
|
+
]
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import signal
|
|
6
|
+
import sys
|
|
7
|
+
from collections.abc import Sequence
|
|
8
|
+
from threading import Thread
|
|
9
|
+
|
|
10
|
+
from .execution import inspect_python_environment
|
|
11
|
+
from .protocol import (
|
|
12
|
+
AuthoringServerMessage,
|
|
13
|
+
CancellationToken,
|
|
14
|
+
CancelRequest,
|
|
15
|
+
CompileRequest,
|
|
16
|
+
ErrorMessage,
|
|
17
|
+
encode_message,
|
|
18
|
+
parse_client_message_text,
|
|
19
|
+
stream_compile,
|
|
20
|
+
)
|
|
21
|
+
from .version import (
|
|
22
|
+
COMPILER_VERSION,
|
|
23
|
+
SUPPORTED_AUTHORING_PROTOCOLS,
|
|
24
|
+
SUPPORTED_RUNTIME_IR_VERSIONS,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _emit(message: AuthoringServerMessage) -> None:
|
|
29
|
+
sys.stdout.write(encode_message(message))
|
|
30
|
+
sys.stdout.write("\n")
|
|
31
|
+
sys.stdout.flush()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _install_signal_cancellation(token: CancellationToken) -> None:
|
|
35
|
+
def cancel(_signum: int, _frame: object) -> None:
|
|
36
|
+
token.cancel()
|
|
37
|
+
|
|
38
|
+
signal.signal(signal.SIGINT, cancel)
|
|
39
|
+
signal.signal(signal.SIGTERM, cancel)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _watch_stdin_cancellation(session_id: str, token: CancellationToken) -> None:
|
|
43
|
+
for raw in sys.stdin:
|
|
44
|
+
if not raw.strip():
|
|
45
|
+
continue
|
|
46
|
+
try:
|
|
47
|
+
message = parse_client_message_text(raw)
|
|
48
|
+
except ValueError:
|
|
49
|
+
continue
|
|
50
|
+
if isinstance(message, CancelRequest) and message.session_id == session_id:
|
|
51
|
+
token.cancel()
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _run_request(request: CompileRequest, *, watch_stdin: bool) -> int:
|
|
56
|
+
token = CancellationToken()
|
|
57
|
+
_install_signal_cancellation(token)
|
|
58
|
+
if watch_stdin:
|
|
59
|
+
Thread(
|
|
60
|
+
target=_watch_stdin_cancellation,
|
|
61
|
+
args=(request.session_id, token),
|
|
62
|
+
daemon=True,
|
|
63
|
+
).start()
|
|
64
|
+
return 0 if stream_compile(request, _emit, cancellation=token) else 1
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _stdio() -> int:
|
|
68
|
+
first = sys.stdin.readline()
|
|
69
|
+
if not first:
|
|
70
|
+
sys.stderr.write("dryv-py stdio expected a compile.request JSONL message\n")
|
|
71
|
+
return 2
|
|
72
|
+
try:
|
|
73
|
+
message = parse_client_message_text(first)
|
|
74
|
+
except ValueError as exc:
|
|
75
|
+
_emit(ErrorMessage(session_id="unknown", code="PROTOCOL_ERROR", message=str(exc)))
|
|
76
|
+
return 2
|
|
77
|
+
if not isinstance(message, CompileRequest):
|
|
78
|
+
_emit(
|
|
79
|
+
ErrorMessage(
|
|
80
|
+
session_id=message.session_id,
|
|
81
|
+
code="PROTOCOL_ERROR",
|
|
82
|
+
message="first stdio message must be compile.request",
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
return 2
|
|
86
|
+
return _run_request(message, watch_stdin=True)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _compile(
|
|
90
|
+
*,
|
|
91
|
+
entrypoint: str,
|
|
92
|
+
session_id: str,
|
|
93
|
+
batch_size: int,
|
|
94
|
+
protocol: str,
|
|
95
|
+
runtime_ir: str,
|
|
96
|
+
) -> int:
|
|
97
|
+
request = CompileRequest(
|
|
98
|
+
session_id=session_id,
|
|
99
|
+
entrypoint=entrypoint,
|
|
100
|
+
protocol_versions=(protocol,),
|
|
101
|
+
runtime_ir_versions=(runtime_ir,),
|
|
102
|
+
batch_size=batch_size,
|
|
103
|
+
)
|
|
104
|
+
return _run_request(request, watch_stdin=False)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _doctor(entrypoint: str) -> int:
|
|
108
|
+
report = inspect_python_environment(entrypoint)
|
|
109
|
+
value: dict[str, object] = {
|
|
110
|
+
"status": report.status.value,
|
|
111
|
+
"pythonExecutable": report.python_executable,
|
|
112
|
+
"pythonVersion": report.python_version,
|
|
113
|
+
"projectRoot": report.project_root,
|
|
114
|
+
"entrypoint": report.entrypoint,
|
|
115
|
+
"virtualEnvironment": report.virtual_environment,
|
|
116
|
+
"authorVersion": report.author_version,
|
|
117
|
+
}
|
|
118
|
+
if report.message is not None:
|
|
119
|
+
value["message"] = report.message
|
|
120
|
+
sys.stdout.write(json.dumps(value, sort_keys=True, separators=(",", ":")))
|
|
121
|
+
sys.stdout.write("\n")
|
|
122
|
+
return 0 if report.status.value == "READY" else 1
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
126
|
+
parser = argparse.ArgumentParser(prog="dryv-py")
|
|
127
|
+
parser.add_argument("--version", action="version", version=COMPILER_VERSION)
|
|
128
|
+
commands = parser.add_subparsers(dest="command", required=True)
|
|
129
|
+
|
|
130
|
+
compile_parser = commands.add_parser("compile", help="compile one Python authoring entrypoint")
|
|
131
|
+
compile_parser.add_argument("entrypoint")
|
|
132
|
+
compile_parser.add_argument("--session-id", default="standalone")
|
|
133
|
+
compile_parser.add_argument("--batch-size", type=int, default=64)
|
|
134
|
+
compile_parser.add_argument("--protocol", default=SUPPORTED_AUTHORING_PROTOCOLS[0])
|
|
135
|
+
compile_parser.add_argument("--runtime-ir", default=SUPPORTED_RUNTIME_IR_VERSIONS[0])
|
|
136
|
+
|
|
137
|
+
commands.add_parser("stdio", help="serve one machine-readable JSONL compile session on stdio")
|
|
138
|
+
doctor_parser = commands.add_parser("doctor", help="inspect the Python authoring environment")
|
|
139
|
+
doctor_parser.add_argument("entrypoint")
|
|
140
|
+
return parser
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
144
|
+
parser = build_parser()
|
|
145
|
+
args = parser.parse_args(argv)
|
|
146
|
+
command = str(args.command)
|
|
147
|
+
if command == "compile":
|
|
148
|
+
return _compile(
|
|
149
|
+
entrypoint=str(args.entrypoint),
|
|
150
|
+
session_id=str(args.session_id),
|
|
151
|
+
batch_size=int(args.batch_size),
|
|
152
|
+
protocol=str(args.protocol),
|
|
153
|
+
runtime_ir=str(args.runtime_ir),
|
|
154
|
+
)
|
|
155
|
+
if command == "stdio":
|
|
156
|
+
return _stdio()
|
|
157
|
+
if command == "doctor":
|
|
158
|
+
return _doctor(str(args.entrypoint))
|
|
159
|
+
parser.error(f"unsupported command: {command}")
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from dryv_author import AUTHOR_REPRESENTATION_VERSION
|
|
6
|
+
from dryv_author import __version__ as author_version
|
|
7
|
+
from packaging.specifiers import SpecifierSet
|
|
8
|
+
from packaging.version import InvalidVersion, Version
|
|
9
|
+
|
|
10
|
+
from .version import AUTHOR_COMPATIBILITY, AUTHOR_REPRESENTATION
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AuthorCompatibilityError(RuntimeError):
|
|
14
|
+
"""Raised when an author SDK cannot be consumed by this compiler."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True, slots=True)
|
|
18
|
+
class AuthorCompatibility:
|
|
19
|
+
author_version: str
|
|
20
|
+
supported_versions: str
|
|
21
|
+
representation: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def current_author_compatibility() -> AuthorCompatibility:
|
|
25
|
+
return AuthorCompatibility(
|
|
26
|
+
author_version=author_version,
|
|
27
|
+
supported_versions=AUTHOR_COMPATIBILITY,
|
|
28
|
+
representation=AUTHOR_REPRESENTATION_VERSION,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def validate_author_details(author_version_value: str, representation: str) -> AuthorCompatibility:
|
|
33
|
+
compatibility = AuthorCompatibility(
|
|
34
|
+
author_version=author_version_value,
|
|
35
|
+
supported_versions=AUTHOR_COMPATIBILITY,
|
|
36
|
+
representation=representation,
|
|
37
|
+
)
|
|
38
|
+
try:
|
|
39
|
+
parsed = Version(compatibility.author_version)
|
|
40
|
+
except InvalidVersion as exc:
|
|
41
|
+
raise AuthorCompatibilityError(
|
|
42
|
+
f"installed dryv-author version {compatibility.author_version!r} is invalid"
|
|
43
|
+
) from exc
|
|
44
|
+
|
|
45
|
+
if parsed not in SpecifierSet(compatibility.supported_versions):
|
|
46
|
+
raise AuthorCompatibilityError(
|
|
47
|
+
"installed dryv-author version "
|
|
48
|
+
f"{compatibility.author_version!r} is incompatible with compiler requirement "
|
|
49
|
+
f"{compatibility.supported_versions!r}"
|
|
50
|
+
)
|
|
51
|
+
if compatibility.representation != AUTHOR_REPRESENTATION:
|
|
52
|
+
raise AuthorCompatibilityError(
|
|
53
|
+
"installed dryv-author compiler-facing representation "
|
|
54
|
+
f"{compatibility.representation!r} is incompatible with {AUTHOR_REPRESENTATION!r}"
|
|
55
|
+
)
|
|
56
|
+
return compatibility
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def validate_author_compatibility() -> AuthorCompatibility:
|
|
60
|
+
compatibility = current_author_compatibility()
|
|
61
|
+
return validate_author_details(
|
|
62
|
+
compatibility.author_version,
|
|
63
|
+
compatibility.representation,
|
|
64
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from .entrypoint import AuthorEntrypointError, LoadedAuthor, load_author_entrypoint
|
|
2
|
+
from .environment import EnvironmentStatus, PythonEnvironmentReport, inspect_python_environment
|
|
3
|
+
from .project import (
|
|
4
|
+
CapturedAuthor,
|
|
5
|
+
ProjectPythonError,
|
|
6
|
+
capture_author_entrypoint,
|
|
7
|
+
discover_project_python,
|
|
8
|
+
inspect_project_python,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"AuthorEntrypointError",
|
|
13
|
+
"CapturedAuthor",
|
|
14
|
+
"EnvironmentStatus",
|
|
15
|
+
"LoadedAuthor",
|
|
16
|
+
"ProjectPythonError",
|
|
17
|
+
"PythonEnvironmentReport",
|
|
18
|
+
"capture_author_entrypoint",
|
|
19
|
+
"discover_project_python",
|
|
20
|
+
"inspect_project_python",
|
|
21
|
+
"inspect_python_environment",
|
|
22
|
+
"load_author_entrypoint",
|
|
23
|
+
]
|