From 18cd049c726ebb80402403951c2d0e547cafc08a Mon Sep 17 00:00:00 2001 From: Justin Buist Date: Wed, 11 Dec 2024 09:38:45 -0500 Subject: [PATCH 1/3] Now uses pytest-xdist; one process per test --- pyfrc/mains/cli_add_tests.py | 34 ++++++++++++++++++++++++++++- pyfrc/mains/cli_test.py | 25 ++++++++++++++++++++- pyfrc/test_support/pytest_plugin.py | 2 ++ setup.cfg | 1 + 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/pyfrc/mains/cli_add_tests.py b/pyfrc/mains/cli_add_tests.py index 404af8d..7b8a76a 100644 --- a/pyfrc/mains/cli_add_tests.py +++ b/pyfrc/mains/cli_add_tests.py @@ -10,6 +10,30 @@ from pyfrc.tests import * """ +conftest = """''' + This file registesr the PyFrcPlugin so it can be found during + distributed tests with pytest-xdist +''' + +import sys +import pathlib +from pyfrc.test_support.pytest_plugin import PyFrcPlugin + +# Add the location of robot.py to our path +parentdir = pathlib.Path(__file__).parent.parent +sys.path.append(str(parentdir)) +import robot + +def pytest_configure(config): + if config.pluginmanager.has_plugin("pyfrc_plugin"): + # Avoid double registration + return + robot_class = robot.MyRobot + robot_file = parentdir/'robot.py' + plugin = PyFrcPlugin(robot_class, robot_file) + config.pluginmanager.register(plugin, "pyfrc_plugin") +""" + class PyFrcAddTests: """ @@ -48,5 +72,13 @@ def run(self, main_file: pathlib.Path, project_path: pathlib.Path): fp.write(builtin_tests) print("- builtin tests created at", builtin_tests_file) + conftest_file = test_directory / "conftest.py" + if conftest_file.exists(): + print("- conftest.py already exists") + else: + with open(conftest_file, "w") as fp: + fp.write(conftest) + print("- conftest created at", conftest_file) + print() - print("Robot tests can be ran via 'python3 -m robotpy test'") + print("Robot tests can be ran via 'robotpy test'") diff --git a/pyfrc/mains/cli_test.py b/pyfrc/mains/cli_test.py index 5b59f33..5eec4b6 100644 --- a/pyfrc/mains/cli_test.py +++ b/pyfrc/mains/cli_test.py @@ -1,3 +1,5 @@ +import io +import re import os from os.path import abspath import inspect @@ -20,6 +22,23 @@ class _TryAgain(Exception): pass +def count_tests(test_path='.'): + import subprocess + # Run pytest in collect-only mode to get test count + result = subprocess.run( + ['pytest', '--collect-only', '-v', test_path], + capture_output=True, + text=True + ) + print('subprocess result: ') + print(result.stdout) + + # Count lines that look like test collections + test_lines = [line for line in result.stdout.split('\n') + if re.search(r'\s*test_\w+\[?', line) and 'cachedir' not in line] + + test_count = len(test_lines) + return test_count # # main test class @@ -112,8 +131,12 @@ def _run_test( pytest_args.insert(0, abspath(inspect.getfile(basic))) try: + test_count = count_tests() + print(f'Running {test_count} parallel workers') + + args = ['-v', '-n', str(test_count)] + pytest_args retv = pytest.main( - pytest_args, + args, plugins=[pytest_plugin.PyFrcPlugin(robot_class, main_file)], ) finally: diff --git a/pyfrc/test_support/pytest_plugin.py b/pyfrc/test_support/pytest_plugin.py index 0724319..e9c369b 100644 --- a/pyfrc/test_support/pytest_plugin.py +++ b/pyfrc/test_support/pytest_plugin.py @@ -38,6 +38,8 @@ def __init__(self, robot_class: Type[wpilib.RobotBase], robot_file: pathlib.Path robot_file.parent, ) + print('robot file: ', robot_file) + # Tests need to know when robotInit is called, so override the robot # to do that class TestRobot(robot_class): diff --git a/setup.cfg b/setup.cfg index c591ab6..4c1d911 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,6 +25,7 @@ packages = find: install_requires = pytest>=3.9 pytest-reraise + pytest-xdist>=3.6.1 pint>=0.11.0 wpilib>=2024.1.0,<2025 From bd7f85a8b784c06a4ee85be9685d979d03d71b7d Mon Sep 17 00:00:00 2001 From: Justin Buist Date: Thu, 12 Dec 2024 11:02:41 -0500 Subject: [PATCH 2/3] Moved the pytest_configure() hook to setup plugins --- pyfrc/mains/cli_test.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pyfrc/mains/cli_test.py b/pyfrc/mains/cli_test.py index 5eec4b6..e8aa468 100644 --- a/pyfrc/mains/cli_test.py +++ b/pyfrc/mains/cli_test.py @@ -19,6 +19,24 @@ # could be a useful thing. Will have to consider that later. +import sys +import pathlib +from pyfrc.test_support.pytest_plugin import PyFrcPlugin +# Tests are always run from the top directory of the robot project +# so the location of robot.py should be the current working directory +sys.path.append('.') +import robot + +def pytest_configure(config): + if config.pluginmanager.has_plugin("pyfrc_plugin"): + # Avoid double registration + return + robot_class = robot.MyRobot + robot_file = './robot.py' + plugin = PyFrcPlugin(robot_class, robot_file) + config.pluginmanager.register(plugin, "pyfrc_plugin") + + class _TryAgain(Exception): pass From ae95c08feed91473461b9bad3365082d09a98de8 Mon Sep 17 00:00:00 2001 From: Justin Buist Date: Thu, 12 Dec 2024 11:49:14 -0500 Subject: [PATCH 3/3] Move plugin registration out of robot project --- pyfrc/mains/cli_add_tests.py | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/pyfrc/mains/cli_add_tests.py b/pyfrc/mains/cli_add_tests.py index 7b8a76a..0bb013d 100644 --- a/pyfrc/mains/cli_add_tests.py +++ b/pyfrc/mains/cli_add_tests.py @@ -10,30 +10,6 @@ from pyfrc.tests import * """ -conftest = """''' - This file registesr the PyFrcPlugin so it can be found during - distributed tests with pytest-xdist -''' - -import sys -import pathlib -from pyfrc.test_support.pytest_plugin import PyFrcPlugin - -# Add the location of robot.py to our path -parentdir = pathlib.Path(__file__).parent.parent -sys.path.append(str(parentdir)) -import robot - -def pytest_configure(config): - if config.pluginmanager.has_plugin("pyfrc_plugin"): - # Avoid double registration - return - robot_class = robot.MyRobot - robot_file = parentdir/'robot.py' - plugin = PyFrcPlugin(robot_class, robot_file) - config.pluginmanager.register(plugin, "pyfrc_plugin") -""" - class PyFrcAddTests: """ @@ -72,13 +48,4 @@ def run(self, main_file: pathlib.Path, project_path: pathlib.Path): fp.write(builtin_tests) print("- builtin tests created at", builtin_tests_file) - conftest_file = test_directory / "conftest.py" - if conftest_file.exists(): - print("- conftest.py already exists") - else: - with open(conftest_file, "w") as fp: - fp.write(conftest) - print("- conftest created at", conftest_file) - - print() print("Robot tests can be ran via 'robotpy test'")