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.
Files changed (212) hide show
  1. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/.gitignore +3 -0
  2. pytest_threadpool-0.4.0/CHANGELOG.md +161 -0
  3. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/PKG-INFO +125 -17
  4. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/README.md +121 -14
  5. pytest_threadpool-0.4.0/ROADMAP.md +159 -0
  6. pytest_threadpool-0.4.0/examples/test_event_bus/event_bus.py +76 -0
  7. pytest_threadpool-0.4.0/examples/test_event_bus/test_event_bus.py +110 -0
  8. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_queue/test_queue.py +23 -2
  9. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/pyproject.toml +5 -2
  10. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/_fixtures.py +23 -3
  11. pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/__init__.py +40 -0
  12. pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_ansi.py +87 -0
  13. pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_buffer.py +40 -0
  14. pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_cursor.py +73 -0
  15. pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_display.py +386 -0
  16. pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_field.py +145 -0
  17. pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_input.py +244 -0
  18. pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_layout.py +101 -0
  19. pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_scroll_column.py +46 -0
  20. pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_status_line.py +46 -0
  21. pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_tree_overlay.py +435 -0
  22. pytest_threadpool-0.4.0/src/pytest_threadpool/_live_view/_view_manager.py +763 -0
  23. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/_markers.py +25 -31
  24. pytest_threadpool-0.4.0/src/pytest_threadpool/_runner.py +1612 -0
  25. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/_version.py +2 -2
  26. pytest_threadpool-0.4.0/src/pytest_threadpool/hooks.py +26 -0
  27. pytest_threadpool-0.4.0/src/pytest_threadpool/plugin.py +175 -0
  28. pytest_threadpool-0.4.0/tests/integration_tests/__init__.py +3 -0
  29. pytest_threadpool-0.4.0/tests/integration_tests/cases/caplog_parallel.py +96 -0
  30. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/capture_print_parallel.py +3 -1
  31. pytest_threadpool-0.4.0/tests/integration_tests/cases/capture_scoped_output.py +57 -0
  32. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/capture_two_groups.py +5 -3
  33. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/class_barrier_concurrency.py +2 -2
  34. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/class_single_method.py +2 -2
  35. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/class_thread_verification.py +2 -2
  36. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/collected_count.py +2 -2
  37. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_first_item_setup_fail.py +3 -1
  38. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_keyboard_interrupt.py +2 -2
  39. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_maxfail_parallel.py +4 -2
  40. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_nested_threads.py +2 -2
  41. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_sigint.py +3 -1
  42. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_sigint_many.py +2 -2
  43. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_system_exit.py +2 -2
  44. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_teardown_exception.py +3 -1
  45. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_worker_exception.py +2 -2
  46. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_autouse_function.py +3 -1
  47. pytest_threadpool-0.4.0/tests/integration_tests/cases/fixture_class_across_groups.py +50 -0
  48. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_class_scoped_once.py +3 -1
  49. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_class_yield.py +3 -1
  50. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_addfinalizer.py +3 -1
  51. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_chain.py +3 -1
  52. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_from_conftest.py +2 -2
  53. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_implicit_scope.py +3 -1
  54. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_mixed_parallel.py +4 -2
  55. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_multiple_per_test.py +3 -1
  56. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_setup_parallel.py +3 -1
  57. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_with_shared_deps.py +3 -1
  58. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_with_tmp_path.py +2 -2
  59. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_with_xunit.py +3 -1
  60. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_yield_teardown.py +3 -1
  61. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_function_scoped.py +3 -1
  62. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_interdependent_finalizers.py +3 -1
  63. pytest_threadpool-0.4.0/tests/integration_tests/cases/fixture_module_across_groups.py +52 -0
  64. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_multiple_scopes.py +3 -1
  65. pytest_threadpool-0.4.0/tests/integration_tests/cases/fixture_package_across_groups.py +72 -0
  66. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_parameterized.py +3 -1
  67. pytest_threadpool-0.4.0/tests/integration_tests/cases/fixture_session_across_groups.py +52 -0
  68. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_teardown_exception.py +3 -1
  69. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_yield_cleanup.py +3 -1
  70. pytest_threadpool-0.4.0/tests/integration_tests/cases/logging_basic_parallel.py +42 -0
  71. pytest_threadpool-0.4.0/tests/integration_tests/cases/logging_streamhandler.py +57 -0
  72. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/marks_custom.py +3 -1
  73. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/marks_standard.py +3 -1
  74. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/reporting_incremental.py +2 -2
  75. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/reporting_single_file_params.py +3 -1
  76. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/reporting_stdout_during_parallel.py +3 -1
  77. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/runner_collect_only.py +2 -2
  78. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/runner_setup_only.py +3 -1
  79. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/runner_setup_show.py +3 -1
  80. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/runner_single_parallel_item.py +3 -1
  81. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/runner_single_worker.py +2 -2
  82. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_all_merged.py +3 -1
  83. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_all_not_parallelizable.py +5 -5
  84. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_children_on_function.py +2 -2
  85. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_children_separate_params.py +3 -1
  86. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_dynamic_parametrize.py +2 -2
  87. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_method_overrides_class.py +4 -2
  88. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_mixed_fail_skip.py +5 -3
  89. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_module_children.py +2 -2
  90. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_not_parallelizable_function.py +4 -4
  91. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_not_parallelizable_method.py +3 -3
  92. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_parameters.py +3 -1
  93. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/scope_two_classes_mixed.py +2 -2
  94. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/setup_all_fail.py +3 -1
  95. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/setup_mixed_pass_fail.py +3 -1
  96. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/shared_counter.py +2 -2
  97. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/shared_cross_group_non_pickleable.py +3 -3
  98. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/shared_dict_mutation.py +2 -2
  99. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/shared_non_pickleable.py +2 -2
  100. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/shared_two_phase_barrier.py +2 -2
  101. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/teardown_after_test_failure.py +3 -1
  102. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/teardown_parallel_timing.py +3 -1
  103. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/teardown_same_thread.py +3 -1
  104. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/teardown_xunit_function.py +3 -3
  105. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/teardown_xunit_method_thread.py +2 -2
  106. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/validate_threadpool.py +2 -2
  107. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_class_setup.py +2 -2
  108. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_combined_setup.py +2 -2
  109. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_function_mixed_parallel.py +4 -4
  110. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_method_mixed_parallel.py +3 -3
  111. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_method_setup.py +2 -2
  112. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_method_teardown_runs.py +2 -2
  113. pytest_threadpool-0.4.0/tests/integration_tests/cases/xunit_setup_class_across_groups.py +61 -0
  114. pytest_threadpool-0.4.0/tests/integration_tests/cases/xunit_setup_method_across_groups.py +53 -0
  115. pytest_threadpool-0.4.0/tests/integration_tests/cases/xunit_setup_module_across_groups.py +47 -0
  116. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/conftest.py +8 -2
  117. pytest_threadpool-0.4.0/tests/integration_tests/test_caplog.py +100 -0
  118. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_capture.py +53 -6
  119. pytest_threadpool-0.4.0/tests/integration_tests/test_ide_reporter.py +353 -0
  120. pytest_threadpool-0.4.0/tests/integration_tests/test_live_view.py +689 -0
  121. pytest_threadpool-0.4.0/tests/integration_tests/test_logging.py +247 -0
  122. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_class.py +5 -1
  123. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_fixtures.py +39 -0
  124. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_xunit.py +18 -0
  125. pytest_threadpool-0.4.0/tests/integration_tests/test_scoped_output.py +307 -0
  126. pytest_threadpool-0.4.0/tests/unit_tests/__init__.py +3 -0
  127. pytest_threadpool-0.4.0/tests/unit_tests/live_view/__init__.py +0 -0
  128. pytest_threadpool-0.4.0/tests/unit_tests/live_view/conftest.py +8 -0
  129. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_ansi.py +87 -0
  130. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_buffer.py +57 -0
  131. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_content_search.py +48 -0
  132. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_cursor.py +94 -0
  133. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_display.py +336 -0
  134. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_field.py +184 -0
  135. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_input.py +92 -0
  136. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_layout.py +75 -0
  137. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_scroll_column.py +55 -0
  138. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_scroll_latency.py +571 -0
  139. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_status_line.py +57 -0
  140. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_tree_overlay.py +325 -0
  141. pytest_threadpool-0.4.0/tests/unit_tests/live_view/test_view_manager.py +278 -0
  142. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/unit_tests/test_unit_grouping.py +4 -12
  143. pytest_threadpool-0.4.0/tests/unit_tests/test_unit_runner.py +142 -0
  144. pytest_threadpool-0.3.5/CHANGELOG.md +0 -19
  145. pytest_threadpool-0.3.5/ROADMAP.md +0 -83
  146. pytest_threadpool-0.3.5/examples/test_event_bus/event_bus.py +0 -85
  147. pytest_threadpool-0.3.5/examples/test_event_bus/test_event_bus.py +0 -112
  148. pytest_threadpool-0.3.5/examples/test_queue/conftest.py +0 -16
  149. pytest_threadpool-0.3.5/examples/test_queue/user_pool.py +0 -26
  150. pytest_threadpool-0.3.5/src/pytest_threadpool/_runner.py +0 -897
  151. pytest_threadpool-0.3.5/src/pytest_threadpool/plugin.py +0 -82
  152. pytest_threadpool-0.3.5/tests/integration_tests/__init__.py +0 -3
  153. pytest_threadpool-0.3.5/tests/unit_tests/__init__.py +0 -3
  154. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/.github/workflows/ci.yml +0 -0
  155. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/.github/workflows/publish.yml +0 -0
  156. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/.pre-commit-config.yaml +0 -0
  157. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/CONTRIBUTING.md +0 -0
  158. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/LICENSE +0 -0
  159. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/codecov.yml +0 -0
  160. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/__init__.py +0 -0
  161. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/__init__.py +0 -0
  162. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/conftest.py +0 -0
  163. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/container.py +0 -0
  164. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/providers.py +0 -0
  165. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/services.py +0 -0
  166. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/test_factory.py +0 -0
  167. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/test_local.py +0 -0
  168. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/test_singleton.py +0 -0
  169. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_di/test_thread_local.py +0 -0
  170. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_event_bus/__init__.py +0 -0
  171. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_logging/__init__.py +0 -0
  172. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_logging/test_log_capture.py +0 -0
  173. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_queue/__init__.py +0 -0
  174. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_shared_state/__init__.py +0 -0
  175. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_shared_state/test_barrier.py +0 -0
  176. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_shared_state/test_counter.py +0 -0
  177. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/examples/test_shared_state/test_counter_async.py +0 -0
  178. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/scripts/setup-dev +0 -0
  179. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/__init__.py +0 -0
  180. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/_api.py +0 -0
  181. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/_constants.py +0 -0
  182. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/_grouping.py +0 -0
  183. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/src/pytest_threadpool/py.typed +0 -0
  184. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/__init__.py +0 -0
  185. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/__init__.py +0 -0
  186. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/_templates.py +0 -0
  187. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_cross_module_group.py +0 -0
  188. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/edge_worker_exception_conftest.py +0 -0
  189. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/fixture_func_from_conftest_conftest.py +0 -0
  190. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/parallel_only_skip.py +0 -0
  191. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/reporting_cross_module.py +0 -0
  192. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/reporting_incremental_conftest.py +0 -0
  193. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/reporting_package_children.py +0 -0
  194. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/sequential_bare_functions.py +0 -0
  195. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/sequential_unmarked_class.py +0 -0
  196. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/validate_threadpool_conftest.py +0 -0
  197. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_function_setup.py +0 -0
  198. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/cases/xunit_module_setup.py +0 -0
  199. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_edge_cases.py +0 -0
  200. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_func_fixtures.py +0 -0
  201. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_marks.py +0 -0
  202. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_package.py +0 -0
  203. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_parallel_teardown.py +0 -0
  204. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_reporting.py +0 -0
  205. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_scopes.py +0 -0
  206. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_sequential.py +0 -0
  207. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/integration_tests/test_pytester_shared.py +0 -0
  208. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/unit_tests/test_unit_api.py +0 -0
  209. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/unit_tests/test_unit_fixtures.py +0 -0
  210. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/unit_tests/test_unit_markers.py +0 -0
  211. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/unit_tests/test_unit_plugin.py +0 -0
  212. {pytest_threadpool-0.3.5 → pytest_threadpool-0.4.0}/tests/unit_tests/test_unit_stream_proxy.py +0 -0
