Skip to main content

vowel-core

Write, run, and debug YAML-based evaluation specs for Python functions using the vowel framework. This skill contains the complete YAML specification, all evaluators, fixtures, serializers, CLI, and the RunEvals fluent API. Use when the user asks about testing Python functions with vowel, writing eval YAML files, running evaluations, or using fixtures/serializers.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
vcoderun/vowel-core
آخر نشاط في المصدر
٢٥ فبراير ٢٠٢٦ في ١٦:٤٢
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٠
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
vowel-core
description
Write, run, and debug YAML-based evaluation specs for Python functions using the vowel framework. This skill contains the complete YAML specification, all evaluators, fixtures, serializers, CLI, and the RunEvals fluent API. Use when the user asks about testing Python functions with vowel, writing eval YAML files, running evaluations, or using fixtures/serializers.
license
Apache-2.0
metadata
{"author":"fswair","version":"2.0"}
# Vowel — YAML Evaluation Framework vowel is a YAML-based evaluation framework for testing Python functions. Write specs, run them, check results. ```bash pip install vowel ``` --- ## YAML Specification ### Basic Structure ```yaml # Top-level fixture definitions (optional) fixtures: fixture_name: setup: module.setup_func teardown: module.teardown_func # optional scope: function # function | module | session kwargs: # optional key: value # Function evaluation specs function_name: fixture: # fixture dependencies (optional) - fixture_name evals: # global evaluators (optional) EvaluatorName: param: value dataset: # test cases (required) - case: input: <value> # single parameter # OR inputs: { a: 1, b: 2 } # named parameters (dict) # OR inputs: [1, 2, 3] # positional parameters (list) expected: <value> # expected output (optional) raises: ExceptionType # expected exception (optional) match: "regex pattern" # exception message match (optional) duration: 50 # max ms for this case (optional) ``` ### Input Types ```yaml # Single parameter: func(x) single_param: dataset: - case: input: 42 expected: 84 # Multiple positional: func(a, b, c) multi_positional: dataset: - case: inputs: [1, 2, 3] expected: 6 # Named parameters: func(x=1, y=2) named_params: dataset: - case: inputs: { x: 10, y: 20 } expected: 30 ``` ### Function Sources vowel resolves functions from 4 sources: ```yaml # 1. Python builtins len: dataset: - case: { input: [1, 2, 3], expected: 3 } # 2. Standard library (module.function) math.sqrt: dataset: - case: { input: 16, expected: 4.0 } os.path.join: dataset: - case: { inputs: ["/home", "user"], expected: "/home/user" } # 3. Your own functions (via functions= or with_functions()) my_function: dataset: - case: { input: "hello", expected: "HELLO" } # 4. Local module functions (module.function) utils.uppercase: dataset: - case: { input: "hello", expected: "HELLO" } ``` ### Fixtures in YAML ```yaml fixtures: db: setup: myapp.fixtures.setup_db teardown: myapp.fixtures.close_db scope: module kwargs: db_name: test_db cache: setup: myapp.fixtures.setup_cache scope: session temp_dir: setup: myapp.fixtures.create_temp_dir teardown: myapp.fixtures.remove_temp_dir scope: function query_user: fixture: - db dataset: - case: inputs: { user_id: 1 } expected: { name: "Alice", email: "alice@test.com" } save_with_cache: fixture: - db - cache evals: Type: type: "bool" dataset: - case: inputs: { key: "user:1", value: "Alice" } expected: true ``` Functions MUST use keyword-only args for fixtures: ```python def query_user(user_id: int, *, db: dict) -> dict | None: return db["users"].get(user_id) def save_with_cache(key: str, value: str, *, db: dict, cache: dict) -> bool: db["data"][key] = value cache[key] = value return True ``` ### Input Serializers in YAML **Schema mode** — automatic dict → type: ```yaml get_user_info: dataset: - case: input: { id: 1, name: "Alice", email: "alice@test.com" } expected: "User Alice has email alice@test.com" ``` ```python from pydantic import BaseModel from vowel import RunEvals class User(BaseModel): id: int name: str email: str summary = ( RunEvals.from_file("user_evals.yml") .with_functions({"get_user_info": get_user_info}) .with_serializer({"get_user_info": User}) .run() ) ``` **Dict schema** — per-parameter types: ```python .with_serializer({"process": {"user": User, "config": Config}}) ``` **Serial fn mode** — full control: ```python from datetime import date def parse_date(data: dict) -> date: raw = data.get("input") or data.get("inputs") return date.fromisoformat(raw) summary = ( RunEvals.from_source(spec) .with_functions({"get_year": get_year}) .with_serializer(serial_fn={"get_year": parse_date}) .run() ) ``` Return types from serial_fn: | Return Type | Behavior | |-------------|----------| | **Single value** | Passed as single argument | | **Tuple** | Unpacked as positional arguments | | **Dict** | Unpacked as keyword arguments | ### Raises Variants ```yaml # Specific exception type - case: input: "bad" raises: ZeroDivisionError match: "division by zero" # optional regex on message # Dotted exception paths (compared by short name) - case: input: "bad" raises: mypackage.errors.APIError # Any exception must be raised - case: input: "bad" raises: any # Any exception OR normal return (both pass) - case: input: "maybe" raises: any? ``` --- ## Evaluators 8 built-in evaluators. ### Expected Value (Exact Match) ```yaml add: dataset: - case: inputs: { x: 2, y: 3 } expected: 5 ``` ### Type Checking ```yaml divide: evals: Type: type: "float" strict: true # no type promotion (int won't pass for float) dataset: - case: inputs: { a: 10, b: 3 } ``` Supported: `int`, `float`, `str`, `bool`, `list`, `dict`, `int | float`, `str | None`, etc. ### Assertion ```yaml is_positive: evals: Assertion: assertion: "output == (input > 0)" dataset: - case: { input: 5 } - case: { input: -3 } ``` **Available variables:** | Variable | Description | |----------|-------------| | `input` | Input value(s): single value, list, or dict | | `output` | Function return value | | `expected` | Expected value (if provided) | | `duration` | Execution time in seconds | **Examples:** ```yaml assertion: "output > 0" assertion: "output == input * 2" assertion: "abs(output - expected) < 0.001" assertion: "output == input[0] + input[1]" # list inputs assertion: "output == input['x'] * input['y']" # dict inputs ``` ### Duration (Performance) Function-level (seconds): ```yaml fast_function: evals: Duration: duration: 0.5 dataset: - case: { input: 1000 } ``` Case-level (milliseconds): ```yaml compute: dataset: - case: input: 100 duration: 50 ``` ### Pattern Matching (Regex) ```yaml format_phone: evals: Pattern: pattern: "^\\+?[0-9]{10,14}$" case_sensitive: true dataset: - case: { input: "5551234567" } ``` ### Contains Input ```yaml echo: evals: ContainsInput: case_sensitive: false as_strings: true dataset: - case: { input: "Hello" } ``` ### Raises (Exception Testing) ```yaml divide: dataset: - case: inputs: { a: 10, b: 0 } raises: ZeroDivisionError match: "division by zero" - case: input: "bad" raises: any - case: input: "maybe" raises: any? ``` ### LLM Judge ```yaml summarize: evals: LLMJudge: rubric: "Summary captures main points without losing critical information" include: [input, expected_output] config: model: "openai:gpt-4o-mini" temperature: 0.0 dataset: - case: input: "Long article text..." ``` ### Combining Evaluators ```yaml factorial: evals: Assertion: assertion: "output > 0" Type: type: "int" Duration: duration: 1.0 dataset: - case: { input: 0, expected: 1 } - case: { input: 5, expected: 120 } - case: { input: 10, expected: 3628800 } ``` --- ## Fixtures Fixtures inject external dependencies (databases, temp files, caches) as keyword-only arguments. ### Three Patterns ```python # 1. Generator (pytest-style yield) import tempfile, os def temp_file(): fd, path = tempfile.mkstemp() yield path # injected into function os.close(fd) os.remove(path) # 2. Tuple (setup + teardown) def setup_db(): return Database.connect() def teardown_db(conn): conn.close() # Usage: .with_fixtures({"db": (setup_db, teardown_db)}) # 3. Simple (setup only) def sample_data(): return {"users": ["alice", "bob"]} # Usage: .with_fixtures({"data": sample_data}) ``` ### Fixture Scopes | Scope | Behavior | |-------|----------| | `function` (default) | Setup/teardown for each test case | | `module` | Setup once per eval spec, teardown after all cases | | `session` | Setup once per `run_evals()` call, teardown at end | ### Function Signature Pattern ```python def query_user(user_id: int, *, db: dict) -> dict | None: return db["users"].get(user_id) ``` ### CLI Inspection ```bash vowel evals.yml --list-fixtures # list fixtures with scope/usage vowel evals.yml --fixture-tree # show dependency tree ``` --- ## CLI Reference ```bash vowel [OPTIONS] [YAML_FILE] ``` | Option | Short | Description | |--------|-------|-------------| | `--debug` | | Enable debug mode with stack traces | | `--dir` | `-d` | Run all YAML files in directory (recursive) | | `--filter` | `-f` | Only run specific function(s) (comma-separated) | | `--cov` / `--coverage` | | Required coverage percent (default: 100) | | `--ci` | | CI mode — exit 1 if coverage not met | | `--quiet` | `-q` | Minimal output | | `--watch` | `-w` | Watch mode: re-run on file changes |
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub