Skip to content

API Reference

test decorator

Decorator for marking functions as tests.

Tryke discovers functions decorated with @test (or prefixed with test_) during collection.

Attributes:

Name Type Description
skip

Skip a test unconditionally.

todo

Mark a test as a placeholder.

xfail

Mark a test as expected to fail.

Example
from tryke import test

@test
def my_test():
    ...

@test(name="descriptive test name")
def named():
    ...

@test(tags=["slow", "network"])
def tagged():
    ...

__call__

__call__(fn: _AnyTestFn) -> _AnyTestFn
__call__(name: str) -> _Decorator
__call__(
    fn: None = None,
    /,
    *,
    name: str | None = None,
    tags: list[str] | None = None,
) -> _Decorator
__call__(fn=None, /, *, name=None, tags=None)

Register a function as a test.

Can be used as a bare decorator (@test) or called with keyword arguments (@test(name="...", tags=[...])) to set metadata.

Parameters:

Name Type Description Default
fn

The test function (when used as a bare decorator).

None
name

Optional display name for the test.

None
tags

Optional list of tags for filtering with -m.

None

case

case(
    label: str, /, *args: P.args, **kwargs: P.kwargs
) -> _CaseSpec[P]

Build one typed case for a :meth:cases decorator.

The label is an arbitrary string — spaces, math operators, and punctuation are all fine, so "my test" and "2 + 3" both work and survive -k filtering end-to-end.

