pytest-threadpool 0.3.5__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/.gitignore +3 -0
- pytest_threadpool-0.4.0/CHANGELOG.md +161 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/PKG-INFO +125 -17
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/README.md +121 -14
- pytest_threadpool-0.4.0/ROADMAP.md +159 -0
- pytest_threadpool-0.4.0/examples/test_event_bus/event_bus.py +76 -0
- pytest_threadpool-0.4.0/examples/test_event_bus/test_event_bus.py +110 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_queue/test_queue.py +23 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/pyproject.toml +5 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/_fixtures.py +23 -3
- pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/__init__.py +40 -0
- pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_ansi.py +87 -0
- pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_buffer.py +40 -0
- pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_cursor.py +73 -0
- pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_display.py +386 -0
- pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_field.py +145 -0
- pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_input.py +244 -0
- pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_layout.py +101 -0
- pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_scroll_column.py +46 -0
- pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_status_line.py +46 -0
- pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_tree_overlay.py +435 -0
- pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_view_manager.py +763 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/_markers.py +25 -31
- pytest_threadpool-0.4.0/src/pytest_threadpool/_runner.py +1612 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/_version.py +2 -2
- pytest_threadpool-0.4.0/src/pytest_threadpool/hooks.py +26 -0
- pytest_threadpool-0.4.0/src/pytest_threadpool/plugin.py +175 -0
- pytest_threadpool-0.4.0/tests/integration_tests/__init__.py +3 -0
- pytest_threadpool-0.4.0/tests/integration_tests/cases/caplog_parallel.py +96 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/capture_print_parallel.py +3 -1
- pytest_threadpool-0.4.0/tests/integration_tests/cases/capture_scoped_output.py +57 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/capture_two_groups.py +5 -3
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/class_barrier_concurrency.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/class_single_method.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/class_thread_verification.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/collected_count.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_first_item_setup_fail.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_keyboard_interrupt.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_maxfail_parallel.py +4 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_nested_threads.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_sigint.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_sigint_many.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_system_exit.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_teardown_exception.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_worker_exception.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_autouse_function.py +3 -1
- pytest_threadpool-0.4.0/tests/integration_tests/cases/fixture_class_across_groups.py +50 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_class_scoped_once.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_class_yield.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_addfinalizer.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_chain.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_from_conftest.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_implicit_scope.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_mixed_parallel.py +4 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_multiple_per_test.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_setup_parallel.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_with_shared_deps.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_with_tmp_path.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_with_xunit.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_yield_teardown.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_function_scoped.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_interdependent_finalizers.py +3 -1
- pytest_threadpool-0.4.0/tests/integration_tests/cases/fixture_module_across_groups.py +52 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_multiple_scopes.py +3 -1
- pytest_threadpool-0.4.0/tests/integration_tests/cases/fixture_package_across_groups.py +72 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_parameterized.py +3 -1
- pytest_threadpool-0.4.0/tests/integration_tests/cases/fixture_session_across_groups.py +52 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_teardown_exception.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_yield_cleanup.py +3 -1
- pytest_threadpool-0.4.0/tests/integration_tests/cases/logging_basic_parallel.py +42 -0
- pytest_threadpool-0.4.0/tests/integration_tests/cases/logging_streamhandler.py +57 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/marks_custom.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/marks_standard.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/reporting_incremental.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/reporting_single_file_params.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/reporting_stdout_during_parallel.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/runner_collect_only.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/runner_setup_only.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/runner_setup_show.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/runner_single_parallel_item.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/runner_single_worker.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_all_merged.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_all_not_parallelizable.py +5 -5
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_children_on_function.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_children_separate_params.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_dynamic_parametrize.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_method_overrides_class.py +4 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_mixed_fail_skip.py +5 -3
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_module_children.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_not_parallelizable_function.py +4 -4
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_not_parallelizable_method.py +3 -3
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_parameters.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_two_classes_mixed.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/setup_all_fail.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/setup_mixed_pass_fail.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/shared_counter.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/shared_cross_group_non_pickleable.py +3 -3
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/shared_dict_mutation.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/shared_non_pickleable.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/shared_two_phase_barrier.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/teardown_after_test_failure.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/teardown_parallel_timing.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/teardown_same_thread.py +3 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/teardown_xunit_function.py +3 -3
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/teardown_xunit_method_thread.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/validate_threadpool.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_class_setup.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_combined_setup.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_function_mixed_parallel.py +4 -4
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_method_mixed_parallel.py +3 -3
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_method_setup.py +2 -2
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_method_teardown_runs.py +2 -2
- pytest_threadpool-0.4.0/tests/integration_tests/cases/xunit_setup_class_across_groups.py +61 -0
- pytest_threadpool-0.4.0/tests/integration_tests/cases/xunit_setup_method_across_groups.py +53 -0
- pytest_threadpool-0.4.0/tests/integration_tests/cases/xunit_setup_module_across_groups.py +47 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/conftest.py +8 -2
- pytest_threadpool-0.4.0/tests/integration_tests/test_caplog.py +100 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_capture.py +53 -6
- pytest_threadpool-0.4.0/tests/integration_tests/test_ide_reporter.py +353 -0
- pytest_threadpool-0.4.0/tests/integration_tests/test_live_view.py +689 -0
- pytest_threadpool-0.4.0/tests/integration_tests/test_logging.py +247 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_class.py +5 -1
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_fixtures.py +39 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_xunit.py +18 -0
- pytest_threadpool-0.4.0/tests/integration_tests/test_scoped_output.py +307 -0
- pytest_threadpool-0.4.0/tests/unit_tests/__init__.py +3 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/__init__.py +0 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/conftest.py +8 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_ansi.py +87 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_buffer.py +57 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_content_search.py +48 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_cursor.py +94 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_display.py +336 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_field.py +184 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_input.py +92 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_layout.py +75 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_scroll_column.py +55 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_scroll_latency.py +571 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_status_line.py +57 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_tree_overlay.py +325 -0
- pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_view_manager.py +278 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/unit_tests/test_unit_grouping.py +4 -12
- pytest_threadpool-0.4.0/tests/unit_tests/test_unit_runner.py +142 -0
- pytest_threadpool-0.3.5/CHANGELOG.md +0 -19
- pytest_threadpool-0.3.5/ROADMAP.md +0 -83
- pytest_threadpool-0.3.5/examples/test_event_bus/event_bus.py +0 -85
- pytest_threadpool-0.3.5/examples/test_event_bus/test_event_bus.py +0 -112
- pytest_threadpool-0.3.5/examples/test_queue/conftest.py +0 -16
- pytest_threadpool-0.3.5/examples/test_queue/user_pool.py +0 -26
- pytest_threadpool-0.3.5/src/pytest_threadpool/_runner.py +0 -897
- pytest_threadpool-0.3.5/src/pytest_threadpool/plugin.py +0 -82
- pytest_threadpool-0.3.5/tests/integration_tests/__init__.py +0 -3
- pytest_threadpool-0.3.5/tests/unit_tests/__init__.py +0 -3
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/.github/workflows/ci.yml +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/.github/workflows/publish.yml +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/.pre-commit-config.yaml +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/CONTRIBUTING.md +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/LICENSE +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/codecov.yml +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/__init__.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/__init__.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/conftest.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/container.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/providers.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/services.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/test_factory.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/test_local.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/test_singleton.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/test_thread_local.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_event_bus/__init__.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_logging/__init__.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_logging/test_log_capture.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_queue/__init__.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_shared_state/__init__.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_shared_state/test_barrier.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_shared_state/test_counter.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_shared_state/test_counter_async.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/scripts/setup-dev +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/__init__.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/_api.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/_constants.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/_grouping.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/py.typed +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/__init__.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/__init__.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/_templates.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_cross_module_group.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_worker_exception_conftest.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_from_conftest_conftest.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/parallel_only_skip.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/reporting_cross_module.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/reporting_incremental_conftest.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/reporting_package_children.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/sequential_bare_functions.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/sequential_unmarked_class.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/validate_threadpool_conftest.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_function_setup.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_module_setup.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_edge_cases.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_func_fixtures.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_marks.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_package.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_parallel_teardown.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_reporting.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_scopes.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_sequential.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_shared.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/unit_tests/test_unit_api.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/unit_tests/test_unit_fixtures.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/unit_tests/test_unit_markers.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/unit_tests/test_unit_plugin.py +0 -0
- {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/unit_tests/test_unit_stream_proxy.py +0 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Highlights
|
|
6
|
+
|
|
7
|
+
- **Interactive live-view terminal UI** (`--threadpool-output live`) with
|
|
8
|
+
split-pane layout, test tree navigation, and real-time output inspection.
|
|
9
|
+
|
|
10
|
+
### Live-view features
|
|
11
|
+
|
|
12
|
+
- **Split-pane layout**: `Tab` opens a tree panel on the left with the main
|
|
13
|
+
content on the right, both independently scrollable.
|
|
14
|
+
- **Test tree**: Full session hierarchy (packages > modules > classes > tests)
|
|
15
|
+
with live outcome markers (`✓` passed, `✗` failed, `E` error, `s` skipped,
|
|
16
|
+
`x` xfail, `X` xpass). Groups show aggregated status.
|
|
17
|
+
- **Fuzzy search**: Type in the tree panel to fuzzy-filter tests (fzf-style
|
|
18
|
+
subsequence matching). `Escape` clears the query.
|
|
19
|
+
- **Context switching**: `Enter` on a test shows its captured output (stdout,
|
|
20
|
+
stderr, logs, colored tracebacks) in the content pane. `Enter` on a group
|
|
21
|
+
shows combined output for all descendants. `Summary` node returns to the
|
|
22
|
+
main progress view.
|
|
23
|
+
- **Outcome filters**: `Ctrl+P` toggles passed test visibility, `Ctrl+X`
|
|
24
|
+
toggles failed test visibility. Empty groups are automatically hidden.
|
|
25
|
+
- **Content search**: `/` activates vim-style search within the content pane.
|
|
26
|
+
`n`/`N` navigate matches. Current match highlighted in orange, other matches
|
|
27
|
+
in grey. `Escape` clears search.
|
|
28
|
+
- **Save to file**: `Ctrl+W` saves the full active buffer (ANSI-stripped) to
|
|
29
|
+
`logs/{name}_{timestamp}.log`.
|
|
30
|
+
- **Focus switching**: `Ctrl+←`/`Ctrl+→` switches keyboard focus between panes.
|
|
31
|
+
Mouse scroll targets whichever pane the cursor is over.
|
|
32
|
+
- **Keybinds hint line**: Bottom bar shows available keyboard shortcuts.
|
|
33
|
+
- **Configurable tree width**: `threadpool_tree_width` ini setting (supports
|
|
34
|
+
`pyproject.toml`, `pytest.ini`).
|
|
35
|
+
|
|
36
|
+
### Test outcome markers
|
|
37
|
+
|
|
38
|
+
- Added `x` (xfail), `X` (xpass), and `E` (setup/teardown error) markers
|
|
39
|
+
to the live reporter alongside existing `.` (pass), `F` (fail), `s` (skip).
|
|
40
|
+
- Sequential nodeid-style output now shows `XFAIL`, `XPASS`, and `ERROR` words.
|
|
41
|
+
|
|
42
|
+
### Scroll responsiveness
|
|
43
|
+
|
|
44
|
+
- Fixed scroll input being unresponsive after tests finish — root cause was
|
|
45
|
+
multiple competing `InputReader` threads stealing from the shared terminal
|
|
46
|
+
input buffer on free-threaded Python.
|
|
47
|
+
- `InputReader` now uses `os.dup()` to create a private fd immune to pytest
|
|
48
|
+
capture redirections.
|
|
49
|
+
- Device-level singleton ensures only one active reader per terminal device.
|
|
50
|
+
- `ensure_entered()` uses `threading.Event` + lock for thread-safe
|
|
51
|
+
initialization on free-threaded Python.
|
|
52
|
+
- `ensure_cbreak()` uses `TCSANOW` to avoid flushing pending input.
|
|
53
|
+
|
|
54
|
+
### Architecture
|
|
55
|
+
|
|
56
|
+
- Region-based dirty tracking (`Region` enum) for independent pane rendering
|
|
57
|
+
without cross-pane flicker.
|
|
58
|
+
- `Display.redraw_buffer()` supports `left_offset` for split-pane rendering,
|
|
59
|
+
`highlight`/`highlight_line` for search result visualization.
|
|
60
|
+
- `Display.redraw_pane()` and `redraw_separator()` for side panel rendering.
|
|
61
|
+
|
|
62
|
+
### Tests
|
|
63
|
+
|
|
64
|
+
- Integration tests for all test outcome markers (pass, fail, skip, xfail,
|
|
65
|
+
xpass, error) in both classic and live modes.
|
|
66
|
+
- Integration test for tree panel rendering.
|
|
67
|
+
- Unit tests for tree overlay (navigation, fuzzy search, outcome filters,
|
|
68
|
+
group markers, expand/collapse).
|
|
69
|
+
- Unit tests for content search highlighting.
|
|
70
|
+
- Unit tests for scroll latency.
|
|
71
|
+
|
|
72
|
+
## 0.3.6
|
|
73
|
+
|
|
74
|
+
### Fixes
|
|
75
|
+
|
|
76
|
+
- Fixed session, module, and class-scoped fixtures being torn down and
|
|
77
|
+
re-created between parallel groups instead of being resolved once and
|
|
78
|
+
shared for their entire scope. The same fix applies to xunit-style
|
|
79
|
+
`setup_module`/`setup_class` hooks.
|
|
80
|
+
|
|
81
|
+
## 0.3.5
|
|
82
|
+
|
|
83
|
+
### Fixes
|
|
84
|
+
|
|
85
|
+
- Fixed crash (KeyError) when a worker thread throws an unexpected exception
|
|
86
|
+
outside the normal test lifecycle — failures are now reported gracefully
|
|
87
|
+
instead of taking down the entire test run.
|
|
88
|
+
- `--threadpool` with a non-numeric value (e.g. `--threadpool foo`) now raises
|
|
89
|
+
a clean `pytest.UsageError` instead of an unhandled `ValueError` traceback.
|
|
90
|
+
- `@parallelizable("children")` applied directly to a test function now emits
|
|
91
|
+
a warning explaining that functions have no children, instead of being
|
|
92
|
+
silently ignored.
|
|
93
|
+
|
|
94
|
+
### Cleanup
|
|
95
|
+
|
|
96
|
+
- Moved `ParallelScope` import to module top in `_markers.py`, removed
|
|
97
|
+
misleading circular-import comment.
|
|
98
|
+
|
|
99
|
+
## 0.3.4
|
|
100
|
+
|
|
101
|
+
### Highlights
|
|
102
|
+
|
|
103
|
+
- GIL-enabled builds now supported — `--threadpool` no longer raises
|
|
104
|
+
`UsageError` on non-free-threaded Python; it issues a warning instead
|
|
105
|
+
and runs with GIL-limited parallelism.
|
|
106
|
+
- Thread-safe stdout/stderr capture via `_ThreadLocalStream` proxy,
|
|
107
|
+
preventing worker `print()` output from corrupting test result lines.
|
|
108
|
+
- Package-group merging — split package-level parallel groups (interrupted
|
|
109
|
+
by sequential `@not_parallelizable` items) are merged back together.
|
|
110
|
+
|
|
111
|
+
### New examples
|
|
112
|
+
|
|
113
|
+
- DI container, parallel logging, user pool with LIFO queue, shared state
|
|
114
|
+
patterns (barrier, atomic counter, async counter).
|
|
115
|
+
|
|
116
|
+
### Improvements
|
|
117
|
+
|
|
118
|
+
- Cross-module package groups correctly initialize per-module shared fixtures.
|
|
119
|
+
- Mixed parallel/sequential reporting with `nodeid PASSED` format.
|
|
120
|
+
- Live reporter line separation fixes between groups and transitions.
|
|
121
|
+
|
|
122
|
+
### Build & CI
|
|
123
|
+
|
|
124
|
+
- Python version matrix expanded to 3.13, 3.13t, 3.14, 3.14t, 3.15, 3.15t.
|
|
125
|
+
- Codecov integration, CI ignores tag pushes.
|
|
126
|
+
|
|
127
|
+
## 0.3.3
|
|
128
|
+
|
|
129
|
+
### Build & CI
|
|
130
|
+
|
|
131
|
+
- Added GitHub Actions workflows for CI and PyPI publishing.
|
|
132
|
+
- Integrated `hatch-vcs` for automatic version management.
|
|
133
|
+
|
|
134
|
+
## 0.3.2
|
|
135
|
+
|
|
136
|
+
### Features
|
|
137
|
+
|
|
138
|
+
- Parallelized function-scoped fixture teardowns — `yield` cleanup,
|
|
139
|
+
`addfinalizer` callbacks, and xunit `teardown_method` now run in
|
|
140
|
+
worker threads alongside test calls.
|
|
141
|
+
|
|
142
|
+
## 0.3.1
|
|
143
|
+
|
|
144
|
+
### Cleanup
|
|
145
|
+
|
|
146
|
+
- Removed unused `selenium` dependency.
|
|
147
|
+
|
|
148
|
+
## 0.3.0
|
|
149
|
+
|
|
150
|
+
### Features
|
|
151
|
+
|
|
152
|
+
- Parallelized function-scoped fixture setups — each worker creates
|
|
153
|
+
independent fixture instances from cloned `FixtureDef` objects.
|
|
154
|
+
- Shared fixtures (module/class/session) resolved once sequentially
|
|
155
|
+
before workers launch.
|
|
156
|
+
|
|
157
|
+
## 0.2.0
|
|
158
|
+
|
|
159
|
+
- Initial beta release with core parallel execution engine.
|
|
160
|
+
- Marker-based parallelism (`children`, `parameters`, `all`).
|
|
161
|
+
- Priority chain: `not_parallelizable` > own > class > module > package.
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-threadpool
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Parallel test execution
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Parallel test execution using threads — true parallelism on free-threaded Python, concurrent I/O on standard builds
|
|
5
5
|
Project-URL: Homepage, https://github.com/pytest-threadpool/pytest-threadpool
|
|
6
6
|
Project-URL: Source, https://github.com/pytest-threadpool/pytest-threadpool
|
|
7
7
|
Project-URL: Issues, https://github.com/pytest-threadpool/pytest-threadpool/issues
|
|
8
8
|
License-Expression: Apache-2.0
|
|
9
9
|
License-File: LICENSE
|
|
10
|
-
Keywords: free-threaded,nogil,parallel,pytest,pytest parallel,testing,threadpool
|
|
10
|
+
Keywords: concurrent testing,free-threaded,nogil,parallel,pytest,pytest parallel,sdet,test automation,testing,threadpool
|
|
11
11
|
Classifier: Development Status :: 4 - Beta
|
|
12
12
|
Classifier: Framework :: Pytest
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Information Technology
|
|
14
15
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
16
|
Classifier: Programming Language :: Python :: 3
|
|
16
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
@@ -128,7 +129,8 @@ objects — both within a parallel group and across sequential groups:
|
|
|
128
129
|
|
|
129
130
|
```python
|
|
130
131
|
import threading
|
|
131
|
-
|
|
132
|
+
|
|
133
|
+
from pytest_threadpool import parallelizable
|
|
132
134
|
|
|
133
135
|
|
|
134
136
|
class SharedState:
|
|
@@ -137,7 +139,7 @@ class SharedState:
|
|
|
137
139
|
results = {}
|
|
138
140
|
|
|
139
141
|
|
|
140
|
-
@
|
|
142
|
+
@parallelizable("children")
|
|
141
143
|
class TestGroupA:
|
|
142
144
|
def test_a1(self):
|
|
143
145
|
with SharedState.lock:
|
|
@@ -148,7 +150,7 @@ class TestGroupA:
|
|
|
148
150
|
SharedState.results["a2"] = True
|
|
149
151
|
|
|
150
152
|
|
|
151
|
-
@
|
|
153
|
+
@parallelizable("children")
|
|
152
154
|
class TestGroupB:
|
|
153
155
|
def test_b1(self):
|
|
154
156
|
SharedState.event.set()
|
|
@@ -179,6 +181,83 @@ pytest --threadpool 8
|
|
|
179
181
|
pytest
|
|
180
182
|
```
|
|
181
183
|
|
|
184
|
+
To enable `--threadpool` by default, add it to your config:
|
|
185
|
+
|
|
186
|
+
**pyproject.toml** (pytest 9.0+):
|
|
187
|
+
|
|
188
|
+
```toml
|
|
189
|
+
[tool.pytest]
|
|
190
|
+
addopts = ["--threadpool", "auto"]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**pytest.ini**:
|
|
194
|
+
|
|
195
|
+
```ini
|
|
196
|
+
[pytest]
|
|
197
|
+
addopts = --threadpool auto
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Configuration
|
|
201
|
+
|
|
202
|
+
### Command-line options
|
|
203
|
+
|
|
204
|
+
| Option | Values | Default | Description |
|
|
205
|
+
|-----------------------|-------------------|-----------|---------------------------------------------------------------------------------------------------------------|
|
|
206
|
+
| `--threadpool` | `N` or `auto` | *(off)* | Enable parallel execution with N threads. `auto` uses `os.cpu_count()`. |
|
|
207
|
+
| `--threadpool-output` | `classic`, `live` | `classic` | Output mode. `live` opens an interactive terminal viewer with scroll, tree navigation, and real-time updates. |
|
|
208
|
+
|
|
209
|
+
### INI settings
|
|
210
|
+
|
|
211
|
+
Set in `pyproject.toml`, `pytest.ini`, or `setup.cfg`:
|
|
212
|
+
|
|
213
|
+
| Setting | Type | Default | Description |
|
|
214
|
+
|-------------------------|------|---------|---------------------------------------------------------------------------------|
|
|
215
|
+
| `threadpool_tree_width` | int | `0` | Width (columns) of the live-view tree pane. `0` = auto (1/4 of terminal width). |
|
|
216
|
+
|
|
217
|
+
**pyproject.toml:**
|
|
218
|
+
|
|
219
|
+
```toml
|
|
220
|
+
[tool.pytest]
|
|
221
|
+
threadpool_tree_width = "35"
|
|
222
|
+
|
|
223
|
+
# or under ini_options
|
|
224
|
+
[tool.pytest.ini_options]
|
|
225
|
+
threadpool_tree_width = "35"
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**pytest.ini:**
|
|
229
|
+
|
|
230
|
+
```ini
|
|
231
|
+
[pytest]
|
|
232
|
+
threadpool_tree_width = "35"
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Live-view keybindings
|
|
236
|
+
|
|
237
|
+
Available when `--threadpool-output live` is active:
|
|
238
|
+
|
|
239
|
+
| Key | Action |
|
|
240
|
+
|-------------------|------------------------------------------------------|
|
|
241
|
+
| `↑` `↓` | Scroll content / move tree cursor |
|
|
242
|
+
| `PgUp` `PgDn` | Page scroll |
|
|
243
|
+
| `Home` `End` | Jump to top / bottom |
|
|
244
|
+
| `Tab` | Toggle tree panel (split-pane) |
|
|
245
|
+
| `Enter` | Show test/group output in content pane |
|
|
246
|
+
| `←` `→` | Collapse/expand tree node |
|
|
247
|
+
| `Ctrl+←` `Ctrl+→` | Switch keyboard focus between tree and content panes |
|
|
248
|
+
| `Ctrl+P` | Toggle show/hide passed tests in tree |
|
|
249
|
+
| `Ctrl+X` | Toggle show/hide failed tests in tree |
|
|
250
|
+
| `/` | Search within content pane (when focused) |
|
|
251
|
+
| `n` / `N` | Jump to next / previous search match |
|
|
252
|
+
| `Ctrl+W` | Save current pane content to `.log` file |
|
|
253
|
+
| Mouse scroll | Scrolls whichever pane the cursor is over |
|
|
254
|
+
| `Escape` | Clear search / close tree |
|
|
255
|
+
| `Ctrl+C` | Exit |
|
|
256
|
+
|
|
257
|
+
The tree panel shows the full test hierarchy (session > packages > modules > classes > tests)
|
|
258
|
+
with live outcome markers (`✓` passed, `✗` failed, `E` error, `s` skipped, `x` xfail, `X` xpass).
|
|
259
|
+
Groups show aggregated status. Type in the tree panel to fuzzy-filter tests (fzf-style).
|
|
260
|
+
|
|
182
261
|
## Tested versions
|
|
183
262
|
|
|
184
263
|
| Component | Versions |
|
|
@@ -211,17 +290,46 @@ worth browsing for real-world grouping, fixture, and reporting scenarios.
|
|
|
211
290
|
- **No plugin compatibility guarantees** — Interactions with other pytest
|
|
212
291
|
plugins (e.g. `pytest-xdist`, `pytest-timeout`, `pytest-randomly`) are
|
|
213
292
|
untested and may conflict.
|
|
214
|
-
- **No `capsys`/`capfd
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
[
|
|
293
|
+
- **No `capsys`/`capfd` in parallel** — These fixtures are not thread-safe.
|
|
294
|
+
`capsys`/`capfd` fail with "cannot use capsys and capsys at the same time"
|
|
295
|
+
when requested by parallel tests. Alternatives:
|
|
296
|
+
- **`print()`** — Worker output is buffered by thread-local stream
|
|
297
|
+
proxies and reported alongside each test's result. In default capture
|
|
298
|
+
mode, output appears in "Captured stdout call" sections on failure.
|
|
299
|
+
With `-vs` (`--capture=no -v`), captured output is emitted after the
|
|
300
|
+
PASSED/FAILED line for each test. TTY mode (default without `-s`)
|
|
301
|
+
suppresses print output; use `-vs` to see it. A TTY-friendly output
|
|
302
|
+
viewer with switchable per-thread/per-test frames is planned (see
|
|
303
|
+
[ROADMAP](ROADMAP.md)).
|
|
304
|
+
- **`caplog`** — The `caplog` fixture works natively in parallel tests.
|
|
305
|
+
`caplog.records`, `caplog.text`, `caplog.record_tuples`,
|
|
306
|
+
`caplog.messages`, `caplog.clear()`, `caplog.at_level()`, and
|
|
307
|
+
`caplog.set_level()` all behave the same as in sequential pytest.
|
|
308
|
+
Each worker gets its own `LogCaptureHandler` with per-thread record
|
|
309
|
+
isolation — parallel tests don't leak records into each other's
|
|
310
|
+
caplog. Failed tests show "Captured log call" sections as expected.
|
|
311
|
+
- **`logging.Logger`** — Standard `logging` calls (`logger.info()`,
|
|
312
|
+
`logger.warning()`, etc.) work natively in parallel tests. A
|
|
313
|
+
thread-local log handler captures records per-worker and attaches
|
|
314
|
+
them to "Captured log call" report sections on failure, matching
|
|
315
|
+
sequential pytest behavior. Log output does not appear in stdout
|
|
316
|
+
for passing tests unless `--log-cli-level` is set or a
|
|
317
|
+
`StreamHandler` explicitly targets `sys.stdout` or `sys.stderr`.
|
|
318
|
+
`--log-level` controls which records are captured. Existing
|
|
319
|
+
`StreamHandler` instances are automatically redirected through
|
|
320
|
+
the per-thread proxy so their output is grouped per-test instead
|
|
321
|
+
of interleaving globally.
|
|
322
|
+
- **IDE and CI runners (PyCharm, TeamCity, VS Code)** — Each test's
|
|
323
|
+
function-scoped setup, call, and teardown output appears in its own
|
|
324
|
+
report. Shared fixture output (session/package/module/class setup
|
|
325
|
+
and teardown) is emitted at the suite level, not inside individual
|
|
326
|
+
tests. Parametrized tests are reported in collection order so
|
|
327
|
+
runners group them correctly. Works via the `teamcity-messages`
|
|
328
|
+
plugin (`--teamcity` flag); PyCharm and TeamCity CI use the same
|
|
329
|
+
protocol.
|
|
330
|
+
- **Custom output hook** — Implement `pytest_threadpool_report` in a
|
|
331
|
+
conftest or plugin to customize how captured worker output is handled.
|
|
332
|
+
Return `True` to suppress the default output handling.
|
|
225
333
|
|
|
226
334
|
## License
|
|
227
335
|
|
|
@@ -105,7 +105,8 @@ objects — both within a parallel group and across sequential groups:
|
|
|
105
105
|
|
|
106
106
|
```python
|
|
107
107
|
import threading
|
|
108
|
-
|
|
108
|
+
|
|
109
|
+
from pytest_threadpool import parallelizable
|
|
109
110
|
|
|
110
111
|
|
|
111
112
|
class SharedState:
|
|
@@ -114,7 +115,7 @@ class SharedState:
|
|
|
114
115
|
results = {}
|
|
115
116
|
|
|
116
117
|
|
|
117
|
-
@
|
|
118
|
+
@parallelizable("children")
|
|
118
119
|
class TestGroupA:
|
|
119
120
|
def test_a1(self):
|
|
120
121
|
with SharedState.lock:
|
|
@@ -125,7 +126,7 @@ class TestGroupA:
|
|
|
125
126
|
SharedState.results["a2"] = True
|
|
126
127
|
|
|
127
128
|
|
|
128
|
-
@
|
|
129
|
+
@parallelizable("children")
|
|
129
130
|
class TestGroupB:
|
|
130
131
|
def test_b1(self):
|
|
131
132
|
SharedState.event.set()
|
|
@@ -156,6 +157,83 @@ pytest --threadpool 8
|
|
|
156
157
|
pytest
|
|
157
158
|
```
|
|
158
159
|
|
|
160
|
+
To enable `--threadpool` by default, add it to your config:
|
|
161
|
+
|
|
162
|
+
**pyproject.toml** (pytest 9.0+):
|
|
163
|
+
|
|
164
|
+
```toml
|
|
165
|
+
[tool.pytest]
|
|
166
|
+
addopts = ["--threadpool", "auto"]
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**pytest.ini**:
|
|
170
|
+
|
|
171
|
+
```ini
|
|
172
|
+
[pytest]
|
|
173
|
+
addopts = --threadpool auto
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Configuration
|
|
177
|
+
|
|
178
|
+
### Command-line options
|
|
179
|
+
|
|
180
|
+
| Option | Values | Default | Description |
|
|
181
|
+
|-----------------------|-------------------|-----------|---------------------------------------------------------------------------------------------------------------|
|
|
182
|
+
| `--threadpool` | `N` or `auto` | *(off)* | Enable parallel execution with N threads. `auto` uses `os.cpu_count()`. |
|
|
183
|
+
| `--threadpool-output` | `classic`, `live` | `classic` | Output mode. `live` opens an interactive terminal viewer with scroll, tree navigation, and real-time updates. |
|
|
184
|
+
|
|
185
|
+
### INI settings
|
|
186
|
+
|
|
187
|
+
Set in `pyproject.toml`, `pytest.ini`, or `setup.cfg`:
|
|
188
|
+
|
|
189
|
+
| Setting | Type | Default | Description |
|
|
190
|
+
|-------------------------|------|---------|---------------------------------------------------------------------------------|
|
|
191
|
+
| `threadpool_tree_width` | int | `0` | Width (columns) of the live-view tree pane. `0` = auto (1/4 of terminal width). |
|
|
192
|
+
|
|
193
|
+
**pyproject.toml:**
|
|
194
|
+
|
|
195
|
+
```toml
|
|
196
|
+
[tool.pytest]
|
|
197
|
+
threadpool_tree_width = "35"
|
|
198
|
+
|
|
199
|
+
# or under ini_options
|
|
200
|
+
[tool.pytest.ini_options]
|
|
201
|
+
threadpool_tree_width = "35"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**pytest.ini:**
|
|
205
|
+
|
|
206
|
+
```ini
|
|
207
|
+
[pytest]
|
|
208
|
+
threadpool_tree_width = "35"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Live-view keybindings
|
|
212
|
+
|
|
213
|
+
Available when `--threadpool-output live` is active:
|
|
214
|
+
|
|
215
|
+
| Key | Action |
|
|
216
|
+
|-------------------|------------------------------------------------------|
|
|
217
|
+
| `↑` `↓` | Scroll content / move tree cursor |
|
|
218
|
+
| `PgUp` `PgDn` | Page scroll |
|
|
219
|
+
| `Home` `End` | Jump to top / bottom |
|
|
220
|
+
| `Tab` | Toggle tree panel (split-pane) |
|
|
221
|
+
| `Enter` | Show test/group output in content pane |
|
|
222
|
+
| `←` `→` | Collapse/expand tree node |
|
|
223
|
+
| `Ctrl+←` `Ctrl+→` | Switch keyboard focus between tree and content panes |
|
|
224
|
+
| `Ctrl+P` | Toggle show/hide passed tests in tree |
|
|
225
|
+
| `Ctrl+X` | Toggle show/hide failed tests in tree |
|
|
226
|
+
| `/` | Search within content pane (when focused) |
|
|
227
|
+
| `n` / `N` | Jump to next / previous search match |
|
|
228
|
+
| `Ctrl+W` | Save current pane content to `.log` file |
|
|
229
|
+
| Mouse scroll | Scrolls whichever pane the cursor is over |
|
|
230
|
+
| `Escape` | Clear search / close tree |
|
|
231
|
+
| `Ctrl+C` | Exit |
|
|
232
|
+
|
|
233
|
+
The tree panel shows the full test hierarchy (session > packages > modules > classes > tests)
|
|
234
|
+
with live outcome markers (`✓` passed, `✗` failed, `E` error, `s` skipped, `x` xfail, `X` xpass).
|
|
235
|
+
Groups show aggregated status. Type in the tree panel to fuzzy-filter tests (fzf-style).
|
|
236
|
+
|
|
159
237
|
## Tested versions
|
|
160
238
|
|
|
161
239
|
| Component | Versions |
|
|
@@ -188,17 +266,46 @@ worth browsing for real-world grouping, fixture, and reporting scenarios.
|
|
|
188
266
|
- **No plugin compatibility guarantees** — Interactions with other pytest
|
|
189
267
|
plugins (e.g. `pytest-xdist`, `pytest-timeout`, `pytest-randomly`) are
|
|
190
268
|
untested and may conflict.
|
|
191
|
-
- **No `capsys`/`capfd
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
[
|
|
269
|
+
- **No `capsys`/`capfd` in parallel** — These fixtures are not thread-safe.
|
|
270
|
+
`capsys`/`capfd` fail with "cannot use capsys and capsys at the same time"
|
|
271
|
+
when requested by parallel tests. Alternatives:
|
|
272
|
+
- **`print()`** — Worker output is buffered by thread-local stream
|
|
273
|
+
proxies and reported alongside each test's result. In default capture
|
|
274
|
+
mode, output appears in "Captured stdout call" sections on failure.
|
|
275
|
+
With `-vs` (`--capture=no -v`), captured output is emitted after the
|
|
276
|
+
PASSED/FAILED line for each test. TTY mode (default without `-s`)
|
|
277
|
+
suppresses print output; use `-vs` to see it. A TTY-friendly output
|
|
278
|
+
viewer with switchable per-thread/per-test frames is planned (see
|
|
279
|
+
[ROADMAP](ROADMAP.md)).
|
|
280
|
+
- **`caplog`** — The `caplog` fixture works natively in parallel tests.
|
|
281
|
+
`caplog.records`, `caplog.text`, `caplog.record_tuples`,
|
|
282
|
+
`caplog.messages`, `caplog.clear()`, `caplog.at_level()`, and
|
|
283
|
+
`caplog.set_level()` all behave the same as in sequential pytest.
|
|
284
|
+
Each worker gets its own `LogCaptureHandler` with per-thread record
|
|
285
|
+
isolation — parallel tests don't leak records into each other's
|
|
286
|
+
caplog. Failed tests show "Captured log call" sections as expected.
|
|
287
|
+
- **`logging.Logger`** — Standard `logging` calls (`logger.info()`,
|
|
288
|
+
`logger.warning()`, etc.) work natively in parallel tests. A
|
|
289
|
+
thread-local log handler captures records per-worker and attaches
|
|
290
|
+
them to "Captured log call" report sections on failure, matching
|
|
291
|
+
sequential pytest behavior. Log output does not appear in stdout
|
|
292
|
+
for passing tests unless `--log-cli-level` is set or a
|
|
293
|
+
`StreamHandler` explicitly targets `sys.stdout` or `sys.stderr`.
|
|
294
|
+
`--log-level` controls which records are captured. Existing
|
|
295
|
+
`StreamHandler` instances are automatically redirected through
|
|
296
|
+
the per-thread proxy so their output is grouped per-test instead
|
|
297
|
+
of interleaving globally.
|
|
298
|
+
- **IDE and CI runners (PyCharm, TeamCity, VS Code)** — Each test's
|
|
299
|
+
function-scoped setup, call, and teardown output appears in its own
|
|
300
|
+
report. Shared fixture output (session/package/module/class setup
|
|
301
|
+
and teardown) is emitted at the suite level, not inside individual
|
|
302
|
+
tests. Parametrized tests are reported in collection order so
|
|
303
|
+
runners group them correctly. Works via the `teamcity-messages`
|
|
304
|
+
plugin (`--teamcity` flag); PyCharm and TeamCity CI use the same
|
|
305
|
+
protocol.
|
|
306
|
+
- **Custom output hook** — Implement `pytest_threadpool_report` in a
|
|
307
|
+
conftest or plugin to customize how captured worker output is handled.
|
|
308
|
+
Return `True` to suppress the default output handling.
|
|
202
309
|
|
|
203
310
|
## License
|
|
204
311
|
|