Skip to content
Development
Skill

/nw-pbt-python

Python property-based testing with Hypothesis framework, strategies, and pytest integration

From plugin
nwave
635183 skills37 agents

Claude Code

$ npx -y skills add nWave-ai/nWave --skill nw-pbt-python --agent claude-code

SKILL.md

nw-pbt-python.SKILL.md
name: nw-pbt-python
agent: nw-functional-software-crafter
description: Python property-based testing with Hypothesis framework, strategies, and pytest integration
user-invocable: false

PBT Python -- Hypothesis

Framework Selection

**Hypothesis** is the only serious choice for Python PBT. No competitive alternatives.

  • 10+ years mature, very actively maintained
  • Used by PyTorch, NumPy, pandas
  • Seamless pytest integration (no plugin needed)

Quick Start

from hypothesis import given, assume, settings, HealthCheck
from hypothesis import strategies as st

@given(st.lists(st.integers()))
def test_sort_idempotent(xs):
    assert sorted(sorted(xs)) == sorted(xs)

# Run: pytest test_file.py

Generator (Strategy) Cheat Sheet

Primitives

st.integers()                         # any int
st.integers(min_value=0, max_value=99) # bounded
st.floats()                           # includes NaN, inf
st.floats(allow_nan=False, allow_infinity=False)
st.text()                             # unicode strings
st.text(min_size=1, max_size=50)
st.binary()                           # bytes
st.booleans()
st.none()

Collections

st.lists(st.integers())
st.lists(st.integers(), min_size=1, max_size=10)
st.sets(st.integers())
st.frozensets(st.text())
st.dictionaries(st.text(), st.integers())
st.tuples(st.integers(), st.text())

Combinators

st.one_of(st.integers(), st.text())   # union
st.sampled_from([1, 2, 3])            # pick from list
st.just(42)                           # constant

# Map (transform)
st.integers().map(lambda x: x * 2)    # even integers

# Filter (use sparingly)
st.integers().filter(lambda x: x > 0)
# Prefer: st.integers(min_value=1)

# Composite (dependent generation)
@st.composite
def list_and_element(draw):
    xs = draw(st.lists(st.integers(), min_size=1))
    elem = draw(st.sampled_from(xs))
    return (xs, elem)

Recursive

json_values = st.recursive(
    st.none() | st.booleans() | st.integers() | st.text(),
    lambda children: st.lists(children) | st.dictionaries(st.text(), children),
    max_leaves=50
)

Objects

from dataclasses import dataclass

@dataclass
class User:
    name: str
    age: int

users = st.builds(User, name=st.text(min_size=1), age=st.integers(1, 120))
# Or: st.from_type(User) if type annotations are sufficient

Stateful Testing

from hypothesis.stateful import RuleBasedStateMachine, Bundle, rule, initialize, invariant, precondition, consumes

class MyStoreTest(RuleBasedStateMachine):
    keys = Bundle("keys")

    @initialize()
    def init(self):
        self.store = MyStore()
        self.model = {}

    @rule(target=keys, k=st.text(min_size=1))
    def create(self, k):
        return k  # deposited into keys bundle

    @rule(k=keys, v=st.integers())
    def put(self, k, v):
        self.store.put(k, v)
        self.model[k] = v

    @rule(k=keys)
    def get(self, k):
        if k in self.model:
            assert self.store.get(k) == self.model[k]

    @rule(k=consumes(keys))  # removes from bundle
    def delete(self, k):
        self.store.delete(k)
        self.model.pop(k, None)

    @invariant()
    def size_matches(self):
        assert self.store.size() == len(self.model)

TestMyStore = MyStoreTest.TestCase
TestMyStore.settings = settings(max_examples=100, stateful_step_count=50)

Limitation: No parallel/linearizability testing.

Test Runner Integration

# pytest -- just works, no plugin needed
# @given tests are regular pytest functions

# Settings profiles
from hypothesis import settings, Phase
settings.register_profile("ci", max_examples=1000)
settings.register_profile("dev", max_examples=50)
settings.load_profile("ci")  # or via HYPOTHESIS_PROFILE env var

# Suppress slow test warnings
@settings(suppress_health_check=[HealthCheck.too_slow])

# Deadline (max time per example)
@settings(deadline=500)  # 500ms

# Database of failing examples
# Hypothesis auto-saves failures to .hypothesis/
# Replays them on subsequent runs

Django Integration

`@given` never runs directly under a plain `django.test.TestCase` helper — Hypothesis's example-replay/database-reset interaction with Django's per-test transaction wrapping requires `hypothesis.extra.django.TestCase` (or `TransactionTestCase`) as the base. A property test class must subclass the matching `hypothesis.extra.django` base as documented, then:

  • if the repository's setup/assertion behavior is already a cooperative

mixin (no `TestCase` in its own bases, calls `super()` in `setUp`), mix it with the Hypothesis base using the repository-validated ordering;

  • if the repository helper is a concrete `django.test.TestCase` subclass,

never blindly multiple-inherit two concrete `TestCase` hierarchies — extract its behavior into a cooperative mixin, or write a repository-owned Hypothesis-compatible helper, preserving the documented setup/fixtures and validating the actual MRO (`ClassName.__mro__`) rather than assuming one.

from hypothesis import given
from hypothesis import strategies as st
from hypothesis.extra.django import TestCase as HypothesisDjangoTestCase

class RepositoryFixtureMixin:
    """Cooperative mixin: no TestCase base and calls super()."""

    def setUp(self):
        super().setUp()
        self.account_factory = AccountFactory()

    def build_account(self):
        return self.account_factory.create()

class RepositoryPropertyTestCase(RepositoryFixtureMixin, HypothesisDjangoTestCase):
    pass  # validate this ordering against the repository's fixture contract

class PropertyTests(RepositoryPropertyTestCase):
    @given(st.text(min_size=1))
    def test_create_never_raises_on_valid_name(self, name):
        # explicitly construct any state the property needs -- never assume
        # an attribute the shared fixture does not document constructing
        account = self.build_account()
        account.rename(name)
`
Read more
@nwave-ai
Ships withnwave

nWave supplies specialist roles and a host-led delivery workflow for software teams.

635183 skills37 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
635
Star history of nWave-ai/nWave on GitHub, a chart by star-history.com

Other skills on nwave.

nw-ab-agent-template

nw-ab-agent-template

KNOWLEDGE — the canonical agent-spec template (frontmatter + body skeleton). Reference loaded by the create/migrate procedures;…

@nwave-ai@nwave-aiInstall Skill
nw-ab-anti-patterns

nw-ab-anti-patterns

KNOWLEDGE — agent/skill/command anti-pattern catalog with fixes. Reference scanned by validate-spec; no sequence.

@nwave-ai@nwave-aiInstall Skill
nw-ab-create-agent

nw-ab-create-agent

PROCEDURE — create a NEW agent via the 5-phase workflow (ANALYZE→DESIGN→CREATE→VALIDATE→REFINE). Trigger: build a new AI agent.…

@nwave-ai@nwave-aiInstall Skill
nw-ab-examples

nw-ab-examples

KNOWLEDGE — canonical worked examples for agent creation, migration, and command optimization. Reference for the relevant…

@nwave-ai@nwave-aiInstall Skill
nw-ab-house-style

nw-ab-house-style

KNOWLEDGE — caveman-native authoring house style + by-construction guarantees (Reasoning Mandate injection, measured-gain…

@nwave-ai@nwave-aiInstall Skill

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills13d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react4d252k
@facebook@facebookInstall Skill

Questions about nw-pbt-python.

Which coding agents can use nw-pbt-python?
nw-pbt-python installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.