The *args/**kwargs are typed via PEP 612 _P.args / _P.kwargs so that mypy and pyright can match them against the decorated function's signature inside :meth:cases. ty does not yet enforce this pattern; see the module docstring for :class:_CaseSpec for details.

The keyword names skip, xfail, and todo are reserved for per-case modifiers. When passed, they must be strings and are consumed by the framework — they are not forwarded to the test function.

Example
@test.cases(
    test.case("zero", n=0, expected=0),
    test.case("one",  n=1, expected=1),
    test.case("broken", n=2, expected=999, xfail="bug #42"),
)
def square(n: int, expected: int) -> None:
    expect(n * n).to_equal(expected)

cases

cases(
    *specs: _CaseSpec[P],
) -> Callable[[Callable[P, None]], Callable[P, None]]
cases(
    positional: list[tuple[str, CaseArgs]],
) -> Callable[[_Fn], _Fn]
cases(**kwargs: CaseArgs) -> Callable[[_Fn], _Fn]
cases(
    *positional: object, **kwargs: CaseArgs
) -> Callable[[_Fn], _Fn]

Parametrize a test over multiple named cases.

Pass one :meth:case spec per row. PEP 612 ParamSpec binds the kwargs against the decorated function's signature so typos and mismatched types become static errors under mypy/pyright::

@test.cases(
    test.case("zero",     n=0,  expected=0),
    test.case("one",      n=1,  expected=1),
    test.case("ten",      n=10, expected=100),
)
def square(n: int, expected: int) -> None:
    expect(n * n).to_equal(expected)

ty (as of 0.0.21) does not yet enforce this pattern. Runtime validation still catches label collisions and inconsistent key sets.

Composes with @fixture/Depends() parameters, describe(...) blocks, and @test.skip/@test.xfail.

Raises:

Type Description
TypeError

If no cases are provided, forms are mixed, two cases share a label, or cases disagree on key sets.

skip_if

skip_if(condition: bool, *, reason: str = '') -> _Decorator

Skip a test conditionally, evaluated at import time.

Parameters:

Name Type Description Default
condition bool

When True, the test is skipped.

required
reason str

Optional reason shown in test output.

''
Example
import sys

@test.skip_if(sys.platform == "win32", reason="unix only")
def unix_test():
    ...

Bases: _Marker

Skip a test unconditionally.

Can be used as a bare decorator or called with a reason string.

Example
@test.skip
def not_ready():
    ...

@test.skip("waiting on upstream fix")
def with_reason():
    ...

__call__

__call__(fn_or_reason: _Fn) -> _SkipMarked
__call__(
    fn_or_reason: str | None = ...,
    /,
    *,
    reason: str | None = ...,
    name: str | None = ...,
    tags: list[str] | None = ...,
) -> Callable[[_Fn], _SkipMarked]
__call__(
    fn_or_reason: _Fn | str | None = None,
    /,
    *,
    reason: str | None = None,
    name: str | None = None,
    tags: list[str] | None = None,
) -> object

Mark a test to be skipped.

Parameters:

Name Type Description Default
fn_or_reason _Fn | str | None

The test function (when used as a bare decorator) or a reason string (when called with parentheses).

None
reason str | None

Reason for skipping (alternative to positional string).

None
name str | None

Optional test name override.

None
tags list[str] | None

Optional list of tags for filtering.

None

Bases: _Marker

Mark a test as a placeholder — it will be collected but not executed.

Can be used as a bare decorator or called with a description string.

Example
@test.todo
def future_feature():
    ...

@test.todo("implement caching layer")
def with_description():
    ...

__call__

__call__(fn_or_desc: _Fn) -> _TodoMarked
__call__(
    fn_or_desc: str | None = ...,
    /,
    *,
    description: str | None = ...,
    name: str | None = ...,
    tags: list[str] | None = ...,
) -> Callable[[_Fn], _TodoMarked]
__call__(
    fn_or_desc: _Fn | str | None = None,
    /,
    *,
    description: str | None = None,
    name: str | None = None,
    tags: list[str] | None = None,
) -> object

Mark a test as a todo placeholder.

Parameters:

Name Type Description Default
fn_or_desc _Fn | str | None

The test function (when used as a bare decorator) or a description string (when called with parentheses).

None
description str | None

Description of what needs to be done (alternative to positional string).

None
name str | None

Optional test name override.

None
tags list[str] | None

Optional list of tags for filtering.

None

Bases: _Marker

Mark a test as expected to fail.

Can be used as a bare decorator or called with a reason string.

Example
@test.xfail
def known_bug():
    ...

@test.xfail("upstream issue #42")
def with_reason():
    ...

__call__

__call__(fn_or_reason: _Fn) -> _XfailMarked
__call__(
    fn_or_reason: str | None = ...,
    /,
    *,
    reason: str | None = ...,
    name: str | None = ...,
    tags: list[str] | None = ...,
) -> Callable[[_Fn], _XfailMarked]
__call__(
    fn_or_reason: _Fn | str | None = None,
    /,
    *,
    reason: str | None = None,
    name: str | None = None,
    tags: list[str] | None = None,
) -> object

Mark a test as expected to fail.

Parameters:

Name Type Description Default
fn_or_reason _Fn | str | None

The test function (when used as a bare decorator) or a reason string (when called with parentheses).

None
reason str | None

Reason the test is expected to fail (alternative to positional string).

None
name str | None

Optional test name override.

None
tags list[str] | None

Optional list of tags for filtering.

None

expect assertions

Create an Expectation for expr.

Parameters:

Name Type Description Default
expr T

The value to make assertions on.

required
name str | None

Optional label for the assertion (used by the Rust-side discovery to extract assertion labels from source code; unused at runtime).

None

Returns:

Type Description
Expectation[T]

An Expectation with chainable assertion methods.

Example
>>> from tryke import expect
>>> expect(1 + 1).to_equal(2)
MatchResult(ok)
>>> expect("hello").to_contain("ell")
MatchResult(ok)

Chainable assertion wrapper created by expect.

Every assertion method returns a MatchResult. Use .not_ to negate any assertion.

Example
>>> from tryke import expect
>>> expect(1 + 1).to_equal(2)
MatchResult(ok)
>>> expect(None).not_.to_be_truthy()
MatchResult(ok)

not_ property

not_: Expectation[T]

Negate the next assertion.

Example
>>> from tryke import expect
>>> expect(1).not_.to_equal(2)
MatchResult(ok)
>>> expect(None).not_.to_be_truthy()
MatchResult(ok)

to_equal

to_equal(other: T) -> MatchResult

Deep equality check (==).

Parameters:

Name Type Description Default
other T

The value to compare against.

required
Example
>>> from tryke import expect
>>> expect(1 + 1).to_equal(2)
MatchResult(ok)
>>> expect([1, 2]).to_equal([1, 2])
MatchResult(ok)

to_be

to_be(other: object) -> MatchResult

Identity check (is).

Parameters:

Name Type Description Default
other object

The object to compare identity against.

required
Example
>>> from tryke import expect
>>> sentinel = object()
>>> expect(sentinel).to_be(sentinel)
MatchResult(ok)

to_be_truthy

to_be_truthy() -> MatchResult

Assert the value is truthy (bool(value) is True).

Example
>>> from tryke import expect
>>> expect(1).to_be_truthy()
MatchResult(ok)
>>> expect([1]).to_be_truthy()
MatchResult(ok)

to_be_falsy

to_be_falsy() -> MatchResult

Assert the value is falsy (bool(value) is False).

Example
>>> from tryke import expect
>>> expect(0).to_be_falsy()
MatchResult(ok)
>>> expect("").to_be_falsy()
MatchResult(ok)

to_be_none

to_be_none() -> MatchResult

Assert the value is None.

Example
>>> from tryke import expect
>>> expect(None).to_be_none()
MatchResult(ok)
>>> expect(42).not_.to_be_none()
MatchResult(ok)

to_be_greater_than

to_be_greater_than(n: C) -> MatchResult

Assert the value is greater than n.

Parameters:

Name Type Description Default
n C

The value to compare against.

required
Example
>>> from tryke import expect
>>> expect(5).to_be_greater_than(3)
MatchResult(ok)

to_be_less_than

to_be_less_than(n: C) -> MatchResult

Assert the value is less than n.

Parameters:

Name Type Description Default
n C

The value to compare against.

required
Example
>>> from tryke import expect
>>> expect(3).to_be_less_than(5)
MatchResult(ok)

to_be_greater_than_or_equal

to_be_greater_than_or_equal(n: C) -> MatchResult

Assert the value is greater than or equal to n.

Parameters:

Name Type Description Default
n C

The value to compare against.

required
Example
>>> from tryke import expect
>>> expect(5).to_be_greater_than_or_equal(5)
MatchResult(ok)

to_be_less_than_or_equal

to_be_less_than_or_equal(n: C) -> MatchResult

Assert the value is less than or equal to n.

Parameters:

Name Type Description Default
n C

The value to compare against.

required
Example
>>> from tryke import expect
>>> expect(4).to_be_less_than_or_equal(5)
MatchResult(ok)

to_contain

to_contain(item: object) -> MatchResult

Assert the value contains item.

Works on lists, strings, and any container supporting in.

Parameters:

Name Type Description Default
item object

The item to search for.

required
Example
>>> from tryke import expect
>>> expect([1, 2, 3]).to_contain(2)
MatchResult(ok)
>>> expect("hello world").to_contain("world")
MatchResult(ok)

to_have_length

to_have_length(n: int) -> MatchResult

Assert the value has length n.

Parameters:

Name Type Description Default
n int

The expected length.

required
Example
>>> from tryke import expect
>>> expect([1, 2, 3]).to_have_length(3)
MatchResult(ok)
>>> expect("hello").to_have_length(5)
MatchResult(ok)

to_match

to_match(pattern: str) -> MatchResult

Regex match against the string representation of the value.

Parameters:

Name Type Description Default
pattern str

A regular expression pattern.

required
Example
>>> from tryke import expect
>>> expect("hello world").to_match(r"hello")
MatchResult(ok)
>>> expect("foo123").to_match(r"\d+")
MatchResult(ok)

to_raise

to_raise(
    exc_type: type[BaseException] | None = None,
    *,
    match: str | None = None,
) -> MatchResult

Assert that a callable raises an exception.

Wrap the expression in a lambda.

Parameters:

Name Type Description Default
exc_type type[BaseException] | None

Expected exception type, or None for any exception.

None
match str | None

Regex pattern to match against the exception message.

None
Example
>>> from tryke import expect
>>> expect(lambda: int("abc")).to_raise(ValueError)
MatchResult(ok)
>>> expect(lambda: 1 / 0).to_raise(ZeroDivisionError, match="division")
MatchResult(ok)
>>> expect(lambda: None).not_.to_raise()
MatchResult(ok)

Result of an assertion.

By default assertions are soft — a failing assertion records the failure but does not stop the test. Call .fatal() to opt in to immediate failure.

fatal

fatal() -> None

Stop the test immediately if this assertion failed.

Example
@test
def must_pass():
    expect(config).not_.to_be_none().fatal()  # stops here if None
    expect(config.value).to_equal(42)

describe context manager

Group tests visually in output.

The describe name is used as a prefix in test names during reporting. The name is inspected by tryke's static discovery, so it must be a string literal when used as with describe("..."):.

Example
from tryke import describe, expect, test

with describe("math"):
    @test
    def addition():
        expect(1 + 1).to_equal(2)

    @test
    def subtraction():
        expect(3 - 1).to_equal(2)

Fixtures

A single @fixture decorator handles setup and teardown, with two granularities selected via per=. Scope is determined by position: module top-level applies to all tests in the file; inside a describe() block applies to that group only.

Form Runs Scope
@fixture (default: per="test") Before/after every test in scope Per-test
@fixture(per="scope") Once for all tests in scope Per-(lexical-)scope

Use yield to split setup and teardown in the same function. See the Writing tests guide for worked examples.

fixture

fixture(fn: F) -> F
fixture(*, per: FixturePer = 'test') -> Callable[[F], F]
fixture(
    fn: _FixtureFn | None = None,
    /,
    *,
    per: FixturePer = "test",
) -> _FixtureFn | Callable[[_FixtureFn], _FixtureFn]

Mark a function as a tryke fixture.

A fixture runs automatically around every test in its lexical scope (module-level fixtures cover all tests in the file; fixtures defined inside with describe(...) cover tests in that describe block).

Use yield to split setup and teardown::

@fixture
def db():
    conn = connect()
    yield conn          # value visible to tests via Depends()
    conn.close()        # teardown runs after each test

Use per="scope" to cache the value across every test in the fixture's lexical scope — the function runs once, and teardown runs after the last test in that scope::

@fixture(per="scope")
def app():
    return TestApp()    # plain return: no teardown

Tests (and other fixtures) consume values with :func:Depends.


Depends

Depends

Depends(dep: Callable[..., Generator[T, None, None]]) -> T
Depends(dep: Callable[..., AsyncGenerator[T, None]]) -> T
Depends(dep: Callable[..., Awaitable[T]]) -> T
Depends(dep: Callable[..., T]) -> T
Depends(dep: Callable[..., Any]) -> Any

Declare a dependency on another fixture.

Used in function signatures to request a resolved value::

@fixture(per="scope")
def db() -> Connection:
    return create_connection()

@test
def my_test(conn: Connection = Depends(db)):
    ...

Type checkers see Depends(db) as returning Connection. At runtime it returns a :class:_Depends sentinel that the executor resolves before calling the function.