skilltest-pytest 0.1.0__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.
- skilltest_pytest-0.1.0/.gitignore +31 -0
- skilltest_pytest-0.1.0/PKG-INFO +58 -0
- skilltest_pytest-0.1.0/README.md +47 -0
- skilltest_pytest-0.1.0/project.json +43 -0
- skilltest_pytest-0.1.0/pyproject.toml +42 -0
- skilltest_pytest-0.1.0/skilltest_pytest/__init__.py +70 -0
- skilltest_pytest-0.1.0/skilltest_pytest/plugin.py +86 -0
- skilltest_pytest-0.1.0/tests/collected/greet.skilltest.yaml +9 -0
- skilltest_pytest-0.1.0/tests/collected/greeter/SKILL.md +9 -0
- skilltest_pytest-0.1.0/tests/conftest.py +51 -0
- skilltest_pytest-0.1.0/tests/test_plugin.py +77 -0
- skilltest_pytest-0.1.0/uv.lock +280 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Rust
|
|
2
|
+
/target
|
|
3
|
+
**/*.rs.bk
|
|
4
|
+
|
|
5
|
+
# Python
|
|
6
|
+
.venv/
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.pyc
|
|
9
|
+
.pytest_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
dist/
|
|
12
|
+
*.egg-info/
|
|
13
|
+
|
|
14
|
+
# Node / TypeScript
|
|
15
|
+
node_modules/
|
|
16
|
+
*.tsbuildinfo
|
|
17
|
+
|
|
18
|
+
# Nx
|
|
19
|
+
.nx/cache
|
|
20
|
+
.nx/workspace-data
|
|
21
|
+
|
|
22
|
+
# Editors / OS
|
|
23
|
+
.DS_Store
|
|
24
|
+
*.swp
|
|
25
|
+
|
|
26
|
+
# Secrets: never commit these. `gh-secrets manifest sync` writes the real harness
|
|
27
|
+
# auth tokens into .env (and tracks push state in .gh-secrets-state.json). The
|
|
28
|
+
# manifest (gh-secrets.json) is committed; the resolved values are not.
|
|
29
|
+
.env
|
|
30
|
+
.env.local
|
|
31
|
+
.gh-secrets-state.json
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: skilltest-pytest
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: pytest integration for skilltest: auto-collect *.skilltest.yaml cases as pytest tests, built on skilltest-sdk.
|
|
5
|
+
Author: Nick DeRobertis
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Requires-Dist: pytest>=8
|
|
9
|
+
Requires-Dist: skilltest-sdk==0.1.0
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# skilltest-pytest
|
|
13
|
+
|
|
14
|
+
A [pytest](https://pytest.org) plugin for [skilltest](../../README.md): run
|
|
15
|
+
AI-skill tests and natural-language evals as ordinary pytest tests, and mix in
|
|
16
|
+
your own deterministic checks. Built on
|
|
17
|
+
[`skilltest-sdk`](../../sdks/python/README.md) — the SDK's code API is
|
|
18
|
+
re-exported here, so a pytest suite needs only this one dependency.
|
|
19
|
+
|
|
20
|
+
## Two ways to use it
|
|
21
|
+
|
|
22
|
+
**Auto-collected case files.** Name a case `something.skilltest.yaml` and pytest
|
|
23
|
+
runs it:
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
# greet.skilltest.yaml
|
|
27
|
+
skill: ./skills/greeter
|
|
28
|
+
input: "Greet Dr. Smith."
|
|
29
|
+
evals:
|
|
30
|
+
- type: boolean
|
|
31
|
+
criterion: "the reply greets Dr. Smith by name"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**As code**, for matrices and deterministic mix-ins:
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from skilltest_pytest import run_skill
|
|
38
|
+
|
|
39
|
+
def test_greeter():
|
|
40
|
+
report = run_skill("cases/greet.yaml", platforms=["claude-code"], models=["claude-opus-4-8"])
|
|
41
|
+
assert report.passed, report.describe_failures()
|
|
42
|
+
assert "Dr. Smith" in report.runs[0].transcript.assistant_text()
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
The plugin shells out to the `skilltest` binary. Point it at one with the
|
|
48
|
+
`SKILLTEST_BIN` env var (or `bin=`), the provider with `SKILLTEST_PROVIDER` (or
|
|
49
|
+
`provider=`), and set defaults in `pyproject.toml`:
|
|
50
|
+
|
|
51
|
+
```toml
|
|
52
|
+
[tool.pytest.ini_options]
|
|
53
|
+
skilltest_provider = "oneharness"
|
|
54
|
+
skilltest_platforms = ["claude-code"]
|
|
55
|
+
skilltest_models = ["claude-opus-4-8"]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
See the repository root for the provider protocol and the full schema.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# skilltest-pytest
|
|
2
|
+
|
|
3
|
+
A [pytest](https://pytest.org) plugin for [skilltest](../../README.md): run
|
|
4
|
+
AI-skill tests and natural-language evals as ordinary pytest tests, and mix in
|
|
5
|
+
your own deterministic checks. Built on
|
|
6
|
+
[`skilltest-sdk`](../../sdks/python/README.md) — the SDK's code API is
|
|
7
|
+
re-exported here, so a pytest suite needs only this one dependency.
|
|
8
|
+
|
|
9
|
+
## Two ways to use it
|
|
10
|
+
|
|
11
|
+
**Auto-collected case files.** Name a case `something.skilltest.yaml` and pytest
|
|
12
|
+
runs it:
|
|
13
|
+
|
|
14
|
+
```yaml
|
|
15
|
+
# greet.skilltest.yaml
|
|
16
|
+
skill: ./skills/greeter
|
|
17
|
+
input: "Greet Dr. Smith."
|
|
18
|
+
evals:
|
|
19
|
+
- type: boolean
|
|
20
|
+
criterion: "the reply greets Dr. Smith by name"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**As code**, for matrices and deterministic mix-ins:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from skilltest_pytest import run_skill
|
|
27
|
+
|
|
28
|
+
def test_greeter():
|
|
29
|
+
report = run_skill("cases/greet.yaml", platforms=["claude-code"], models=["claude-opus-4-8"])
|
|
30
|
+
assert report.passed, report.describe_failures()
|
|
31
|
+
assert "Dr. Smith" in report.runs[0].transcript.assistant_text()
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Configuration
|
|
35
|
+
|
|
36
|
+
The plugin shells out to the `skilltest` binary. Point it at one with the
|
|
37
|
+
`SKILLTEST_BIN` env var (or `bin=`), the provider with `SKILLTEST_PROVIDER` (or
|
|
38
|
+
`provider=`), and set defaults in `pyproject.toml`:
|
|
39
|
+
|
|
40
|
+
```toml
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
skilltest_provider = "oneharness"
|
|
43
|
+
skilltest_platforms = ["claude-code"]
|
|
44
|
+
skilltest_models = ["claude-opus-4-8"]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
See the repository root for the provider protocol and the full schema.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
3
|
+
"name": "skilltest-pytest",
|
|
4
|
+
"projectType": "library",
|
|
5
|
+
"implicitDependencies": ["skilltest-sdk"],
|
|
6
|
+
"targets": {
|
|
7
|
+
"lint": {
|
|
8
|
+
"executor": "nx:run-commands",
|
|
9
|
+
"options": {
|
|
10
|
+
"command": "uv run ruff check .",
|
|
11
|
+
"cwd": "{projectRoot}"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"format-check": {
|
|
15
|
+
"executor": "nx:run-commands",
|
|
16
|
+
"options": {
|
|
17
|
+
"command": "uv run ruff format --check .",
|
|
18
|
+
"cwd": "{projectRoot}"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"format": {
|
|
22
|
+
"executor": "nx:run-commands",
|
|
23
|
+
"options": {
|
|
24
|
+
"command": "uv run ruff format .",
|
|
25
|
+
"cwd": "{projectRoot}"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"typecheck": {
|
|
29
|
+
"executor": "nx:run-commands",
|
|
30
|
+
"options": {
|
|
31
|
+
"command": "uv run ty check",
|
|
32
|
+
"cwd": "{projectRoot}"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"test-e2e": {
|
|
36
|
+
"executor": "nx:run-commands",
|
|
37
|
+
"options": {
|
|
38
|
+
"command": "SKILLTEST_BIN=\"$PWD/../../target/debug/skilltest\" SKILLTEST_PROVIDER=\"$PWD/../../target/debug/skilltest-fake-provider\" uv run pytest",
|
|
39
|
+
"cwd": "{projectRoot}"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "skilltest-pytest"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "pytest integration for skilltest: auto-collect *.skilltest.yaml cases as pytest tests, built on skilltest-sdk."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
authors = [{ name = "Nick DeRobertis" }]
|
|
9
|
+
dependencies = [
|
|
10
|
+
"skilltest-sdk==0.1.0",
|
|
11
|
+
"pytest>=8",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.entry-points.pytest11]
|
|
15
|
+
skilltest = "skilltest_pytest.plugin"
|
|
16
|
+
|
|
17
|
+
[dependency-groups]
|
|
18
|
+
dev = [
|
|
19
|
+
"ruff>=0.6",
|
|
20
|
+
"ty>=0.0.1a1",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[tool.uv.sources]
|
|
24
|
+
skilltest-sdk = { path = "../../sdks/python", editable = true }
|
|
25
|
+
|
|
26
|
+
[build-system]
|
|
27
|
+
requires = ["hatchling"]
|
|
28
|
+
build-backend = "hatchling.build"
|
|
29
|
+
|
|
30
|
+
[tool.hatch.build.targets.wheel]
|
|
31
|
+
packages = ["skilltest_pytest"]
|
|
32
|
+
|
|
33
|
+
[tool.ruff]
|
|
34
|
+
line-length = 100
|
|
35
|
+
target-version = "py312"
|
|
36
|
+
|
|
37
|
+
[tool.ruff.lint]
|
|
38
|
+
select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]
|
|
39
|
+
|
|
40
|
+
[tool.pytest.ini_options]
|
|
41
|
+
addopts = "-q"
|
|
42
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""skilltest-pytest: run AI-skill tests and natural-language evals as pytest.
|
|
2
|
+
|
|
3
|
+
The pytest integration on top of [`skilltest-sdk`][skilltest_sdk]: drop a
|
|
4
|
+
``*.skilltest.yaml`` next to your other tests and pytest collects it as a test
|
|
5
|
+
item. The SDK's code-level API is re-exported here for convenience, so a pytest
|
|
6
|
+
suite only needs one dependency:
|
|
7
|
+
|
|
8
|
+
from skilltest_pytest import run_skill, validate_skill
|
|
9
|
+
|
|
10
|
+
def test_greeter():
|
|
11
|
+
report = run_skill("cases/greet.yaml")
|
|
12
|
+
assert report.passed, describe_failures(report)
|
|
13
|
+
# Mix in a deterministic check on the transcript:
|
|
14
|
+
assert "Dr. Smith" in assistant_text(report.runs[0].transcript)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from skilltest_sdk import (
|
|
20
|
+
ENV_BIN,
|
|
21
|
+
ENV_PROVIDER,
|
|
22
|
+
BooleanDetail,
|
|
23
|
+
CaseRun,
|
|
24
|
+
EvalOutcome,
|
|
25
|
+
Message,
|
|
26
|
+
NumericDetail,
|
|
27
|
+
Report,
|
|
28
|
+
SkilltestError,
|
|
29
|
+
SkilltestProviderError,
|
|
30
|
+
SkilltestUsageError,
|
|
31
|
+
Summary,
|
|
32
|
+
Transcript,
|
|
33
|
+
Usage,
|
|
34
|
+
ValidationFinding,
|
|
35
|
+
ValidationReport,
|
|
36
|
+
assistant_text,
|
|
37
|
+
describe_failures,
|
|
38
|
+
failed_evals,
|
|
39
|
+
failed_runs,
|
|
40
|
+
run_skill,
|
|
41
|
+
validate_skill,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
from .plugin import SkilltestFailure
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
"ENV_BIN",
|
|
48
|
+
"ENV_PROVIDER",
|
|
49
|
+
"BooleanDetail",
|
|
50
|
+
"CaseRun",
|
|
51
|
+
"EvalOutcome",
|
|
52
|
+
"Message",
|
|
53
|
+
"NumericDetail",
|
|
54
|
+
"Report",
|
|
55
|
+
"SkilltestError",
|
|
56
|
+
"SkilltestFailure",
|
|
57
|
+
"SkilltestProviderError",
|
|
58
|
+
"SkilltestUsageError",
|
|
59
|
+
"Summary",
|
|
60
|
+
"Transcript",
|
|
61
|
+
"Usage",
|
|
62
|
+
"ValidationFinding",
|
|
63
|
+
"ValidationReport",
|
|
64
|
+
"assistant_text",
|
|
65
|
+
"describe_failures",
|
|
66
|
+
"failed_evals",
|
|
67
|
+
"failed_runs",
|
|
68
|
+
"run_skill",
|
|
69
|
+
"validate_skill",
|
|
70
|
+
]
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""pytest integration: collect ``*.skilltest.yaml`` files as test items.
|
|
2
|
+
|
|
3
|
+
Drop a ``greets.skilltest.yaml`` next to your other tests and `pytest` will run
|
|
4
|
+
it as a case, failing with the judge's reasons when an eval does not pass. For
|
|
5
|
+
finer control — multiple platforms/models, or deterministic mix-in assertions on
|
|
6
|
+
the transcript — call [`run_skill`][skilltest_sdk.runner.run_skill] from an
|
|
7
|
+
ordinary test function instead.
|
|
8
|
+
|
|
9
|
+
Settings come from ``pytest.ini``/``pyproject.toml`` (``skilltest_bin``,
|
|
10
|
+
``skilltest_provider``, ``skilltest_platforms``, ``skilltest_models``,
|
|
11
|
+
``skilltest_config``) or the ``SKILLTEST_BIN`` / ``SKILLTEST_PROVIDER`` env vars.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import TYPE_CHECKING
|
|
17
|
+
|
|
18
|
+
import pytest
|
|
19
|
+
from skilltest_sdk import Report, describe_failures, run_skill
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from collections.abc import Sequence
|
|
23
|
+
|
|
24
|
+
_SUFFIXES = (".skilltest.yaml", ".skilltest.yml")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def pytest_addoption(parser: pytest.Parser) -> None:
|
|
28
|
+
parser.addini("skilltest_bin", "Path to the skilltest binary", default=None)
|
|
29
|
+
parser.addini("skilltest_provider", "Provider command for skilltest", default=None)
|
|
30
|
+
parser.addini("skilltest_platforms", "Platforms to run cases on", type="args", default=[])
|
|
31
|
+
parser.addini("skilltest_models", "Models to run cases on", type="args", default=[])
|
|
32
|
+
parser.addini("skilltest_config", "Path to a skilltest config file", default=None)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def pytest_collect_file(parent: pytest.Collector, file_path) -> SkilltestFile | None:
|
|
36
|
+
name = file_path.name
|
|
37
|
+
if any(name.endswith(suffix) for suffix in _SUFFIXES):
|
|
38
|
+
return SkilltestFile.from_parent(parent, path=file_path)
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class _Settings:
|
|
43
|
+
"""Resolved collector settings, read once from the pytest config."""
|
|
44
|
+
|
|
45
|
+
def __init__(self, config: pytest.Config) -> None:
|
|
46
|
+
self.bin: str | None = config.getini("skilltest_bin") or None
|
|
47
|
+
self.provider: str | None = config.getini("skilltest_provider") or None
|
|
48
|
+
self.platforms: Sequence[str] = config.getini("skilltest_platforms")
|
|
49
|
+
self.models: Sequence[str] = config.getini("skilltest_models")
|
|
50
|
+
self.config: str | None = config.getini("skilltest_config") or None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class SkilltestFailure(Exception):
|
|
54
|
+
"""Raised when a collected case fails, carrying the report for reporting."""
|
|
55
|
+
|
|
56
|
+
def __init__(self, report: Report) -> None:
|
|
57
|
+
super().__init__(describe_failures(report))
|
|
58
|
+
self.report = report
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class SkilltestFile(pytest.File):
|
|
62
|
+
def collect(self): # type: ignore[override]
|
|
63
|
+
yield SkilltestItem.from_parent(self, name=self.path.stem)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class SkilltestItem(pytest.Item):
|
|
67
|
+
def runtest(self) -> None:
|
|
68
|
+
settings = _Settings(self.config)
|
|
69
|
+
report = run_skill(
|
|
70
|
+
self.path,
|
|
71
|
+
bin=settings.bin,
|
|
72
|
+
provider=settings.provider,
|
|
73
|
+
platforms=settings.platforms,
|
|
74
|
+
models=settings.models,
|
|
75
|
+
config=settings.config,
|
|
76
|
+
)
|
|
77
|
+
if not report.passed:
|
|
78
|
+
raise SkilltestFailure(report)
|
|
79
|
+
|
|
80
|
+
def repr_failure(self, excinfo, style=None): # type: ignore[override]
|
|
81
|
+
if isinstance(excinfo.value, SkilltestFailure):
|
|
82
|
+
return f"skilltest case failed:\n{excinfo.value}"
|
|
83
|
+
return super().repr_failure(excinfo, style=style)
|
|
84
|
+
|
|
85
|
+
def reportinfo(self): # type: ignore[override]
|
|
86
|
+
return self.path, 0, f"skilltest: {self.name}"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Auto-collected by the skilltest pytest plugin: running `pytest` turns this file
|
|
2
|
+
# into a test item. Provider/binary come from the env defaults in conftest.py.
|
|
3
|
+
name: collected_greet
|
|
4
|
+
skill: ./greeter
|
|
5
|
+
input: "Greet Dr. Smith."
|
|
6
|
+
evals:
|
|
7
|
+
- type: boolean
|
|
8
|
+
name: names-the-patient
|
|
9
|
+
criterion: "the reply greets `Dr. Smith` by name"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Shared test setup: point the plugin at the locally built Rust binaries.
|
|
2
|
+
|
|
3
|
+
These tests exercise the *real* `skilltest` binary and the deterministic
|
|
4
|
+
`skilltest-fake-provider`, both built by `cargo build` (run via `just bootstrap`
|
|
5
|
+
/ `just check` before the Python suite). Only the model is faked.
|
|
6
|
+
|
|
7
|
+
`pytester` is enabled so the suite can run the collector end-to-end in a child
|
|
8
|
+
pytest process and assert on its outcome — including failures, which cannot be
|
|
9
|
+
asserted from inside the same run.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
pytest_plugins = ["pytester"]
|
|
20
|
+
|
|
21
|
+
REPO_ROOT = Path(__file__).resolve().parents[3]
|
|
22
|
+
TARGET = REPO_ROOT / "target" / "debug"
|
|
23
|
+
SKILLTEST_BIN = TARGET / "skilltest"
|
|
24
|
+
FAKE_PROVIDER = TARGET / "skilltest-fake-provider"
|
|
25
|
+
FIXTURES = REPO_ROOT / "tests" / "fixtures"
|
|
26
|
+
|
|
27
|
+
# Defaults so the collector (and the child pytest runs) find the binary and
|
|
28
|
+
# provider without per-call wiring.
|
|
29
|
+
os.environ.setdefault("SKILLTEST_BIN", str(SKILLTEST_BIN))
|
|
30
|
+
os.environ.setdefault("SKILLTEST_PROVIDER", str(FAKE_PROVIDER))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.fixture(scope="session", autouse=True)
|
|
34
|
+
def _require_binaries() -> None:
|
|
35
|
+
missing = [p for p in (SKILLTEST_BIN, FAKE_PROVIDER) if not p.exists()]
|
|
36
|
+
if missing:
|
|
37
|
+
names = ", ".join(str(p) for p in missing)
|
|
38
|
+
pytest.fail(
|
|
39
|
+
f"built binaries not found: {names}. Run `just bootstrap` (cargo build) first.",
|
|
40
|
+
pytrace=False,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@pytest.fixture
|
|
45
|
+
def fixtures() -> Path:
|
|
46
|
+
return FIXTURES
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@pytest.fixture
|
|
50
|
+
def cases(fixtures: Path) -> Path:
|
|
51
|
+
return fixtures / "cases"
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""E2e tests for the pytest integration.
|
|
2
|
+
|
|
3
|
+
The happy path of auto-collection is also exercised by `collected/`
|
|
4
|
+
(`greet.skilltest.yaml` runs as part of this very suite); the `pytester` tests
|
|
5
|
+
here drive a *child* pytest end-to-end so the failure path — a collected case
|
|
6
|
+
whose eval fails — can be asserted on too.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import pytest
|
|
14
|
+
|
|
15
|
+
from skilltest_pytest import describe_failures, run_skill
|
|
16
|
+
|
|
17
|
+
SKILL_MD = """\
|
|
18
|
+
---
|
|
19
|
+
name: greeter
|
|
20
|
+
description: A local greeter skill used to exercise pytest auto-collection.
|
|
21
|
+
---
|
|
22
|
+
# Greeter
|
|
23
|
+
|
|
24
|
+
Greet the user by name.
|
|
25
|
+
|
|
26
|
+
<!-- fake-reply: Hello, Dr. Smith! Welcome to the clinic. -->
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def write_skill(root: Path) -> None:
|
|
31
|
+
skill = root / "greeter"
|
|
32
|
+
skill.mkdir()
|
|
33
|
+
(skill / "SKILL.md").write_text(SKILL_MD)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_sdk_api_is_reexported_and_works(cases: Path) -> None:
|
|
37
|
+
# One dependency is enough for a pytest suite: the SDK's code-level API is
|
|
38
|
+
# available straight from skilltest_pytest.
|
|
39
|
+
report = run_skill(cases / "greet_pass.yaml")
|
|
40
|
+
assert report.passed, describe_failures(report)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_collected_case_passes(pytester: pytest.Pytester) -> None:
|
|
44
|
+
write_skill(pytester.path)
|
|
45
|
+
pytester.makefile(
|
|
46
|
+
".skilltest.yaml",
|
|
47
|
+
greet="""
|
|
48
|
+
name: collected_greet
|
|
49
|
+
skill: ./greeter
|
|
50
|
+
input: "Greet Dr. Smith."
|
|
51
|
+
evals:
|
|
52
|
+
- type: boolean
|
|
53
|
+
name: names-the-patient
|
|
54
|
+
criterion: "the reply greets `Dr. Smith` by name"
|
|
55
|
+
""",
|
|
56
|
+
)
|
|
57
|
+
result = pytester.runpytest_subprocess()
|
|
58
|
+
result.assert_outcomes(passed=1)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_collected_case_failure_reports_judge_reason(pytester: pytest.Pytester) -> None:
|
|
62
|
+
write_skill(pytester.path)
|
|
63
|
+
pytester.makefile(
|
|
64
|
+
".skilltest.yaml",
|
|
65
|
+
farewell="""
|
|
66
|
+
name: collected_farewell
|
|
67
|
+
skill: ./greeter
|
|
68
|
+
input: "Greet Dr. Smith."
|
|
69
|
+
evals:
|
|
70
|
+
- type: boolean
|
|
71
|
+
name: says-goodbye
|
|
72
|
+
criterion: "the reply contains a `goodbye`"
|
|
73
|
+
""",
|
|
74
|
+
)
|
|
75
|
+
result = pytester.runpytest_subprocess()
|
|
76
|
+
result.assert_outcomes(failed=1)
|
|
77
|
+
result.stdout.fnmatch_lines(["*skilltest case failed:*", "*says-goodbye*"])
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
version = 1
|
|
2
|
+
revision = 3
|
|
3
|
+
requires-python = ">=3.12"
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "annotated-types"
|
|
7
|
+
version = "0.7.0"
|
|
8
|
+
source = { registry = "https://pypi.org/simple" }
|
|
9
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
|
|
10
|
+
wheels = [
|
|
11
|
+
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[[package]]
|
|
15
|
+
name = "colorama"
|
|
16
|
+
version = "0.4.6"
|
|
17
|
+
source = { registry = "https://pypi.org/simple" }
|
|
18
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
|
19
|
+
wheels = [
|
|
20
|
+
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[[package]]
|
|
24
|
+
name = "iniconfig"
|
|
25
|
+
version = "2.3.0"
|
|
26
|
+
source = { registry = "https://pypi.org/simple" }
|
|
27
|
+
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
|
28
|
+
wheels = [
|
|
29
|
+
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[[package]]
|
|
33
|
+
name = "packaging"
|
|
34
|
+
version = "26.2"
|
|
35
|
+
source = { registry = "https://pypi.org/simple" }
|
|
36
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" }
|
|
37
|
+
wheels = [
|
|
38
|
+
{ url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" },
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[[package]]
|
|
42
|
+
name = "pluggy"
|
|
43
|
+
version = "1.6.0"
|
|
44
|
+
source = { registry = "https://pypi.org/simple" }
|
|
45
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
|
46
|
+
wheels = [
|
|
47
|
+
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[[package]]
|
|
51
|
+
name = "pydantic"
|
|
52
|
+
version = "2.13.4"
|
|
53
|
+
source = { registry = "https://pypi.org/simple" }
|
|
54
|
+
dependencies = [
|
|
55
|
+
{ name = "annotated-types" },
|
|
56
|
+
{ name = "pydantic-core" },
|
|
57
|
+
{ name = "typing-extensions" },
|
|
58
|
+
{ name = "typing-inspection" },
|
|
59
|
+
]
|
|
60
|
+
sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" }
|
|
61
|
+
wheels = [
|
|
62
|
+
{ url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" },
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
[[package]]
|
|
66
|
+
name = "pydantic-core"
|
|
67
|
+
version = "2.46.4"
|
|
68
|
+
source = { registry = "https://pypi.org/simple" }
|
|
69
|
+
dependencies = [
|
|
70
|
+
{ name = "typing-extensions" },
|
|
71
|
+
]
|
|
72
|
+
sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" }
|
|
73
|
+
wheels = [
|
|
74
|
+
{ url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" },
|
|
75
|
+
{ url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" },
|
|
76
|
+
{ url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" },
|
|
77
|
+
{ url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" },
|
|
78
|
+
{ url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" },
|
|
79
|
+
{ url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" },
|
|
80
|
+
{ url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" },
|
|
81
|
+
{ url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" },
|
|
82
|
+
{ url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" },
|
|
83
|
+
{ url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" },
|
|
84
|
+
{ url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" },
|
|
85
|
+
{ url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" },
|
|
86
|
+
{ url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" },
|
|
87
|
+
{ url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" },
|
|
88
|
+
{ url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" },
|
|
89
|
+
{ url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" },
|
|
90
|
+
{ url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" },
|
|
91
|
+
{ url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" },
|
|
92
|
+
{ url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" },
|
|
93
|
+
{ url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" },
|
|
94
|
+
{ url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" },
|
|
95
|
+
{ url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" },
|
|
96
|
+
{ url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" },
|
|
97
|
+
{ url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" },
|
|
98
|
+
{ url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" },
|
|
99
|
+
{ url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" },
|
|
100
|
+
{ url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" },
|
|
101
|
+
{ url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" },
|
|
102
|
+
{ url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" },
|
|
103
|
+
{ url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" },
|
|
104
|
+
{ url = "https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb", size = 2102079, upload-time = "2026-05-06T13:38:41.019Z" },
|
|
105
|
+
{ url = "https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462", size = 1952179, upload-time = "2026-05-06T13:36:59.812Z" },
|
|
106
|
+
{ url = "https://files.pythonhosted.org/packages/95/30/5211a831ae054928054b2f79731661087a2bc5c01e825c672b3a4a8f1b3e/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9", size = 1978926, upload-time = "2026-05-06T13:37:39.933Z" },
|
|
107
|
+
{ url = "https://files.pythonhosted.org/packages/57/e9/689668733b1eb67adeef047db3c2e8788fcf65a7fd9c9e2b46b7744fe245/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4", size = 2046785, upload-time = "2026-05-06T13:38:01.995Z" },
|
|
108
|
+
{ url = "https://files.pythonhosted.org/packages/60/d9/6715260422ff50a2109878fd24d948a6c3446bb2664f34ee78cd972b3acd/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914", size = 2228733, upload-time = "2026-05-06T13:40:50.371Z" },
|
|
109
|
+
{ url = "https://files.pythonhosted.org/packages/18/ae/fdb2f64316afca925640f8e70bb1a564b0ec2721c1389e25b8eb4bf9a299/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28", size = 2307534, upload-time = "2026-05-06T13:37:21.531Z" },
|
|
110
|
+
{ url = "https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b", size = 2099732, upload-time = "2026-05-06T13:39:31.942Z" },
|
|
111
|
+
{ url = "https://files.pythonhosted.org/packages/06/d5/ee5a3366637fee41dee51a1fc91562dcf12ddbc68fda34e6b253da2324bb/pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c", size = 2129627, upload-time = "2026-05-06T13:37:25.033Z" },
|
|
112
|
+
{ url = "https://files.pythonhosted.org/packages/94/33/2414be571d2c6a6c4d08be21f9292b6d3fdb08949a97b6dfe985017821db/pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb", size = 2179141, upload-time = "2026-05-06T13:37:14.046Z" },
|
|
113
|
+
{ url = "https://files.pythonhosted.org/packages/7b/79/7daa95be995be0eecc4cf75064cb33f9bbbfe3fe0158caf2f0d4a996a5c7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898", size = 2184325, upload-time = "2026-05-06T13:36:53.615Z" },
|
|
114
|
+
{ url = "https://files.pythonhosted.org/packages/9f/cb/d0a382f5c0de8a222dc61c65348e0ce831b1f68e0a018450d31c2cace3a5/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e", size = 2323990, upload-time = "2026-05-06T13:40:29.971Z" },
|
|
115
|
+
{ url = "https://files.pythonhosted.org/packages/05/db/d9ba624cc4a5aced1598e88c04fdbd8310c8a69b9d38b9a3d39ce3a61ed7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519", size = 2369978, upload-time = "2026-05-06T13:37:23.027Z" },
|
|
116
|
+
{ url = "https://files.pythonhosted.org/packages/f2/20/d15df15ba918c423461905802bfd2981c3af0bfa0e40d05e13edbfa48bc3/pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4", size = 1966354, upload-time = "2026-05-06T13:38:03.499Z" },
|
|
117
|
+
{ url = "https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac", size = 2072238, upload-time = "2026-05-06T13:39:40.807Z" },
|
|
118
|
+
{ url = "https://files.pythonhosted.org/packages/32/36/51eb763beec1f4cf59b1db243a7dcc39cbb41230f050a09b9d69faaf0a48/pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a", size = 2018251, upload-time = "2026-05-06T13:37:26.72Z" },
|
|
119
|
+
{ url = "https://files.pythonhosted.org/packages/e8/91/855af51d625b23aa987116a19e231d2aaef9c4a415273ddc189b79a45fee/pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0", size = 2099593, upload-time = "2026-05-06T13:39:47.682Z" },
|
|
120
|
+
{ url = "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d", size = 1935226, upload-time = "2026-05-06T13:40:40.428Z" },
|
|
121
|
+
{ url = "https://files.pythonhosted.org/packages/e8/e7/1955d28d1afc56dd4b3ad7cc0cf39df1b9852964cf16e5d13912756d6d6b/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b", size = 1974605, upload-time = "2026-05-06T13:37:32.029Z" },
|
|
122
|
+
{ url = "https://files.pythonhosted.org/packages/93/e2/3fedbf0ba7a22850e6e9fd78117f1c0f10f950182344d8a6c535d468fdd8/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000", size = 2030777, upload-time = "2026-05-06T13:38:55.239Z" },
|
|
123
|
+
{ url = "https://files.pythonhosted.org/packages/f8/61/46be275fcaaba0b4f5b9669dd852267ce1ff616592dccf7a7845588df091/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e", size = 2236641, upload-time = "2026-05-06T13:37:08.096Z" },
|
|
124
|
+
{ url = "https://files.pythonhosted.org/packages/60/db/12e93e46a8bac9988be3c016860f83293daea8c716c029c9ace279036f2f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd", size = 2286404, upload-time = "2026-05-06T13:40:20.221Z" },
|
|
125
|
+
{ url = "https://files.pythonhosted.org/packages/e2/4a/4d8b19008f38d31c53b8219cfedc2e3d5de5fe99d90076b7e767de29274f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3", size = 2109219, upload-time = "2026-05-06T13:38:12.153Z" },
|
|
126
|
+
{ url = "https://files.pythonhosted.org/packages/88/70/3cbc40978fefb7bb09c6708d40d4ad1a5d70fd7213c3d17f971de868ec1f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7", size = 2110594, upload-time = "2026-05-06T13:40:02.971Z" },
|
|
127
|
+
{ url = "https://files.pythonhosted.org/packages/9d/20/b8d36736216e29491125531685b2f9e61aa5b4b2599893f8268551da3338/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff", size = 2159542, upload-time = "2026-05-06T13:39:27.506Z" },
|
|
128
|
+
{ url = "https://files.pythonhosted.org/packages/1d/a2/367df868eb584dacf6bf82a389272406d7178e301c4ac82545ab98bc2dd9/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424", size = 2168146, upload-time = "2026-05-06T13:38:31.93Z" },
|
|
129
|
+
{ url = "https://files.pythonhosted.org/packages/c1/b8/4460f77f7e201893f649a29ab355dddd3beee8a97bcb1a320db414f9a06e/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6", size = 2306309, upload-time = "2026-05-06T13:37:44.717Z" },
|
|
130
|
+
{ url = "https://files.pythonhosted.org/packages/64/c4/be2639293acd87dc8ddbcec41a73cee9b2ebf996fe6d892a1a74e88ad3f7/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565", size = 2369736, upload-time = "2026-05-06T13:37:05.645Z" },
|
|
131
|
+
{ url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575, upload-time = "2026-05-06T13:38:51.116Z" },
|
|
132
|
+
{ url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624, upload-time = "2026-05-06T13:38:21.672Z" },
|
|
133
|
+
{ url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325, upload-time = "2026-05-06T13:40:52.723Z" },
|
|
134
|
+
{ url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" },
|
|
135
|
+
{ url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" },
|
|
136
|
+
{ url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" },
|
|
137
|
+
{ url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" },
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
[[package]]
|
|
141
|
+
name = "pygments"
|
|
142
|
+
version = "2.20.0"
|
|
143
|
+
source = { registry = "https://pypi.org/simple" }
|
|
144
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
|
|
145
|
+
wheels = [
|
|
146
|
+
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
[[package]]
|
|
150
|
+
name = "pytest"
|
|
151
|
+
version = "9.0.3"
|
|
152
|
+
source = { registry = "https://pypi.org/simple" }
|
|
153
|
+
dependencies = [
|
|
154
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
155
|
+
{ name = "iniconfig" },
|
|
156
|
+
{ name = "packaging" },
|
|
157
|
+
{ name = "pluggy" },
|
|
158
|
+
{ name = "pygments" },
|
|
159
|
+
]
|
|
160
|
+
sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" }
|
|
161
|
+
wheels = [
|
|
162
|
+
{ url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" },
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
[[package]]
|
|
166
|
+
name = "ruff"
|
|
167
|
+
version = "0.15.17"
|
|
168
|
+
source = { registry = "https://pypi.org/simple" }
|
|
169
|
+
sdist = { url = "https://files.pythonhosted.org/packages/8c/a9/3abdf488f1bf3d24c699415e454ed554a6350d5d89ce183be1ee0a3361ac/ruff-0.15.17.tar.gz", hash = "sha256:2ec446937fd16c8c4de2674a209cc5af64d9c6f17d21fbf1151054fa0bcf5219", size = 4743346, upload-time = "2026-06-11T17:54:47.663Z" }
|
|
170
|
+
wheels = [
|
|
171
|
+
{ url = "https://files.pythonhosted.org/packages/db/4d/e11259f5da07cb6afb2d074c31bf09da9671993f7329d4f15d2fdc458301/ruff-0.15.17-py3-none-linux_armv6l.whl", hash = "sha256:d9feddb927fc68bd295f5eebc587a7e42cfaf9b65f60ca4a2386febff575da8f", size = 10856677, upload-time = "2026-06-11T17:54:49.533Z" },
|
|
172
|
+
{ url = "https://files.pythonhosted.org/packages/29/3e/772d679e1a0dc058e58875bd2c0cb713a0530877b4a76fee3c7966df0d49/ruff-0.15.17-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:25805a226d741c47d274a35ad5c10a7dde175fcddfa511d7cf3da0a21eb3eab7", size = 11223443, upload-time = "2026-06-11T17:55:00.573Z" },
|
|
173
|
+
{ url = "https://files.pythonhosted.org/packages/68/58/bd41f7688b2fd5623012605130ed70e60aa7f2244baa3d5066bdd61530c8/ruff-0.15.17-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f6ad73b14c2d18a3bf8ad7cb6974294d7f613a7898604826058e6ac64918ef4d", size = 10566458, upload-time = "2026-06-11T17:55:07.52Z" },
|
|
174
|
+
{ url = "https://files.pythonhosted.org/packages/d8/5b/733371013fcf1ec339e477ece6ab42bfe10bdd9bba8ee88a9516aa56bfc0/ruff-0.15.17-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ba0c1e4f95bcb3869d0d30cbd5917071ef2e28665abfec970cdab0492c713ed", size = 10914483, upload-time = "2026-06-11T17:55:05.501Z" },
|
|
175
|
+
{ url = "https://files.pythonhosted.org/packages/bd/cc/6f24251cc0252f7239391ccb85833f320efad14ebe5b443943f37ced6332/ruff-0.15.17-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81647960f10bff57d2e51cadd0c3950fe598400c852863a038720ef5b8cca91e", size = 10647497, upload-time = "2026-06-11T17:54:57.733Z" },
|
|
176
|
+
{ url = "https://files.pythonhosted.org/packages/68/dd/0d10c17ce1a1624d6fc3156309c3f834fdb5dfaad026ec90c85684f3990e/ruff-0.15.17-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e01a84ddbc8c16c23055ba3924476850f1bbc1917cebbb9376665a63e74260d", size = 11416967, upload-time = "2026-06-11T17:54:51.461Z" },
|
|
177
|
+
{ url = "https://files.pythonhosted.org/packages/2f/91/556bfb156f6144f355e831c23db00b2fc4120f86b3ce81cc5f7fd2df51f3/ruff-0.15.17-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fe9f653152f8f294f9f7e03bf3a453d8b4a27f7a59c78c8666167f2b17b96c", size = 12335770, upload-time = "2026-06-11T17:54:45.793Z" },
|
|
178
|
+
{ url = "https://files.pythonhosted.org/packages/88/82/8b5999aa13355e926f06d9f42a32dcca862f623bf0363785ff89d607dffd/ruff-0.15.17-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c0fe88a7676e7a05b73174d4d4a59cb2ac21ff8263583f87a81a6018475a978", size = 11575441, upload-time = "2026-06-11T17:54:32.661Z" },
|
|
179
|
+
{ url = "https://files.pythonhosted.org/packages/11/93/f10377bb04109ca0e8cbc483ff1982c54b6d418210041776f93e8cdc7fa9/ruff-0.15.17-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecfc3c7878fff94633ab0348524e093f9ce3243080416dd7d14f8ba400174719", size = 11557614, upload-time = "2026-06-11T17:54:34.698Z" },
|
|
180
|
+
{ url = "https://files.pythonhosted.org/packages/c7/a6/eeeae7f7d5493df41649ab3db92f086b2d0a30199e4efdf8e3dd7a033f24/ruff-0.15.17-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:b8461180b22420b1bdc289909410930761629fddf2a5aaf60fae1ab26cedc4c4", size = 11544450, upload-time = "2026-06-11T17:54:39.042Z" },
|
|
181
|
+
{ url = "https://files.pythonhosted.org/packages/32/88/5991ce565129a24dd4a00db1254b3b5db2e53018cbe4018ea5a89738e727/ruff-0.15.17-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6eccbe50a038b503e7140b441aa9c7fc8c1f36edf23ebef9f4165c2f28f568b7", size = 10892524, upload-time = "2026-06-11T17:55:09.432Z" },
|
|
182
|
+
{ url = "https://files.pythonhosted.org/packages/f5/1d/0fdd248313425f55223968af04b0a42125466a8d88d21c1d99c6af0a51e8/ruff-0.15.17-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:382fc0521025f5a8ad447d8bdd523545d0d7646adb718eb1c2dac5065ec27c0f", size = 10659573, upload-time = "2026-06-11T17:54:36.824Z" },
|
|
183
|
+
{ url = "https://files.pythonhosted.org/packages/9e/0e/072e8260deb9461062ce9311ced27a8e541229a6ffd483013dd37661e43e/ruff-0.15.17-py3-none-musllinux_1_2_i686.whl", hash = "sha256:456d41fcd1b2777ad63f09a6e7121d43f7b688bbc76a800c10f7f8fb1f912c3f", size = 11127818, upload-time = "2026-06-11T17:55:03.124Z" },
|
|
184
|
+
{ url = "https://files.pythonhosted.org/packages/ab/b4/55060a34163121498014696b5f656db5b8c6963768f227dbf0d76b311073/ruff-0.15.17-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b1a04bcc94ae6194e9db05d16ad31f298a7194bfbcb08258bbe589cee1d587b8", size = 11655901, upload-time = "2026-06-11T17:54:53.562Z" },
|
|
185
|
+
{ url = "https://files.pythonhosted.org/packages/49/71/9b29d6b87cef468d697f43c6a91e3fae4a80185779d7d5a4ef27d173439f/ruff-0.15.17-py3-none-win32.whl", hash = "sha256:596065960ab1ff593f744220c9fe6580eda00a95003cffa9f4048bb5b1bf0392", size = 10925574, upload-time = "2026-06-11T17:54:55.723Z" },
|
|
186
|
+
{ url = "https://files.pythonhosted.org/packages/3d/b2/8fc77f3723228836fa5d12497eb71c808f83782e10d058d2b15cfa14640b/ruff-0.15.17-py3-none-win_amd64.whl", hash = "sha256:6769e5fa1710b179b92e0bfa5a51735b35baea9013dadb06d5f44cbcf9547084", size = 12058788, upload-time = "2026-06-11T17:54:41.042Z" },
|
|
187
|
+
{ url = "https://files.pythonhosted.org/packages/2d/c7/c53e8dbff9c9dc4b7928773421ae294a5d28fcb8dcda1a089579d3a7e510/ruff-0.15.17-py3-none-win_arm64.whl", hash = "sha256:f3be1fbb34bcdfd146240d8fb92a709d4c2c8191348580a3c044ec60fa0b4456", size = 11355275, upload-time = "2026-06-11T17:54:43.635Z" },
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
[[package]]
|
|
191
|
+
name = "skilltest-pytest"
|
|
192
|
+
version = "0.1.0"
|
|
193
|
+
source = { editable = "." }
|
|
194
|
+
dependencies = [
|
|
195
|
+
{ name = "pytest" },
|
|
196
|
+
{ name = "skilltest-sdk" },
|
|
197
|
+
]
|
|
198
|
+
|
|
199
|
+
[package.dev-dependencies]
|
|
200
|
+
dev = [
|
|
201
|
+
{ name = "ruff" },
|
|
202
|
+
{ name = "ty" },
|
|
203
|
+
]
|
|
204
|
+
|
|
205
|
+
[package.metadata]
|
|
206
|
+
requires-dist = [
|
|
207
|
+
{ name = "pytest", specifier = ">=8" },
|
|
208
|
+
{ name = "skilltest-sdk", editable = "../../sdks/python" },
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
[package.metadata.requires-dev]
|
|
212
|
+
dev = [
|
|
213
|
+
{ name = "ruff", specifier = ">=0.6" },
|
|
214
|
+
{ name = "ty", specifier = ">=0.0.1a1" },
|
|
215
|
+
]
|
|
216
|
+
|
|
217
|
+
[[package]]
|
|
218
|
+
name = "skilltest-sdk"
|
|
219
|
+
version = "0.1.0"
|
|
220
|
+
source = { editable = "../../sdks/python" }
|
|
221
|
+
dependencies = [
|
|
222
|
+
{ name = "pydantic" },
|
|
223
|
+
]
|
|
224
|
+
|
|
225
|
+
[package.metadata]
|
|
226
|
+
requires-dist = [{ name = "pydantic", specifier = ">=2.7" }]
|
|
227
|
+
|
|
228
|
+
[package.metadata.requires-dev]
|
|
229
|
+
dev = [
|
|
230
|
+
{ name = "datamodel-code-generator", specifier = ">=0.62.0" },
|
|
231
|
+
{ name = "pytest", specifier = ">=8" },
|
|
232
|
+
{ name = "ruff", specifier = ">=0.6" },
|
|
233
|
+
{ name = "ty", specifier = ">=0.0.1a1" },
|
|
234
|
+
]
|
|
235
|
+
|
|
236
|
+
[[package]]
|
|
237
|
+
name = "ty"
|
|
238
|
+
version = "0.0.48"
|
|
239
|
+
source = { registry = "https://pypi.org/simple" }
|
|
240
|
+
sdist = { url = "https://files.pythonhosted.org/packages/0c/ad/7a6568b4a8dbb6531ef4f13cd5658e0e4fbd18b890a137b96e1ac87638d5/ty-0.0.48.tar.gz", hash = "sha256:aa54d69b755ea3f765975abdc5fe41f8daca45b1aabc57f91ddd3bd4b7e0c2de", size = 5868533, upload-time = "2026-06-10T22:36:10.899Z" }
|
|
241
|
+
wheels = [
|
|
242
|
+
{ url = "https://files.pythonhosted.org/packages/92/14/6872bdcd4b2da07c9edebafa22280020b4bc46fe0dcfaad3900cf5b7eede/ty-0.0.48-py3-none-linux_armv6l.whl", hash = "sha256:a6709c6a043524fa36735448e87c902d428033c5f3df7cdf81361ed93b99552c", size = 11810553, upload-time = "2026-06-10T22:35:40.08Z" },
|
|
243
|
+
{ url = "https://files.pythonhosted.org/packages/7d/5c/5f1ee9ee82e05ec7e5456d07ee488776003e3bcc77acdf863b5b14880465/ty-0.0.48-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f52a04c3f9e464860e2ce44afa60d98079c5e09e4e4940990ebe5f3ba9cf3dff", size = 11559964, upload-time = "2026-06-10T22:36:12.816Z" },
|
|
244
|
+
{ url = "https://files.pythonhosted.org/packages/cd/15/933a57a0bdbbfa82f0c7cf884d45155628edc2d44e8afe9d8a172aafc0d7/ty-0.0.48-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd3cb6ee735cfb544e1d6c7cabda7164fd29d1a3ded84f22f092495530faafe2", size = 10950220, upload-time = "2026-06-10T22:35:35.811Z" },
|
|
245
|
+
{ url = "https://files.pythonhosted.org/packages/77/f2/12acd376cc719ebcff1d76efc1cafcc98a24c0f6fb23e730860024cdd965/ty-0.0.48-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5846c1c9e1777e60fa204d9b7c912e8db8647bdc8d4fcb176ccb3278ed96635a", size = 11485715, upload-time = "2026-06-10T22:35:53.229Z" },
|
|
246
|
+
{ url = "https://files.pythonhosted.org/packages/6f/db/b839e397f016274a175f71c53b959007ab5bb1c2928746fbb4a7a2c61153/ty-0.0.48-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:518d08a7194a5d3d07b5f459cace1e2a3a8d67c58e27b092bc948078c03fdad9", size = 11593310, upload-time = "2026-06-10T22:35:46.617Z" },
|
|
247
|
+
{ url = "https://files.pythonhosted.org/packages/dc/39/908e9c2141ff133452552b1f0b0c278b52812047ea671b59dfb064f1180c/ty-0.0.48-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bea4240fd52b1405c090c649bf1786a995f0809499e1a8bedf6a6a372f925a98", size = 12048829, upload-time = "2026-06-10T22:36:06.842Z" },
|
|
248
|
+
{ url = "https://files.pythonhosted.org/packages/e6/51/aa0e5fae345cd5fea8a8d5cfce6a900604ea42b99b3d6b7da99787e60505/ty-0.0.48-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c5241363be03c1ca0cd2b60c5ccf55a5f2803ddfa80fd61944b405fc21226c1", size = 12642932, upload-time = "2026-06-10T22:35:59.962Z" },
|
|
249
|
+
{ url = "https://files.pythonhosted.org/packages/32/d0/6928525166890b04cbb9fc75d6308dbda3bdd81d1c076dade2d36c2276a6/ty-0.0.48-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e22ede258dd37a3117db0259fc80001615a6dfddc36dbb0371253f97fd7fd817", size = 12279019, upload-time = "2026-06-10T22:35:42.036Z" },
|
|
250
|
+
{ url = "https://files.pythonhosted.org/packages/ef/3d/7cb614c74f8883720034ca5ee9ce3d213aff762ad87f50315b50fad705ce/ty-0.0.48-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee756f22cfc8e72c8e01c695c0b97caab6de1df1a299e7c7c6e31a6249441fed", size = 12145259, upload-time = "2026-06-10T22:35:38.02Z" },
|
|
251
|
+
{ url = "https://files.pythonhosted.org/packages/f7/44/391886e74ef7d126aeb1096fc0002a595d99ed87febfb9fe0b2b859325e6/ty-0.0.48-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:05ebfcc99da65786ba42ddb9cab9c1f2d50ad66493f512242fce40036c51fb98", size = 12339393, upload-time = "2026-06-10T22:35:55.216Z" },
|
|
252
|
+
{ url = "https://files.pythonhosted.org/packages/7d/42/dcfe9ace7cbdf6c9a242b26ed7281c692fdf054468255422b277753dd296/ty-0.0.48-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:11f88996c497cb08a33fb5019ea66d096bba469d23b2fed53ee604dff5fd94ae", size = 11442355, upload-time = "2026-06-10T22:36:01.975Z" },
|
|
253
|
+
{ url = "https://files.pythonhosted.org/packages/d5/13/fbd8aabf8fc2034c70538b3ce472ada31391d5e7c86f9ea724940afdf43b/ty-0.0.48-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:70e5e4edbdec56c146f085617f085ae4c7d5dfecbefccef51e093f506af9b02e", size = 11602499, upload-time = "2026-06-10T22:36:04.41Z" },
|
|
254
|
+
{ url = "https://files.pythonhosted.org/packages/64/09/44e53ac462952f8988aa27a5c141c2f3535fc4fcb68f571d80baf73939e4/ty-0.0.48-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d420c3478f338511e47a2987052e5099b7f67aa0ab725e5e1e2f5658d11099bd", size = 11711851, upload-time = "2026-06-10T22:35:44.517Z" },
|
|
255
|
+
{ url = "https://files.pythonhosted.org/packages/89/15/b1b22a01094ce9b2a5ecaf6fe1530490dc25b0260551d702e881b2601014/ty-0.0.48-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0bf036e2e3a359c1e83883a46a4d2076617511d7329fe5421c7d158f28e19615", size = 12230497, upload-time = "2026-06-10T22:35:57.714Z" },
|
|
256
|
+
{ url = "https://files.pythonhosted.org/packages/74/e9/9bba0e7fcc3a5058d7fa55be410356991925cc0f6546ccd1eb0821aee48f/ty-0.0.48-py3-none-win32.whl", hash = "sha256:19ad4acd4347ca3e206e7455c2a05fba228e1b3186463517bcb783f88885ff78", size = 11048763, upload-time = "2026-06-10T22:35:49.049Z" },
|
|
257
|
+
{ url = "https://files.pythonhosted.org/packages/bd/6a/71d815058affbbc26d43538002c74203cf6a72a4b342981fc13324e64412/ty-0.0.48-py3-none-win_amd64.whl", hash = "sha256:1f496d799abab6e5a26c901a049163f171aa1b40c8e418cdf76adf3444d1b0db", size = 12188589, upload-time = "2026-06-10T22:36:08.938Z" },
|
|
258
|
+
{ url = "https://files.pythonhosted.org/packages/1a/fe/a8f8ad81612ab7f75a170c70710f8d2c4ada39e86b827a4e524086f50c24/ty-0.0.48-py3-none-win_arm64.whl", hash = "sha256:77c94e4484897c3a184821cd56274b71f1c001663331f9c1ba06ac889633bff6", size = 11542770, upload-time = "2026-06-10T22:35:51.122Z" },
|
|
259
|
+
]
|
|
260
|
+
|
|
261
|
+
[[package]]
|
|
262
|
+
name = "typing-extensions"
|
|
263
|
+
version = "4.15.0"
|
|
264
|
+
source = { registry = "https://pypi.org/simple" }
|
|
265
|
+
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
|
266
|
+
wheels = [
|
|
267
|
+
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
|
268
|
+
]
|
|
269
|
+
|
|
270
|
+
[[package]]
|
|
271
|
+
name = "typing-inspection"
|
|
272
|
+
version = "0.4.2"
|
|
273
|
+
source = { registry = "https://pypi.org/simple" }
|
|
274
|
+
dependencies = [
|
|
275
|
+
{ name = "typing-extensions" },
|
|
276
|
+
]
|
|
277
|
+
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
|
|
278
|
+
wheels = [
|
|
279
|
+
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
|
|
280
|
+
]
|