Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bazelversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
9.x
9.1.1
1 change: 0 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ The `repository_ctx` API docs are at: https://bazel.build/rules/lib/builtins/rep
e.g. given `load("//foo:bar.bzl", ...)`, the target is `//foo:bar_bzl`.
* For files outside rules_python: remove the `.bzl` suffix. e.g. given
`load("@foo//foo:bar.bzl", ...)`, the target is `@foo//foo:bar`.
* `bzl_library()` targets should be kept in alphabetical order by name.

Example:

Expand Down
2 changes: 1 addition & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ dev_pip.parse(
python_version = "3.11",
requirements_lock = "//tests/multi_pypi/beta:requirements.txt",
)
use_repo(dev_pip, "dev_pip", "pypi_alpha", "pypi_beta", "pypiserver")
use_repo(dev_pip, "dev_pip", "pypi", "pypi_alpha", "pypi_beta", "pypiserver")
Comment thread
rickeylev marked this conversation as resolved.

# Bazel integration test setup below

Expand Down
1 change: 1 addition & 0 deletions docs/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ sphinx_build_binary(
target_compatible_with = _TARGET_COMPATIBLE_WITH,
deps = [
"@dev_pip//myst_parser",
"@dev_pip//pytest",
"@dev_pip//readthedocs_sphinx_ext",
"@dev_pip//sphinx",
"@dev_pip//sphinx_autodoc2",
Expand Down
2 changes: 2 additions & 0 deletions docs/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ dependencies = [
"pyelftools",
"macholib",
"markupsafe",
"pytest",
"pytest-bazel",
]
278 changes: 140 additions & 138 deletions docs/requirements.txt

Large diffs are not rendered by default.

112 changes: 112 additions & 0 deletions docs/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions news/pytest_test.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(pytest) Added `pytest_test` macro to run pytest tests using `pytest-bazel`
from PyPI.
5 changes: 5 additions & 0 deletions python/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,11 @@ alias(
deprecation = "Use //python:py_test instead",
)

bzl_library(
name = "pytest_test",
deps = ["//python/private/pytest_test"],
)

alias(
name = "python_bzl",
actual = ":python",
Expand Down
1 change: 1 addition & 0 deletions python/features.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ _TARGETS = {
"//python:py_runtime_info": True,
"//python:py_runtime_pair": True,
"//python:py_test": True,
"//python:pytest_test": True,
"//python:repositories": True,
"//python:versions": True,
}
Expand Down
27 changes: 27 additions & 0 deletions python/private/pytest_test/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")

package(default_visibility = ["//:__subpackages__"])

filegroup(
name = "bootstrap_template",
srcs = ["pytest_bootstrap_template.py"],
)

bzl_library(
name = "pytest_test",
deps = [
"//python:py_test",
],
)
Comment on lines +10 to +15

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The bzl_library target is missing the srcs attribute. Please include pytest_test.bzl in srcs so that downstream bzl_library targets can correctly depend on it.

Suggested change
bzl_library(
name = "pytest_test",
deps = [
"//python:py_test",
],
)
bzl_library(
name = "pytest_test",
srcs = ["pytest_test.bzl"],
deps = [
"//python:py_test",
],
)


# These aliases are used to avoid duplicate targets in the deps list
alias(
name = "default_pytest",
actual = "@pypi//pytest",
)

# These aliases are used to avoid duplicate targets in the deps list
alias(
name = "default_pytest_bazel",
actual = "@pypi//pytest_bazel",
)
8 changes: 8 additions & 0 deletions python/private/pytest_test/pytest_bootstrap_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import sys

import pytest_bazel

TEST_FILES = """%TEST_FILES%""".splitlines()

args = sys.argv[1:] + TEST_FILES
sys.exit(pytest_bazel.main(args))
Comment thread
rickeylev marked this conversation as resolved.
84 changes: 84 additions & 0 deletions python/private/pytest_test/pytest_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""pytest_test rule implementation."""

load("//python:py_test.bzl", "py_test")

_DEFAULT_PYTEST = Label("//python/private/pytest_test:default_pytest")
_DEFAULT_PYTEST_BAZEL = Label("//python/private/pytest_test:default_pytest_bazel")

def pytest_test(
*,
name,
srcs,
pytest = None,
pytest_bazel = None,
**kwargs):
"""Run pytest tests.

Args:
name: A unique name for this target.
srcs: List of source files (test files). These are the files that
pytest will run as tests.
pytest: The pytest target to use. Defaults to @pypi//pytest.
pytest_bazel: The pytest-bazel target to use. Defaults to
@pypi//pytest_bazel.
**kwargs: Additional arguments passed to py_test. Note that `main` is
not a supported argument.
"""
if pytest == None:
pytest = _DEFAULT_PYTEST
if pytest_bazel == None:
pytest_bazel = _DEFAULT_PYTEST_BAZEL

bootstrap_target = name + "_bootstrap"
main_file = name + "_boot.py"
_write_pytest_bootstrap(
name = bootstrap_target,
srcs = srcs,
output_name = main_file,
)

py_test(
name = name,
main = main_file,
srcs = [bootstrap_target] + srcs,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If srcs is a select(), concatenating it as [bootstrap_target] + srcs will fail with a Starlark evaluation error because list-plus-select concatenation is not supported (only select-plus-list is supported). Reversing the order to srcs + [bootstrap_target] resolves this and makes the rule compatible with select()s.

Suggested change
srcs = [bootstrap_target] + srcs,
srcs = srcs + [bootstrap_target],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bootstrap is not needed, we can just use the main_module that already exists in the py_test rule.

deps = kwargs.pop("deps", []) + [
pytest,
pytest_bazel,
],
**kwargs
)

def _map_file(f):
return f.short_path

def _write_pytest_bootstrap_impl(ctx):
output = ctx.actions.declare_file(ctx.attr.output_name)

computed_subs = ctx.actions.template_dict()

computed_subs.add_joined(
"%TEST_FILES%",
depset(ctx.files.srcs),
join_with = "\n",
map_each = _map_file,
)

ctx.actions.expand_template(
output = output,
template = ctx.file._bootstrap_template,
substitutions = {},
computed_substitutions = computed_subs,
)
Comment on lines +57 to +71

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since ctx.files.srcs is already a flat list of files available at analysis time, using computed_substitutions and template_dict is unnecessary and adds extra complexity. We can simplify this by using standard substitutions with a simple string join, which is also more compatible with older Bazel versions.

    ctx.actions.expand_template(
        output = output,
        template = ctx.file._bootstrap_template,
        substitutions = {
            "%TEST_FILES%": "\n".join([f.short_path for f in ctx.files.srcs]),
        },
    )

return [DefaultInfo(files = depset([output]))]

_write_pytest_bootstrap = rule(
implementation = _write_pytest_bootstrap_impl,
attrs = {
"output_name": attr.string(mandatory = True),
"srcs": attr.label_list(allow_files = True),
"_bootstrap_template": attr.label(
default = "//python/private/pytest_test:bootstrap_template",
allow_single_file = True,
),
},
)
5 changes: 5 additions & 0 deletions python/pytest_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""pytest_test rule re-export."""

load("//python/private/pytest_test:pytest_test.bzl", _pytest_test = "pytest_test")

pytest_test = _pytest_test
22 changes: 22 additions & 0 deletions tests/pytest_test/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
load("//python:pytest_test.bzl", "pytest_test")
load("//tests/support:support.bzl", "SUPPORTS_BZLMOD")

pytest_test(
name = "pytest_script_venv_test",
srcs = [
"basic_test.py",
],
config_settings = {
"@rules_python//python/config_settings:bootstrap_impl": "script",
"@rules_python//python/config_settings:venvs_site_packages": "yes",
},
Comment thread
rickeylev marked this conversation as resolved.
target_compatible_with = SUPPORTS_BZLMOD,
)

pytest_test(
name = "pytest_default_test",
srcs = [
"basic_test.py",
],
target_compatible_with = SUPPORTS_BZLMOD,
)
2 changes: 2 additions & 0 deletions tests/pytest_test/basic_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def test_foo():
assert True
Loading