Python API Reference#
pw_build: Integrations for Bazel, GN, and CMake
pw_build.runfiles_manager#
A library that bridges runfiles management between Bazel and bootstrap.
- class pw_build.runfiles_manager.RunfilesManager#
A class that helps manage runtime file resources.
Projects that use bootstrap get their files from the currently activated environment. In contrast, Bazel-based projects will get their files from Bazel’s runfiles mechanism.
This class bridges those differences, and simplifies the process of writing tools that work in both environments. Every resource is associated with a key used to retrieve the resource, and the resources must be registered twice: once for Bazel-based projects, and once for other projects that run from a shell environment bootstrapped by pw_env_setup. To ensure consistency, if a resource is used by one environment, an error will be emitted if it was never registered for the other environment.
If a file is exclusive to one of the two environments, it may be tagged as
exclusive=Trueto suppress the error emitted if a resource isn’t properly registered for the other environment. Attempting to access a resourceexclusiveto a different environment will still raise an error.This class is also a
pw_cli.tool_runner.ToolRunner, and may be used to launch subprocess actions.- __init__()#
- add_bazel_file(key: str, import_path: str, exclusive: bool = False) None#
Maps a non-executable file resource to the provided key.
Files added through this mechanism will be available when running from the Bazel build. Unless you specify
exclusive=True, you must also register this file withpw_build.runfiles_manager.RunfilesManager.add_bootstrapped_file()before attempting to use it.The
import_pathis the import path of thepw_py_importable_runfilerule that provides the desired file.
- add_bazel_tool(tool_name: str, import_path: str, exclusive: bool = False) None#
Maps a runnable tool to the provided tool name.
Files added through this mechanism will be available when running from the Bazel build. Unless you specify
exclusive=True, you must also register this file withpw_build.runfiles_manager.RunfilesManager.add_bootstrapped_tool()before attempting to use it.The
import_pathis the import path of thepw_py_importable_runfilerule that provides the desired file.
- add_bootstrapped_file(key: str, path_or_env: str, exclusive: bool = False) None#
Maps a non-executable file resource to the provided key.
Files added through this mechanism will be available from an activated environment constructed via pw_env_setup. Unless you specify
exclusive=True, you must also register this file withpw_build.runfiles_manager.RunfilesManager.add_bazel_file()before attempting to use it.Environment variables may be expanded using
${PW_FOO}within the path expression.
- add_bootstrapped_tool(
- tool_name: str,
- path_or_env: str,
- from_shell_path: bool = False,
- exclusive: bool = False,
Maps a runnable tool to the provided tool name.
Files added through this mechanism will be available from an activated environment constructed via pw_env_setup. Unless you specify
exclusive=True, you must also register this tool withpw_build.runfiles_manager.RunfilesManager.add_bazel_tool()before attempting to use it.Environment variables may be expanded using
${PW_FOO}within the path expression. Iffrom_shell_path=Trueis enabled, the active shellPATHis searched for the requested tool, and environment variables will not be expanded.
- get(key: str) Path#
Retrieves the
Pathto the resource at the requested key.
pw_build.generated_tests#
Tools for generating Pigweed tests that execute in C++ and Python.
This module provides a way to write data-driven tests that can be executed in multiple languages, ensuring that the implementations behave identically.
The core of this module is the TestGenerator class, which takes a
sequence of test cases and generates tests for Python, C++, and TypeScript.
The following example shows how to use generated_tests.py:
1from pw_build import generated_tests
2
3# Define test cases as a sequence of (input, expected_output) tuples.
4# Use strings as titles for a group of test cases.
5TEST_CASES = (
6 'Simple strings',
7 ('hello', 5),
8 ('world', 5),
9 'Empty and single-character',
10 ('', 0),
11 ('a', 1),
12)
13
14
15# Define a Python test generator function.
16def _define_py_test(ctx: generated_tests.Context):
17 input_str, expected = ctx.test_case
18 # Return a function that will be used as a unittest.TestCase method.
19 return lambda self: self.assertEqual(len(input_str), expected)
20
21
22# Define a C++ test generator function.
23def _define_cc_test(ctx: generated_tests.Context):
24 input_str, expected = ctx.test_case
25 # Yield C++ code for the test case.
26 yield f'TEST(ReverseString, {ctx.cc_name()}) {{'
27 yield f' EXPECT_EQ(std::string_view("{input_str}").size(), {expected}u);'
28 yield '}'
29
30
31CC_HEADER = """\
32#include <string_view>
33
34#include "pw_unit_test/framework.h"
35
36namespace {
37"""
38
39# Create a TestGenerator instance.
40TESTS = generated_tests.TestGenerator(
41 TEST_CASES,
42 cc_test=(_define_cc_test, CC_HEADER, '} // namespace'),
43)
44
45# Create the Python test class.
46ReverseStringTest = TESTS.python_tests('ReverseStringTest', _define_py_test)
47
48# Run the Python tests or generate other tests, depending on the command line
49# arguments.
50if __name__ == '__main__':
51 generated_tests.main(TESTS)
After the test generation code is written, add the Python tests to the build like a regular Python test:
pw_py_test(
name = "generated_tests_example_test",
size = "small",
srcs = ["generated_tests_example_test.py"],
deps = [":pw_build"],
)
A little more work is required to generate tests for other languagues. Start by
declaring the script as a pw_py_binary.
pw_py_binary(
name = "generate_example_generated_test",
srcs = ["generated_tests_example_test.py"],
main = "generated_tests_example_test.py",
deps = [":pw_build"],
)
Then, for each language, declare a run_binary target to generate the test
source and a test target to run it. For C++, this is done as follows:
run_binary(
name = "generate_example_generated_cc_test",
outs = ["example_generated_cc_test.cc"],
args = [
"--generate-cc-test",
"$(execpath :example_generated_cc_test.cc)",
],
tool = ":generate_example_generated_test",
visibility = ["//visibility:private"],
)
pw_cc_test(
name = "example_generated_cc_test",
srcs = [":generate_example_generated_cc_test"],
)
It is also possible to generate tests for other languages and check them in, but that is not recommended, since the tests may become outdated.
- class pw_build.generated_tests.CcTest(
- generator: Callable[[Context[T]], Iterable[str]],
- header: str,
- footer: str,
Captures how to generate a C++ test.
- generator#
Function that takes a
Contextand produces the C++ test.- Type:
Callable[[pw_build.generated_tests.Context[pw_build.generated_tests.T]], Iterable[str]]
- header#
Header that is output before the tests.
- Type:
str
Footer that is output after the tests.
- Type:
str
- class pw_build.generated_tests.Context(group: str, count: int, total: int, test_case: T)#
Information about a particular test case passed to generator functions.
- group#
The name of the test group.
- Type:
str
- count#
The 1-based index of this test case within the group.
- Type:
int
- total#
The total number of test cases in the group.
- Type:
int
- test_case#
The test case object from the list provided to the :class:TestGenerator.
- Type:
pw_build.generated_tests.T
- __init__(group: str, count: int, total: int, test_case: T) None#
- exception pw_build.generated_tests.Error#
Base class for exceptions raised by this module.
- class pw_build.generated_tests.TestGenerator(
- test_cases: Sequence[str | T],
- *,
- cc_test: tuple[Callable[[Context[T]], Iterable[str]], str, str] | CcTest | None = None,
- ts_test: tuple[Callable[[Context[T]], Iterable[str]], str, str] | TsTest | None = None,
Generates tests for multiple languages from a series of test cases.
This class orchestrates the generation of tests for Python, C++, and TypeScript. It takes a sequence of test cases and uses generator functions to produce the corresponding tests for each language.
- __init__(
- test_cases: Sequence[str | T],
- *,
- cc_test: tuple[Callable[[Context[T]], Iterable[str]], str, str] | CcTest | None = None,
- ts_test: tuple[Callable[[Context[T]], Iterable[str]], str, str] | TsTest | None = None,
- cc_tests(output: TextIO) None#
Writes C++ unit tests for each test case to the given file.
- python_tests(
- name: str,
- define_py_test: Callable[[Context[T]], Callable[[TestCase], None]],
Returns a Python unittest.TestCase class with tests for each case.
- ts_tests(output: TextIO) None#
Writes TypeScript unit tests for each test case to the given file.
- class pw_build.generated_tests.TsTest(
- generator: Callable[[Context[T]], Iterable[str]],
- header: str,
- footer: str,
Captures how to generate a TypeScript test.
- generator#
Function that takes a
Contextand produces the TypeScript test.- Type:
Callable[[pw_build.generated_tests.Context[pw_build.generated_tests.T]], Iterable[str]]
- header#
Header that is output before the tests.
- Type:
str
Footer that is output after the tests.
- Type:
str
- pw_build.generated_tests.cc_string(data: str | bytes) str#
Returns a C++ string literal version of bytes or a UTF-8 string.
Adds quotes and handles escaping. Minimizes the number of characters required.
- pw_build.generated_tests.main(*tests: TestGenerator) None#
Runs the test generation or the Python tests.
If command line arguments for generating C++ or TypeScript tests are provided, this function generates those tests. Otherwise, it runs the Python unit tests.