programasweights 0.4.7__tar.gz → 0.4.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.
- {programasweights-0.4.7 → programasweights-0.4.9}/CHANGELOG.md +12 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/PKG-INFO +15 -12
- {programasweights-0.4.7 → programasweights-0.4.9}/PYPI_README.md +14 -11
- {programasweights-0.4.7 → programasweights-0.4.9}/README.md +14 -11
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/__init__.py +8 -4
- {programasweights-0.4.7 → programasweights-0.4.9}/pyproject.toml +11 -1
- programasweights-0.4.7/.cursor/rules/releases.mdc +0 -17
- programasweights-0.4.7/.github/workflows/release.yml +0 -72
- programasweights-0.4.7/.github/workflows/test.yml +0 -94
- programasweights-0.4.7/.readthedocs.yaml +0 -13
- programasweights-0.4.7/AGENTS.md +0 -291
- programasweights-0.4.7/RELEASING.md +0 -82
- programasweights-0.4.7/docs/adr/001-llama-cpp-over-pytorch.md +0 -21
- programasweights-0.4.7/docs/adr/002-q4_0-adapter-format.md +0 -32
- programasweights-0.4.7/docs/adr/003-single-spec-field.md +0 -26
- programasweights-0.4.7/docs/adr/004-compiler-naming.md +0 -32
- programasweights-0.4.7/docs/adr/005-vllm-hidden-states.md +0 -24
- programasweights-0.4.7/docs/adr/006-email-api-key-auth.md +0 -41
- programasweights-0.4.7/docs/advanced/adrs.md +0 -67
- programasweights-0.4.7/docs/advanced/architecture.md +0 -47
- programasweights-0.4.7/docs/api-reference/cli.md +0 -110
- programasweights-0.4.7/docs/api-reference/python-sdk.md +0 -363
- programasweights-0.4.7/docs/api-reference/rest-api.md +0 -200
- programasweights-0.4.7/docs/architecture.md +0 -38
- programasweights-0.4.7/docs/case-studies/alien-taboo.md +0 -117
- programasweights-0.4.7/docs/case-studies/log-monitoring.md +0 -132
- programasweights-0.4.7/docs/case-studies/semantic-search.md +0 -146
- programasweights-0.4.7/docs/case-studies/site-navigation.md +0 -127
- programasweights-0.4.7/docs/case-studies/tool-calling.md +0 -477
- programasweights-0.4.7/docs/getting-started/first-program.md +0 -88
- programasweights-0.4.7/docs/getting-started/installation.md +0 -57
- programasweights-0.4.7/docs/getting-started/naming-programs.md +0 -78
- programasweights-0.4.7/docs/guide/browser-inference.md +0 -141
- programasweights-0.4.7/docs/guide/how-it-works.md +0 -47
- programasweights-0.4.7/docs/guide/local-inference.md +0 -48
- programasweights-0.4.7/docs/guide/writing-good-specs.md +0 -11
- programasweights-0.4.7/docs/hub/browsing-programs.md +0 -37
- programasweights-0.4.7/docs/hub/feedback-cases.md +0 -34
- programasweights-0.4.7/docs/hub/publishing-programs.md +0 -31
- programasweights-0.4.7/docs/index.md +0 -96
- programasweights-0.4.7/docs/requirements.txt +0 -2
- programasweights-0.4.7/examples/flask_app.py +0 -52
- programasweights-0.4.7/examples/jupyter_notebook.py +0 -52
- programasweights-0.4.7/examples/langchain_integration.py +0 -52
- programasweights-0.4.7/examples/paw_monitor.py +0 -180
- programasweights-0.4.7/examples/replace_openai.py +0 -44
- programasweights-0.4.7/mkdocs.yml +0 -87
- programasweights-0.4.7/scripts/release_metadata.py +0 -156
- programasweights-0.4.7/tests/test_api_errors.py +0 -222
- programasweights-0.4.7/tests/test_base_interpreter.py +0 -845
- programasweights-0.4.7/tests/test_cli_auth.py +0 -265
- programasweights-0.4.7/tests/test_compile_timeouts.py +0 -129
- programasweights-0.4.7/tests/test_desktop_sdk.py +0 -1221
- programasweights-0.4.7/tests/test_local_program.py +0 -676
- programasweights-0.4.7/tests/test_offline_cache.py +0 -97
- programasweights-0.4.7/tests/test_release_metadata.py +0 -296
- programasweights-0.4.7/tests/test_remote_inference.py +0 -294
- programasweights-0.4.7/tests/test_runtime_registry_sdk.py +0 -123
- programasweights-0.4.7/tests/test_sdk.py +0 -484
- programasweights-0.4.7/tests/test_sdk.sh +0 -89
- {programasweights-0.4.7 → programasweights-0.4.9}/.gitignore +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/LICENSE +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/_output.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/_program_reference.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/_remote.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/artifacts.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/cache.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/cli.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/client.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/compiler/__init__.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/compiler/dummy.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/config.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/convert_peft_to_paw.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/errors.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/local_program.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/paw_format.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/runtime/__init__.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/runtime/interpreter.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/runtime/interpreter_onnx.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/runtime_llamacpp.py +0 -0
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.9 (2026-09-21)
|
|
4
|
+
|
|
5
|
+
- Lead quickstarts and examples with compiling your own functions, then
|
|
6
|
+
saving and reusing program IDs.
|
|
7
|
+
- Reuse loaded functions in the LangChain example and serialize calls to
|
|
8
|
+
each shared instance.
|
|
9
|
+
|
|
10
|
+
## 0.4.8 (2026-09-20)
|
|
11
|
+
|
|
12
|
+
- Reduce the source distribution to the SDK and files needed to build and
|
|
13
|
+
document the package.
|
|
14
|
+
|
|
3
15
|
## 0.4.7 (2026-09-20)
|
|
4
16
|
|
|
5
17
|
- Add `remote=True` to `paw.function` and `paw.compile_and_load`, plus
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: programasweights
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.9
|
|
4
4
|
Summary: Compile natural language specifications into neural programs that run locally via llama.cpp.
|
|
5
5
|
Project-URL: Homepage, https://programasweights.com
|
|
6
6
|
Project-URL: Repository, https://github.com/programasweights/programasweights-python
|
|
@@ -46,22 +46,21 @@ pip install programasweights --extra-index-url https://pypi.programasweights.com
|
|
|
46
46
|
```python
|
|
47
47
|
import programasweights as paw
|
|
48
48
|
|
|
49
|
-
#
|
|
50
|
-
fn = paw.
|
|
49
|
+
# Compile and load your own function
|
|
50
|
+
fn = paw.compile_and_load(
|
|
51
|
+
"Classify if a message needs immediate attention or can wait. "
|
|
52
|
+
"Return only 'immediate' or 'wait'."
|
|
53
|
+
)
|
|
51
54
|
fn("Urgent: the server is down!") # "immediate"
|
|
52
55
|
fn("Newsletter: spring picnic") # "wait"
|
|
53
56
|
|
|
54
|
-
# Compile
|
|
57
|
+
# Compile once and save the program ID
|
|
55
58
|
program = paw.compile(
|
|
56
|
-
"Fix malformed JSON: repair missing quotes and trailing commas"
|
|
57
|
-
slug="json-fixer" # optional: creates username/json-fixer handle
|
|
59
|
+
"Fix malformed JSON: repair missing quotes and trailing commas"
|
|
58
60
|
)
|
|
59
|
-
|
|
61
|
+
print(program.id) # Save this ID for future runs
|
|
62
|
+
fn = paw.function(program.id)
|
|
60
63
|
fn("{name: 'Alice',}") # '{"name":"Alice"}'
|
|
61
|
-
|
|
62
|
-
# Or compile and load in one step
|
|
63
|
-
fn = paw.compile_and_load("Classify sentiment as positive or negative")
|
|
64
|
-
fn("I love this!") # "positive"
|
|
65
64
|
```
|
|
66
65
|
|
|
67
66
|
If you specifically want the smaller browser-compatible runtime, pass `compiler="paw-4b-gpt2"`. Otherwise, omit `compiler` and let the server default decide.
|
|
@@ -73,7 +72,11 @@ Use the hosted API for fast inference in around 150 ms, without a local model do
|
|
|
73
72
|
```python
|
|
74
73
|
import programasweights as paw
|
|
75
74
|
|
|
76
|
-
with paw.
|
|
75
|
+
with paw.compile_and_load(
|
|
76
|
+
"Classify if a message needs immediate attention or can wait. "
|
|
77
|
+
"Return only 'immediate' or 'wait'.",
|
|
78
|
+
remote=True,
|
|
79
|
+
) as remote_fn:
|
|
77
80
|
print(remote_fn("Urgent: the server is down!"))
|
|
78
81
|
```
|
|
79
82
|
|
|
@@ -15,22 +15,21 @@ pip install programasweights --extra-index-url https://pypi.programasweights.com
|
|
|
15
15
|
```python
|
|
16
16
|
import programasweights as paw
|
|
17
17
|
|
|
18
|
-
#
|
|
19
|
-
fn = paw.
|
|
18
|
+
# Compile and load your own function
|
|
19
|
+
fn = paw.compile_and_load(
|
|
20
|
+
"Classify if a message needs immediate attention or can wait. "
|
|
21
|
+
"Return only 'immediate' or 'wait'."
|
|
22
|
+
)
|
|
20
23
|
fn("Urgent: the server is down!") # "immediate"
|
|
21
24
|
fn("Newsletter: spring picnic") # "wait"
|
|
22
25
|
|
|
23
|
-
# Compile
|
|
26
|
+
# Compile once and save the program ID
|
|
24
27
|
program = paw.compile(
|
|
25
|
-
"Fix malformed JSON: repair missing quotes and trailing commas"
|
|
26
|
-
slug="json-fixer" # optional: creates username/json-fixer handle
|
|
28
|
+
"Fix malformed JSON: repair missing quotes and trailing commas"
|
|
27
29
|
)
|
|
28
|
-
|
|
30
|
+
print(program.id) # Save this ID for future runs
|
|
31
|
+
fn = paw.function(program.id)
|
|
29
32
|
fn("{name: 'Alice',}") # '{"name":"Alice"}'
|
|
30
|
-
|
|
31
|
-
# Or compile and load in one step
|
|
32
|
-
fn = paw.compile_and_load("Classify sentiment as positive or negative")
|
|
33
|
-
fn("I love this!") # "positive"
|
|
34
33
|
```
|
|
35
34
|
|
|
36
35
|
If you specifically want the smaller browser-compatible runtime, pass `compiler="paw-4b-gpt2"`. Otherwise, omit `compiler` and let the server default decide.
|
|
@@ -42,7 +41,11 @@ Use the hosted API for fast inference in around 150 ms, without a local model do
|
|
|
42
41
|
```python
|
|
43
42
|
import programasweights as paw
|
|
44
43
|
|
|
45
|
-
with paw.
|
|
44
|
+
with paw.compile_and_load(
|
|
45
|
+
"Classify if a message needs immediate attention or can wait. "
|
|
46
|
+
"Return only 'immediate' or 'wait'.",
|
|
47
|
+
remote=True,
|
|
48
|
+
) as remote_fn:
|
|
46
49
|
print(remote_fn("Urgent: the server is down!"))
|
|
47
50
|
```
|
|
48
51
|
|
|
@@ -15,22 +15,21 @@ pip install programasweights --extra-index-url https://pypi.programasweights.com
|
|
|
15
15
|
```python
|
|
16
16
|
import programasweights as paw
|
|
17
17
|
|
|
18
|
-
#
|
|
19
|
-
fn = paw.
|
|
18
|
+
# Compile and load your own function
|
|
19
|
+
fn = paw.compile_and_load(
|
|
20
|
+
"Classify if a message needs immediate attention or can wait. "
|
|
21
|
+
"Return only 'immediate' or 'wait'."
|
|
22
|
+
)
|
|
20
23
|
fn("Urgent: the server is down!") # "immediate"
|
|
21
24
|
fn("Newsletter: spring picnic") # "wait"
|
|
22
25
|
|
|
23
|
-
# Compile
|
|
26
|
+
# Compile once and save the program ID
|
|
24
27
|
program = paw.compile(
|
|
25
|
-
"Fix malformed JSON: repair missing quotes and trailing commas"
|
|
26
|
-
slug="json-fixer" # optional: creates username/json-fixer handle
|
|
28
|
+
"Fix malformed JSON: repair missing quotes and trailing commas"
|
|
27
29
|
)
|
|
28
|
-
|
|
30
|
+
print(program.id) # Save this ID for future runs
|
|
31
|
+
fn = paw.function(program.id)
|
|
29
32
|
fn("{name: 'Alice',}") # '{"name":"Alice"}'
|
|
30
|
-
|
|
31
|
-
# Or compile and load in one step
|
|
32
|
-
fn = paw.compile_and_load("Classify sentiment as positive or negative")
|
|
33
|
-
fn("I love this!") # "positive"
|
|
34
33
|
```
|
|
35
34
|
|
|
36
35
|
If you specifically want the smaller browser-compatible runtime, pass `compiler="paw-4b-gpt2"`. Otherwise, omit `compiler` and let the server default decide.
|
|
@@ -42,7 +41,11 @@ Use the hosted API for fast inference in around 150 ms, without a local model do
|
|
|
42
41
|
```python
|
|
43
42
|
import programasweights as paw
|
|
44
43
|
|
|
45
|
-
with paw.
|
|
44
|
+
with paw.compile_and_load(
|
|
45
|
+
"Classify if a message needs immediate attention or can wait. "
|
|
46
|
+
"Return only 'immediate' or 'wait'.",
|
|
47
|
+
remote=True,
|
|
48
|
+
) as remote_fn:
|
|
46
49
|
print(remote_fn("Urgent: the server is down!"))
|
|
47
50
|
```
|
|
48
51
|
|
|
@@ -5,12 +5,16 @@ functions that run locally.
|
|
|
5
5
|
Quick start:
|
|
6
6
|
import programasweights as paw
|
|
7
7
|
|
|
8
|
-
#
|
|
9
|
-
fn = paw.
|
|
8
|
+
# Compile and load your own function
|
|
9
|
+
fn = paw.compile_and_load(
|
|
10
|
+
"Classify if a message needs immediate attention or can wait. "
|
|
11
|
+
"Return only 'immediate' or 'wait'."
|
|
12
|
+
)
|
|
10
13
|
fn("Urgent: server is down!") # "immediate"
|
|
11
14
|
|
|
12
|
-
# Compile
|
|
15
|
+
# Compile once and save the program ID
|
|
13
16
|
program = paw.compile("Fix malformed JSON: repair missing quotes and trailing commas")
|
|
17
|
+
print(program.id) # Save this ID for future runs
|
|
14
18
|
fn = paw.function(program.id)
|
|
15
19
|
fn("{name: 'Alice',}") # '{"name":"Alice"}'
|
|
16
20
|
|
|
@@ -27,7 +31,7 @@ try:
|
|
|
27
31
|
from importlib.metadata import version as _meta_version
|
|
28
32
|
__version__ = _meta_version("programasweights")
|
|
29
33
|
except Exception:
|
|
30
|
-
__version__ = "0.4.
|
|
34
|
+
__version__ = "0.4.9"
|
|
31
35
|
|
|
32
36
|
from ._output import ProgressCallback, ProgressEvent, report_progress
|
|
33
37
|
from .cache import CachedProgram
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "programasweights"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.9"
|
|
8
8
|
description = "Compile natural language specifications into neural programs that run locally via llama.cpp."
|
|
9
9
|
readme = "PYPI_README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -47,6 +47,16 @@ paw = "programasweights.cli:main"
|
|
|
47
47
|
[tool.hatch.build.targets.wheel]
|
|
48
48
|
packages = ["programasweights"]
|
|
49
49
|
|
|
50
|
+
[tool.hatch.build.targets.sdist]
|
|
51
|
+
only-include = [
|
|
52
|
+
"programasweights",
|
|
53
|
+
"README.md",
|
|
54
|
+
"PYPI_README.md",
|
|
55
|
+
"LICENSE",
|
|
56
|
+
"CHANGELOG.md",
|
|
57
|
+
"pyproject.toml",
|
|
58
|
+
]
|
|
59
|
+
|
|
50
60
|
[tool.pytest.ini_options]
|
|
51
61
|
addopts = "-q"
|
|
52
62
|
pythonpath = ["."]
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Publish and verify complete Python SDK releases
|
|
3
|
-
alwaysApply: true
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# SDK releases
|
|
7
|
-
|
|
8
|
-
For release or publication work, read `RELEASING.md` first.
|
|
9
|
-
|
|
10
|
-
- A release is complete only when its annotated remote tag, PyPI wheel and
|
|
11
|
-
source distribution, and published GitHub Release all exist and agree.
|
|
12
|
-
- Build from the clean, tested release commit; push its annotated version tag
|
|
13
|
-
before uploading the exact checked artifacts to PyPI.
|
|
14
|
-
- Verify the `GitHub release` workflow succeeded and the latest GitHub Release
|
|
15
|
-
agrees with PyPI. A tag alone is not a GitHub Release entry.
|
|
16
|
-
- Repair missing entries using the documented workflow dispatch. Never move a
|
|
17
|
-
published tag, rebuild an existing version, or bypass artifact verification.
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
name: GitHub release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags: ['v*']
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
inputs:
|
|
8
|
-
tag:
|
|
9
|
-
description: 'Existing stable version tag, e.g. v0.4.6'
|
|
10
|
-
required: true
|
|
11
|
-
type: string
|
|
12
|
-
|
|
13
|
-
permissions:
|
|
14
|
-
contents: write
|
|
15
|
-
|
|
16
|
-
concurrency:
|
|
17
|
-
group: github-release-${{ inputs.tag || github.ref_name }}
|
|
18
|
-
cancel-in-progress: false
|
|
19
|
-
|
|
20
|
-
jobs:
|
|
21
|
-
release:
|
|
22
|
-
runs-on: ubuntu-latest
|
|
23
|
-
timeout-minutes: 15
|
|
24
|
-
env:
|
|
25
|
-
RELEASE_TAG: ${{ inputs.tag || github.ref_name }}
|
|
26
|
-
GH_TOKEN: ${{ github.token }}
|
|
27
|
-
GH_REPO: ${{ github.repository }}
|
|
28
|
-
steps:
|
|
29
|
-
- name: Set the verification output directory
|
|
30
|
-
run: echo "RELEASE_DIR=$RUNNER_TEMP/verified-release" >> "$GITHUB_ENV"
|
|
31
|
-
- uses: actions/checkout@v4
|
|
32
|
-
with:
|
|
33
|
-
fetch-depth: 0
|
|
34
|
-
- uses: actions/setup-python@v5
|
|
35
|
-
with:
|
|
36
|
-
python-version: '3.12'
|
|
37
|
-
- name: Verify the remote tag and both published PyPI artifacts
|
|
38
|
-
# Tags are pushed before uploading. Wait for the wheel AND sdist;
|
|
39
|
-
# never announce an unpublished version or rebuild release assets.
|
|
40
|
-
run: python scripts/release_metadata.py --tag "$RELEASE_TAG" --output-dir "$RELEASE_DIR" --wait-seconds 600
|
|
41
|
-
- name: Publish the missing GitHub release
|
|
42
|
-
shell: bash
|
|
43
|
-
run: |
|
|
44
|
-
set -euo pipefail
|
|
45
|
-
if gh release view "$RELEASE_TAG" --json tagName >/dev/null 2>&1; then
|
|
46
|
-
echo "Release already exists; preserving its notes and assets."
|
|
47
|
-
else
|
|
48
|
-
latest=$(jq -r .latest "$RELEASE_DIR/verified.json")
|
|
49
|
-
gh release create "$RELEASE_TAG" "$RELEASE_DIR"/artifacts/* \
|
|
50
|
-
--verify-tag --title "$RELEASE_TAG" \
|
|
51
|
-
--notes-file "$RELEASE_DIR/notes.md" --latest="$latest"
|
|
52
|
-
fi
|
|
53
|
-
gh release view "$RELEASE_TAG" --json tagName,isDraft,isPrerelease,url \
|
|
54
|
-
| jq -e --arg tag "$RELEASE_TAG" '.tagName == $tag and .isDraft == false and .isPrerelease == false'
|
|
55
|
-
- name: Verify the uploaded release assets and latest marker
|
|
56
|
-
shell: bash
|
|
57
|
-
run: |
|
|
58
|
-
set -euo pipefail
|
|
59
|
-
gh release download "$RELEASE_TAG" --pattern 'programasweights-*' \
|
|
60
|
-
--dir "$RELEASE_DIR/github-assets"
|
|
61
|
-
for artifact in "$RELEASE_DIR"/artifacts/*; do
|
|
62
|
-
cmp "$artifact" "$RELEASE_DIR/github-assets/$(basename "$artifact")"
|
|
63
|
-
done
|
|
64
|
-
if [ "$(jq -r .latest "$RELEASE_DIR/verified.json")" = true ]; then
|
|
65
|
-
gh api "repos/$GH_REPO/releases/latest" \
|
|
66
|
-
| jq -e --arg tag "$RELEASE_TAG" '.tag_name == $tag'
|
|
67
|
-
fi
|
|
68
|
-
- name: Retain the verification record
|
|
69
|
-
uses: actions/upload-artifact@v4
|
|
70
|
-
with:
|
|
71
|
-
name: release-verification-${{ inputs.tag || github.ref_name }}
|
|
72
|
-
path: ${{ runner.temp }}/verified-release/verified.json
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
name: tests
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
pull_request:
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
release-metadata:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
steps:
|
|
12
|
-
- uses: actions/checkout@v4
|
|
13
|
-
- uses: actions/setup-python@v5
|
|
14
|
-
with:
|
|
15
|
-
python-version: '3.12'
|
|
16
|
-
- run: python -m pip install pytest
|
|
17
|
-
- name: Test release verification without network or publishing
|
|
18
|
-
run: python -m pytest tests/test_release_metadata.py
|
|
19
|
-
|
|
20
|
-
test:
|
|
21
|
-
runs-on: ubuntu-latest
|
|
22
|
-
strategy:
|
|
23
|
-
fail-fast: false
|
|
24
|
-
matrix:
|
|
25
|
-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
26
|
-
steps:
|
|
27
|
-
- uses: actions/checkout@v4
|
|
28
|
-
|
|
29
|
-
- name: Set up Python ${{ matrix.python-version }}
|
|
30
|
-
uses: actions/setup-python@v5
|
|
31
|
-
with:
|
|
32
|
-
python-version: ${{ matrix.python-version }}
|
|
33
|
-
|
|
34
|
-
- name: Install (hermetic deps only)
|
|
35
|
-
# Install httpx + pytest and the package itself without pulling the heavy
|
|
36
|
-
# llama-cpp-python build. Runtime tests inject a fake llama_cpp module,
|
|
37
|
-
# so CI needs neither the native extension nor a model download.
|
|
38
|
-
run: |
|
|
39
|
-
python -m pip install --upgrade pip
|
|
40
|
-
python -m pip install httpx pytest
|
|
41
|
-
python -m pip install -e . --no-deps
|
|
42
|
-
|
|
43
|
-
- name: Run hermetic tests
|
|
44
|
-
# Scoped to tests that need no network, no model download, and no
|
|
45
|
-
# PAW_API_KEY. Auth tests (@needs_auth) auto-skip without a key; the
|
|
46
|
-
# network/model-download tests in test_sdk.py are excluded here and can
|
|
47
|
-
# be run separately against a live server.
|
|
48
|
-
run: |
|
|
49
|
-
pytest \
|
|
50
|
-
tests/test_api_errors.py \
|
|
51
|
-
tests/test_compile_timeouts.py \
|
|
52
|
-
tests/test_local_program.py \
|
|
53
|
-
tests/test_base_interpreter.py \
|
|
54
|
-
tests/test_cli_auth.py \
|
|
55
|
-
tests/test_remote_inference.py \
|
|
56
|
-
tests/test_desktop_sdk.py \
|
|
57
|
-
tests/test_runtime_registry_sdk.py \
|
|
58
|
-
tests/test_sdk.py::TestInstallAndImport
|
|
59
|
-
|
|
60
|
-
local-files-windows:
|
|
61
|
-
runs-on: windows-latest
|
|
62
|
-
strategy:
|
|
63
|
-
fail-fast: false
|
|
64
|
-
matrix:
|
|
65
|
-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
66
|
-
steps:
|
|
67
|
-
- uses: actions/checkout@v4
|
|
68
|
-
- uses: actions/setup-python@v5
|
|
69
|
-
with:
|
|
70
|
-
python-version: ${{ matrix.python-version }}
|
|
71
|
-
- name: Install hermetic test dependencies
|
|
72
|
-
run: |
|
|
73
|
-
python -m pip install httpx pytest
|
|
74
|
-
python -m pip install -e . --no-deps
|
|
75
|
-
- name: Test Windows local paths, cache locks, and compile errors
|
|
76
|
-
run: python -m pytest tests/test_api_errors.py tests/test_compile_timeouts.py tests/test_local_program.py tests/test_remote_inference.py --junitxml=test-results.xml
|
|
77
|
-
- name: Annotate Windows test failures
|
|
78
|
-
if: failure()
|
|
79
|
-
shell: python
|
|
80
|
-
run: |
|
|
81
|
-
from pathlib import Path
|
|
82
|
-
import xml.etree.ElementTree as ET
|
|
83
|
-
|
|
84
|
-
report = Path("test-results.xml")
|
|
85
|
-
if report.exists():
|
|
86
|
-
for case in ET.parse(report).iter("testcase"):
|
|
87
|
-
for result in case:
|
|
88
|
-
if result.tag in {"failure", "error"}:
|
|
89
|
-
# GitHub truncates annotations, so retain the actual
|
|
90
|
-
# exception at the end of long pytest tracebacks.
|
|
91
|
-
detail = result.text or result.get("message", "")
|
|
92
|
-
message = f"{case.get('name')}: {detail[-3500:]}"
|
|
93
|
-
message = message.replace("%", "%25").replace("\r", "%0D").replace("\n", "%0A")
|
|
94
|
-
print(f"::error::{message}")
|