positronic-model-server 0.2.2__tar.gz → 0.2.3__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.
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/PKG-INFO +12 -9
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/README.md +11 -8
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/spec.py +7 -5
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/tests/test_spec.py +28 -2
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/pyproject.toml +1 -1
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/.gitignore +0 -0
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/grpc_wire.py +0 -0
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/keys.py +0 -0
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/protocol.py +0 -0
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/py.typed +0 -0
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/serialization.py +0 -0
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/server.py +0 -0
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/server_wire.py +0 -0
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/tests/test_model_server.py +0 -0
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/tests/test_serialization.py +0 -0
- {positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/websocket_wire.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: positronic-model-server
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Model serving, session lifecycle and serialization without Positronic dependencies
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -22,9 +22,9 @@ The wrapper owns transport, sessions, serialization and cleanup. Vendor scripts
|
|
|
22
22
|
model directly in the same process and describe the client pipeline as plain data.
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
uv pip install "positronic-model-server==0.2.
|
|
26
|
-
uv pip install "positronic-model-server[websocket]==0.2.
|
|
27
|
-
uv pip install "positronic-model-server[grpc]==0.2.
|
|
25
|
+
uv pip install "positronic-model-server==0.2.3"
|
|
26
|
+
uv pip install "positronic-model-server[websocket]==0.2.3"
|
|
27
|
+
uv pip install "positronic-model-server[grpc]==0.2.3"
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
The core depends on NumPy, Pillow, msgpack and `positronic-wire`'s dependency-free transport
|
|
@@ -45,7 +45,7 @@ from positronic_model_server.websocket_wire import WebsocketWire
|
|
|
45
45
|
|
|
46
46
|
class EchoSession(Session):
|
|
47
47
|
def __init__(self, fps):
|
|
48
|
-
super().__init__(component("chunked_schedule",
|
|
48
|
+
super().__init__(component("chunked_schedule", fps=fps))
|
|
49
49
|
|
|
50
50
|
def infer(self, observation):
|
|
51
51
|
return [observation]
|
|
@@ -137,7 +137,7 @@ and instantiates their implementations:
|
|
|
137
137
|
from positronic_model_server.spec import component, parallel, sequence
|
|
138
138
|
|
|
139
139
|
description = sequence(
|
|
140
|
-
component("chunked_schedule",
|
|
140
|
+
component("chunked_schedule", fps=20),
|
|
141
141
|
parallel(
|
|
142
142
|
component("restrict_image_size", width=320, height=180),
|
|
143
143
|
component("metadata", values={"model": "example"}),
|
|
@@ -145,9 +145,12 @@ description = sequence(
|
|
|
145
145
|
)
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
-
`component` accepts a name
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
`component` accepts a name and JSON-compatible keyword arguments. By default it writes `version="latest"`,
|
|
149
|
+
which selects the client's latest supported version. This can change after a client upgrade;
|
|
150
|
+
pass `version=2`, for example, to pin a specific version. Legacy descriptions without a version mean v1.
|
|
151
|
+
|
|
152
|
+
`sequence` and `parallel` reject empty compositions. The helpers check description structure;
|
|
153
|
+
the client checks component names, supported versions and arguments when it builds the pipeline.
|
|
151
154
|
The structural keys (`NAME`, `VERSION`, `ARGS`, `SEQ`, `PAR`) have one definition in `spec`.
|
|
152
155
|
|
|
153
156
|
The wrapper defines only constants used by its own production code. Vendor settings belong to small
|
|
@@ -5,9 +5,9 @@ The wrapper owns transport, sessions, serialization and cleanup. Vendor scripts
|
|
|
5
5
|
model directly in the same process and describe the client pipeline as plain data.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
uv pip install "positronic-model-server==0.2.
|
|
9
|
-
uv pip install "positronic-model-server[websocket]==0.2.
|
|
10
|
-
uv pip install "positronic-model-server[grpc]==0.2.
|
|
8
|
+
uv pip install "positronic-model-server==0.2.3"
|
|
9
|
+
uv pip install "positronic-model-server[websocket]==0.2.3"
|
|
10
|
+
uv pip install "positronic-model-server[grpc]==0.2.3"
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
The core depends on NumPy, Pillow, msgpack and `positronic-wire`'s dependency-free transport
|
|
@@ -28,7 +28,7 @@ from positronic_model_server.websocket_wire import WebsocketWire
|
|
|
28
28
|
|
|
29
29
|
class EchoSession(Session):
|
|
30
30
|
def __init__(self, fps):
|
|
31
|
-
super().__init__(component("chunked_schedule",
|
|
31
|
+
super().__init__(component("chunked_schedule", fps=fps))
|
|
32
32
|
|
|
33
33
|
def infer(self, observation):
|
|
34
34
|
return [observation]
|
|
@@ -120,7 +120,7 @@ and instantiates their implementations:
|
|
|
120
120
|
from positronic_model_server.spec import component, parallel, sequence
|
|
121
121
|
|
|
122
122
|
description = sequence(
|
|
123
|
-
component("chunked_schedule",
|
|
123
|
+
component("chunked_schedule", fps=20),
|
|
124
124
|
parallel(
|
|
125
125
|
component("restrict_image_size", width=320, height=180),
|
|
126
126
|
component("metadata", values={"model": "example"}),
|
|
@@ -128,9 +128,12 @@ description = sequence(
|
|
|
128
128
|
)
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
`component` accepts a name
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
`component` accepts a name and JSON-compatible keyword arguments. By default it writes `version="latest"`,
|
|
132
|
+
which selects the client's latest supported version. This can change after a client upgrade;
|
|
133
|
+
pass `version=2`, for example, to pin a specific version. Legacy descriptions without a version mean v1.
|
|
134
|
+
|
|
135
|
+
`sequence` and `parallel` reject empty compositions. The helpers check description structure;
|
|
136
|
+
the client checks component names, supported versions and arguments when it builds the pipeline.
|
|
134
137
|
The structural keys (`NAME`, `VERSION`, `ARGS`, `SEQ`, `PAR`) have one definition in `spec`.
|
|
135
138
|
|
|
136
139
|
The wrapper defines only constants used by its own production code. Vendor settings belong to small
|
{positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/spec.py
RENAMED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
from collections.abc import Sequence
|
|
5
|
-
from typing import Any
|
|
5
|
+
from typing import Any, Literal
|
|
6
6
|
|
|
7
7
|
SEQ = 'seq'
|
|
8
8
|
PAR = 'par'
|
|
@@ -10,13 +10,15 @@ NAME = 'name'
|
|
|
10
10
|
ARGS = 'args'
|
|
11
11
|
VERSION = 'version'
|
|
12
12
|
|
|
13
|
+
LATEST: Literal['latest'] = 'latest'
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
def component(name: str, /, *, version: int | Literal['latest'] = LATEST, **args: Any) -> dict[str, Any]:
|
|
17
|
+
"""Describe a component, requesting the client's latest supported version unless pinned."""
|
|
16
18
|
if not isinstance(name, str) or not name:
|
|
17
19
|
raise ValueError('A component needs a nonempty name')
|
|
18
|
-
if type(version) is not int or version < 1:
|
|
19
|
-
raise ValueError('A component version must be a positive integer')
|
|
20
|
+
if version != LATEST and (type(version) is not int or version < 1):
|
|
21
|
+
raise ValueError('A component version must be a positive integer or "latest"')
|
|
20
22
|
# JSON normalizes tuples to lists and rejects Python objects and nonfinite numbers.
|
|
21
23
|
return {NAME: name, VERSION: version, ARGS: json.loads(json.dumps(args, allow_nan=False))}
|
|
22
24
|
|
|
@@ -5,6 +5,7 @@ import json
|
|
|
5
5
|
import pytest
|
|
6
6
|
from positronic_model_server.spec import (
|
|
7
7
|
ARGS,
|
|
8
|
+
LATEST,
|
|
8
9
|
NAME,
|
|
9
10
|
PAR,
|
|
10
11
|
SEQ,
|
|
@@ -23,11 +24,29 @@ def test_composition_uses_the_client_wire_format():
|
|
|
23
24
|
assert json.loads(json.dumps(spec)) == {
|
|
24
25
|
'seq': [
|
|
25
26
|
{'name': 'scheduler', 'version': 2, 'args': {'fps': 20}},
|
|
26
|
-
{
|
|
27
|
+
{
|
|
28
|
+
'par': [
|
|
29
|
+
{'name': 'left', 'version': 'latest', 'args': {}},
|
|
30
|
+
{'name': 'right', 'version': 'latest', 'args': {}},
|
|
31
|
+
]
|
|
32
|
+
},
|
|
27
33
|
]
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
|
|
37
|
+
def test_omitted_versions_request_latest():
|
|
38
|
+
saved = json.loads(json.dumps(component('vendor-owned')))
|
|
39
|
+
validate(saved)
|
|
40
|
+
assert saved[VERSION] == LATEST
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@pytest.mark.parametrize('version', [LATEST, 1, 17])
|
|
44
|
+
def test_explicit_versions_survive_json_and_validation(version):
|
|
45
|
+
saved = json.loads(json.dumps(component('vendor-owned', version=version)))
|
|
46
|
+
validate(saved)
|
|
47
|
+
assert saved[VERSION] == version
|
|
48
|
+
|
|
49
|
+
|
|
31
50
|
def test_arguments_are_normalized_to_json():
|
|
32
51
|
arguments = {'offsets': (-0.1, 0), 'nested': {'values': [1, None, True]}}
|
|
33
52
|
spec = component('vendor-owned', **arguments)
|
|
@@ -42,7 +61,7 @@ def test_non_json_arguments_fail_at_construction(value):
|
|
|
42
61
|
component('vendor-owned', value=value)
|
|
43
62
|
|
|
44
63
|
|
|
45
|
-
@pytest.mark.parametrize('version', [0, -1, True, '1'])
|
|
64
|
+
@pytest.mark.parametrize('version', [0, -1, True, '1', 'newest', None])
|
|
46
65
|
def test_invalid_versions_are_rejected(version):
|
|
47
66
|
with pytest.raises(ValueError, match='positive integer'):
|
|
48
67
|
component('vendor-owned', version=version)
|
|
@@ -62,6 +81,7 @@ def test_empty_composition_is_rejected(compose):
|
|
|
62
81
|
{PAR: []},
|
|
63
82
|
{SEQ: [component('x')], NAME: 'x'},
|
|
64
83
|
{NAME: 'x', VERSION: False},
|
|
84
|
+
{NAME: 'chunked_schedule', VERSION: None},
|
|
65
85
|
{NAME: 'x', ARGS: []},
|
|
66
86
|
{NAME: 'x', ARGS: {'value': float('nan')}},
|
|
67
87
|
],
|
|
@@ -75,6 +95,12 @@ def test_structural_validation_does_not_need_a_component_registry():
|
|
|
75
95
|
validate(sequence(component('unknown-vendor-component', version=17), parallel(component('another'))))
|
|
76
96
|
|
|
77
97
|
|
|
98
|
+
def test_validation_preserves_unversioned_wire_descriptions():
|
|
99
|
+
node = {NAME: 'chunked_schedule', ARGS: {'fps': 20}}
|
|
100
|
+
validate(node)
|
|
101
|
+
assert VERSION not in node
|
|
102
|
+
|
|
103
|
+
|
|
78
104
|
def test_parameter_resolution_refuses_unknown_names_and_copies_defaults():
|
|
79
105
|
defaults = {'options': {'steps': [1, 2]}, 'fps': 20}
|
|
80
106
|
effective = resolve_params(defaults, {'fps': 10})
|
|
File without changes
|
{positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/grpc_wire.py
RENAMED
|
File without changes
|
{positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/keys.py
RENAMED
|
File without changes
|
{positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/protocol.py
RENAMED
|
File without changes
|
{positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
{positronic_model_server-0.2.2 → positronic_model_server-0.2.3}/positronic_model_server/server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|