Pytest

Bazel rules for the python test framework Pytest.

Rules

Functions

current_py_pytest_toolchain

load("@rules_venv//python/pytest:defs.bzl", "current_py_pytest_toolchain")

current_py_pytest_toolchain(name)

A rule for exposing the current registered py_pytest_toolchain.

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired

py_pytest_test

load("@rules_venv//python/pytest:defs.bzl", "py_pytest_test")

py_pytest_test(name, deps, srcs, data, config, coverage_rc, env, env_inherit, numprocesses)

A rule which runs python tests using pytest as the py_test test runner.

This rule also supports a build setting for globally applying extra flags to test invocations. Users can add something similar to the following to their .bazelrc files:

build --@rules_venv//python/pytest:extra_args=--color=yes,-vv

The example above will add --colors=yes and -vv arguments to the end of the pytest invocation.

Tips:

  • It's common for tests to have some utility code that does not live in a test source file. To account for this. A py_library can be created that contains only these sources which are then passed to py_pytest_test via deps.
load("@rules_venv//python:defs.bzl", "py_library")
load("@rules_venv//python/pytest:defs.bzl", "py_pytest_test")

py_library(
    name = "test_utils",
    srcs = [
        "tests/__init__.py",
        "tests/conftest.py",
    ],
    deps = ["@rules_venv//python/pytest:current_py_pytest_toolchain"],
    testonly = True,
)

py_pytest_test(
    name = "test",
    srcs = ["tests/example_test.py"],
    deps = [":test_utils"],
)

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
depsThe list of other libraries to be linked in to the binary target.List of labelsoptional[]
srcsAn explicit list of source files to test.List of labelsoptional[]
dataFiles needed by this rule at runtime. May list file or rule targets. Generally allows any target.List of labelsoptional[]
configThe pytest configuration file to use.Labeloptional"@rules_venv//python/pytest:config"
coverage_rcThe pytest-cov configuration file to use.Labeloptional"@rules_venv//python/pytest:coverage_rc"
envDictionary of strings; values are subject to $(location) and "Make variable" substitutionDictionary: String -> Stringoptional{}
env_inheritSpecifies additional environment variables to inherit from the external environment when the test is executed by bazel test.List of stringsoptional[]
numprocessesIf set the pytest-xdist argument --numprocesses (-n) will be passed to the test. Note that the a value 0 or less indicates this flag should not be passed.Integeroptional0

py_pytest_toolchain

load("@rules_venv//python/pytest:defs.bzl", "py_pytest_toolchain")

py_pytest_toolchain(name, pytest)

A toolchain for the pytest rules.

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
pytestThe pytest py_library to use with the rules.Labelrequired

py_pytest_test_suite

load("@rules_venv//python/pytest:defs.bzl", "py_pytest_test_suite")

py_pytest_test_suite(name, tests, args, data, **kwargs)

Generates a test_suite which groups various test targets for a set of python sources.

Given an idiomatic python project structure:

BUILD.bazel
my_lib/
    __init__.py
    mod_a.py
    mod_b.py
    mod_c.py
requirements.in
requirements.txt
tests/
    __init__.py
    fixtures.py
    test_mod_a.py
    test_mod_b.py
    test_mod_c.py

This rule can be used to easily define test targets:

load("@rules_venv//python:defs.bzl", "py_library")
load("@rules_venv//python/pytest:defs.bzl", "py_pytest_test_suite")

py_library(
    name = "my_lib",
    srcs = glob(["my_lib/**/*.py"])
    imports = ["."],
)

py_pytest_test_suite(
    name = "my_lib_test_suite",
    # Source files containing test helpers should go here.
    # Note that the test sources are excluded. This avoids
    # a test to be updated without invalidating all other
    # targets.
    srcs = glob(
        include = ["tests/**/*.py"],
        exclude = ["tests/**/*_test.py"],
    ),
    # Any data files the tests may need would be passed here
    data = glob(["tests/**/*.json"]),
    # This field is used for dedicated test files.
    tests = glob(["tests/**/*_test.py"]),
    deps = [
        ":my_lib",
    ],
)

For each file passed to tests, a py_pytest_test target will be created. From the example above, the user should expect to see the following test targets:

//:my_lib_test_suite
//:tests/test_mod_a
//:tests/test_mod_b
//:tests/test_mod_c

Additional Notes:

  • No file passed to tests should be passed found in the srcs or data attributes or tests will not be able to be individually cached.

PARAMETERS

NameDescriptionDefault Value
nameThe name of the test suitenone
testsA list of source files, typically glob(["tests/**/*_test.py"]), which are converted into test targets.none
argsArguments for the underlying py_pytest_test targets.[]
dataA list of additional data for the test. This field would also include python files containing test helper functionality.[]
kwargsKeyword arguments passed to the underlying py_test rule.none