@@ -163,6 +163,9 @@ cython_debug/
163
163
  .idea/
164
164
  uv.lock
165
165
 
166
+ # Live-view saved logs
167
+ logs/
168
+
166
169
  # hatch-vcs generated version file
167
170
  src/pytest_threadpool/_version.py
168
171
 
@@ -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.3.5
4
- Summary: Parallel test execution for free-threaded Python builds
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
- import pytest
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
- @pytest.mark.parallelizable("children")
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
- @pytest.mark.parallelizable("children")
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`/`caplog` in parallel** — These fixtures are not
215
- thread-safe. `capsys`/`capfd` fail with "cannot use capsys and capsys at
216
- the same time" when requested by parallel tests. `caplog` leaks records
217
- across fixtures and its `at_level()` context managers race on the shared
218
- root logger. Alternatives:
219
- - **`print()`** Worker output is suppressed by default (buffered by
220
- thread-local stream proxies). Pass `-s` (`--capture=no`) to disable
221
- suppression and see interleaved output.
222
- - **Logging** Use a per-test `FileHandler` writing to `tmp_path`, or
223
- collect structured records in a shared thread-safe list (see
224
- [`examples/test_logging/`](examples/test_logging/)).
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
- import pytest
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
- @pytest.mark.parallelizable("children")
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
- @pytest.mark.parallelizable("children")
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`/`caplog` in parallel** — These fixtures are not
192
- thread-safe. `capsys`/`capfd` fail with "cannot use capsys and capsys at
193
- the same time" when requested by parallel tests. `caplog` leaks records
194
- across fixtures and its `at_level()` context managers race on the shared
195
- root logger. Alternatives:
196
- - **`print()`** Worker output is suppressed by default (buffered by
197
- thread-local stream proxies). Pass `-s` (`--capture=no`) to disable
198
- suppression and see interleaved output.
199
- - **Logging** Use a per-test `FileHandler` writing to `tmp_path`, or
200
- collect structured records in a shared thread-safe list (see
201
- [`examples/test_logging/`](examples/test_logging/)).
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