symtest-cli 1.3.2__tar.gz → 1.3.3__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 (364) hide show
  1. {symtest_cli-1.3.2/src/symtest_cli.egg-info → symtest_cli-1.3.3}/PKG-INFO +1 -1
  2. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/docs/user_manual.md +27 -15
  3. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/docs/user_manual_en.md +27 -15
  4. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/__init__.py +1 -1
  5. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/cli.py +10 -0
  6. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/base_runner.py +4 -1
  7. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/execution.py +6 -2
  8. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/parallel_runner.py +2 -1
  9. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/file_comparator/csv_comparator.py +88 -88
  10. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/file_comparator/h5_comparator.py +37 -83
  11. symtest_cli-1.3.3/src/symtest/file_comparator/numeric_compare.py +252 -0
  12. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/utils/report_generator.py +12 -0
  13. {symtest_cli-1.3.2 → symtest_cli-1.3.3/src/symtest_cli.egg-info}/PKG-INFO +1 -1
  14. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest_cli.egg-info/SOURCES.txt +14 -0
  15. symtest_cli-1.3.3/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-7.4.4.pyc +0 -0
  16. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/test_cases.yaml +9 -9
  17. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-7.4.4.pyc +0 -0
  18. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-9.0.3.pyc +0 -0
  19. symtest_cli-1.3.3/tests/integration/__pycache__/test_new_cli_features.cpython-312-pytest-7.4.4.pyc +0 -0
  20. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/__pycache__/test_new_cli_features.cpython-312-pytest-9.0.3.pyc +0 -0
  21. symtest_cli-1.3.3/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-7.4.4.pyc +0 -0
  22. symtest_cli-1.3.3/tests/integration/__pycache__/test_sequence.cpython-312-pytest-7.4.4.pyc +0 -0
  23. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  24. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  25. symtest_cli-1.3.3/tests/integration/parallel/__pycache__/test_depends_on.cpython-312-pytest-7.4.4.pyc +0 -0
  26. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/parallel/__pycache__/test_depends_on.cpython-312-pytest-9.0.3.pyc +0 -0
  27. symtest_cli-1.3.3/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  28. symtest_cli-1.3.3/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-7.4.4.pyc +0 -0
  29. symtest_cli-1.3.3/tests/unit/__pycache__/test_config_io.cpython-312-pytest-7.4.4.pyc +0 -0
  30. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-7.4.4.pyc +0 -0
  31. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_inheritance_expander.cpython-312-pytest-7.4.4.pyc +0 -0
  32. symtest_cli-1.3.3/tests/unit/__pycache__/test_migrate.cpython-312-pytest-7.4.4.pyc +0 -0
  33. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_architecture_guard.cpython-312-pytest-7.4.4.pyc +0 -0
  34. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_architecture_guard.cpython-312-pytest-9.0.3.pyc +0 -0
  35. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-7.4.4.pyc +0 -0
  36. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-9.0.3.pyc +0 -0
  37. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_case_env.cpython-312-pytest-7.4.4.pyc +0 -0
  38. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_case_env.cpython-312-pytest-9.0.3.pyc +0 -0
  39. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-7.4.4.pyc +0 -0
  40. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc +0 -0
  41. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-312-pytest-7.4.4.pyc +0 -0
  42. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-312-pytest-9.0.3.pyc +0 -0
  43. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-7.4.4.pyc +0 -0
  44. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc +0 -0
  45. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_execution_new_features.cpython-312-pytest-7.4.4.pyc +0 -0
  46. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_execution_new_features.cpython-312-pytest-9.0.3.pyc +0 -0
  47. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_model_v2.cpython-312-pytest-7.4.4.pyc +0 -0
  48. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_model_v2.cpython-312-pytest-9.0.3.pyc +0 -0
  49. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_orchestration_accept.cpython-312-pytest-7.4.4.pyc +0 -0
  50. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_orchestration_accept.cpython-312-pytest-9.0.3.pyc +0 -0
  51. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-7.4.4.pyc +0 -0
  52. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_sequence_state.cpython-312-pytest-7.4.4.pyc +0 -0
  53. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_sequence_state.cpython-312-pytest-9.0.3.pyc +0 -0
  54. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-7.4.4.pyc +0 -0
  55. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_validation_error.cpython-312-pytest-7.4.4.pyc +0 -0
  56. symtest_cli-1.3.3/tests/unit/core/__pycache__/test_validation_error.cpython-312-pytest-9.0.3.pyc +0 -0
  57. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_assertions.py +1 -0
  58. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-312-pytest-7.4.4.pyc +0 -0
  59. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-312-pytest-9.0.3.pyc +0 -0
  60. symtest_cli-1.3.3/tests/unit/file_comparator/__pycache__/test_numeric_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  61. symtest_cli-1.3.3/tests/unit/file_comparator/__pycache__/test_numeric_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  62. symtest_cli-1.3.3/tests/unit/file_comparator/__pycache__/test_numeric_parity.cpython-312-pytest-7.4.4.pyc +0 -0
  63. symtest_cli-1.3.3/tests/unit/file_comparator/__pycache__/test_numeric_parity.cpython-312-pytest-9.0.3.pyc +0 -0
  64. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/test_error_analysis.py +3 -4
  65. symtest_cli-1.3.3/tests/unit/file_comparator/test_numeric_compare.py +233 -0
  66. symtest_cli-1.3.3/tests/unit/file_comparator/test_numeric_parity.py +160 -0
  67. symtest_cli-1.3.3/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  68. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-7.4.4.pyc +0 -0
  69. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-7.4.4.pyc +0 -0
  70. symtest_cli-1.3.3/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
  71. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-7.4.4.pyc +0 -0
  72. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-9.0.3.pyc +0 -0
  73. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-7.4.4.pyc +0 -0
  74. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-9.0.3.pyc +0 -0
  75. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/utils/test_report_generator.py +67 -0
  76. symtest_cli-1.3.2/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-7.4.4.pyc +0 -0
  77. symtest_cli-1.3.2/tests/integration/__pycache__/test_new_cli_features.cpython-312-pytest-7.4.4.pyc +0 -0
  78. symtest_cli-1.3.2/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-7.4.4.pyc +0 -0
  79. symtest_cli-1.3.2/tests/integration/__pycache__/test_sequence.cpython-312-pytest-7.4.4.pyc +0 -0
  80. symtest_cli-1.3.2/tests/integration/parallel/__pycache__/test_depends_on.cpython-312-pytest-7.4.4.pyc +0 -0
  81. symtest_cli-1.3.2/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  82. symtest_cli-1.3.2/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-7.4.4.pyc +0 -0
  83. symtest_cli-1.3.2/tests/unit/__pycache__/test_config_io.cpython-312-pytest-7.4.4.pyc +0 -0
  84. symtest_cli-1.3.2/tests/unit/core/__pycache__/test_case_env.cpython-312-pytest-7.4.4.pyc +0 -0
  85. symtest_cli-1.3.2/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-7.4.4.pyc +0 -0
  86. symtest_cli-1.3.2/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-312-pytest-7.4.4.pyc +0 -0
  87. symtest_cli-1.3.2/tests/unit/core/__pycache__/test_execution_new_features.cpython-312-pytest-7.4.4.pyc +0 -0
  88. symtest_cli-1.3.2/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-7.4.4.pyc +0 -0
  89. symtest_cli-1.3.2/tests/unit/core/__pycache__/test_validation_error.cpython-312-pytest-7.4.4.pyc +0 -0
  90. symtest_cli-1.3.2/tests/unit/core/__pycache__/test_validation_error.cpython-312-pytest-9.0.3.pyc +0 -0
  91. symtest_cli-1.3.2/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  92. symtest_cli-1.3.2/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
  93. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/LICENSE +0 -0
  94. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/MANIFEST.in +0 -0
  95. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/README.md +0 -0
  96. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/docs/design.md +0 -0
  97. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/docs/design_en.md +0 -0
  98. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/docs/tui_and_config_split_design.md +0 -0
  99. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/pyproject.toml +0 -0
  100. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/setup.cfg +0 -0
  101. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/setup.py +0 -0
  102. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/commands/__init__.py +0 -0
  103. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/commands/compare.py +0 -0
  104. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/config/__init__.py +0 -0
  105. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/config/config_io.py +0 -0
  106. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/config/config_schema.py +0 -0
  107. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/config/import_expander.py +0 -0
  108. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/config/inheritance_expander.py +0 -0
  109. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/__init__.py +0 -0
  110. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/assertions.py +0 -0
  111. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/config_loader.py +0 -0
  112. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/history_store.py +0 -0
  113. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/last_run_store.py +0 -0
  114. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/process_worker.py +0 -0
  115. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/sequence_state.py +0 -0
  116. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/setup.py +0 -0
  117. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/test_case.py +0 -0
  118. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/core/types.py +0 -0
  119. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/file_comparator/__init__.py +0 -0
  120. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/file_comparator/base_comparator.py +0 -0
  121. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/file_comparator/binary_comparator.py +0 -0
  122. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/file_comparator/factory.py +0 -0
  123. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/file_comparator/json_comparator.py +0 -0
  124. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/file_comparator/result.py +0 -0
  125. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/file_comparator/script_comparator.py +0 -0
  126. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/file_comparator/text_comparator.py +0 -0
  127. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/file_comparator/xml_comparator.py +0 -0
  128. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/logging_config.py +0 -0
  129. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/runners/__init__.py +0 -0
  130. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/runners/config_runner.py +0 -0
  131. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/runners/json_runner.py +0 -0
  132. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/runners/parallel_config_runner.py +0 -0
  133. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/runners/parallel_json_runner.py +0 -0
  134. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/runners/parallel_yaml_runner.py +0 -0
  135. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/runners/yaml_runner.py +0 -0
  136. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/tui/__init__.py +0 -0
  137. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/tui/app.py +0 -0
  138. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/tui/controllers/__init__.py +0 -0
  139. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/tui/controllers/case_controller.py +0 -0
  140. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/tui/screens/__init__.py +0 -0
  141. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/tui/screens/case_editor.py +0 -0
  142. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/tui/screens/case_list.py +0 -0
  143. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/tui/widgets/__init__.py +0 -0
  144. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/tui/widgets/case_table.py +0 -0
  145. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/tui/widgets/expected_editor.py +0 -0
  146. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/tui/widgets/search_bar.py +0 -0
  147. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/tui/widgets/steps_editor.py +0 -0
  148. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/utils/__init__.py +0 -0
  149. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/utils/junit_xml_writer.py +0 -0
  150. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest/utils/path_resolver.py +0 -0
  151. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest_cli.egg-info/dependency_links.txt +0 -0
  152. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest_cli.egg-info/entry_points.txt +0 -0
  153. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest_cli.egg-info/requires.txt +0 -0
  154. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/src/symtest_cli.egg-info/top_level.txt +0 -0
  155. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/README.md +0 -0
  156. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/__init__.py +0 -0
  157. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/__pycache__/__init__.cpython-312.pyc +0 -0
  158. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/__pycache__/__init__.cpython-313.pyc +0 -0
  159. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/__pycache__/__init__.cpython-39.pyc +0 -0
  160. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
  161. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
  162. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc +0 -0
  163. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/__pycache__/conftest.cpython-39-pytest-8.3.4.pyc +0 -0
  164. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/__pycache__/run_all.cpython-312.pyc +0 -0
  165. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/__pycache__/run_all.cpython-313.pyc +0 -0
  166. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/__pycache__/run_all.cpython-39.pyc +0 -0
  167. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/__pycache__/test_setup_module.cpython-312-pytest-7.4.4.pyc +0 -0
  168. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/conftest.py +0 -0
  169. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/demos/h5_filter_demo.py +0 -0
  170. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/demos/manual_report_example.py +0 -0
  171. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/demos/perf_parallel.py +0 -0
  172. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/e2e/__init__.py +0 -0
  173. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/e2e/__pycache__/__init__.cpython-312.pyc +0 -0
  174. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/e2e/__pycache__/__init__.cpython-313.pyc +0 -0
  175. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/e2e/__pycache__/__init__.cpython-39.pyc +0 -0
  176. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-9.0.3.pyc +0 -0
  177. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/e2e/__pycache__/test_user_flows.cpython-313-pytest-9.0.2.pyc +0 -0
  178. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/e2e/__pycache__/test_user_flows.cpython-39-pytest-8.3.4.pyc +0 -0
  179. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/e2e/test_user_flows.py +0 -0
  180. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/circular_config_a.json +0 -0
  181. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/circular_config_b.json +0 -0
  182. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/hourglass_stdout_mismatch.txt +0 -0
  183. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/hourglass_stdout_sample.txt +0 -0
  184. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/inheritance_base.json +0 -0
  185. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/inheritance_chain.json +0 -0
  186. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/inheritance_circular.json +0 -0
  187. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/main_config.json +0 -0
  188. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/missing_fields.json +0 -0
  189. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/mock_fail_script.py +0 -0
  190. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/mock_pass_script.py +0 -0
  191. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/setup_main.json +0 -0
  192. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/setup_sub.json +0 -0
  193. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/sub_json_tests.yaml +0 -0
  194. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/sub_text_tests.json +0 -0
  195. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/test_cases.json +0 -0
  196. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/test_cases1.json +0 -0
  197. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/test_with_setup.json +0 -0
  198. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/fixtures/test_with_setup.yaml +0 -0
  199. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/__pycache__/test_history_feature.cpython-313-pytest-9.0.2.pyc +0 -0
  200. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/__pycache__/test_new_cli_features.cpython-313-pytest-9.0.2.pyc +0 -0
  201. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-9.0.3.pyc +0 -0
  202. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/__pycache__/test_real_command_execution.cpython-313-pytest-9.0.2.pyc +0 -0
  203. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-9.0.3.pyc +0 -0
  204. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/__pycache__/test_sequence.cpython-313-pytest-9.0.2.pyc +0 -0
  205. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  206. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  207. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  208. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  209. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  210. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  211. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  212. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  213. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  214. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  215. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  216. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  217. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  218. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  219. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  220. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  221. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  222. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  223. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  224. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  225. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/test_binary_compare.py +0 -0
  226. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/test_csv_compare.py +0 -0
  227. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/test_h5_compare.py +0 -0
  228. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/test_json_compare.py +0 -0
  229. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/test_text_compare.py +0 -0
  230. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/file_compare/test_xml_compare.py +0 -0
  231. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-9.0.3.pyc +0 -0
  232. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-313-pytest-9.0.2.pyc +0 -0
  233. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-39-pytest-8.3.4.pyc +0 -0
  234. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/parallel/test_depends_on.py +0 -0
  235. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/parallel/test_parallel_runner.py +0 -0
  236. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-9.0.3.pyc +0 -0
  237. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-313-pytest-9.0.2.pyc +0 -0
  238. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-39-pytest-8.3.4.pyc +0 -0
  239. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/path_handling/test_spaces_in_paths.py +0 -0
  240. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/test_history_feature.py +0 -0
  241. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/test_new_cli_features.py +0 -0
  242. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/test_real_command_execution.py +0 -0
  243. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/integration/test_sequence.py +0 -0
  244. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/run_all.py +0 -0
  245. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_binary_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  246. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_binary_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  247. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_binary_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
  248. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_cli.cpython-312-pytest-7.4.4.pyc +0 -0
  249. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_cli.cpython-312-pytest-9.0.3.pyc +0 -0
  250. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.2.pyc +0 -0
  251. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_config_io.cpython-312-pytest-9.0.3.pyc +0 -0
  252. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_config_io.cpython-313-pytest-9.0.2.pyc +0 -0
  253. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  254. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  255. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_h5_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
  256. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-9.0.3.pyc +0 -0
  257. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_import_expander.cpython-313-pytest-9.0.2.pyc +0 -0
  258. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_inheritance_expander.cpython-312-pytest-9.0.3.pyc +0 -0
  259. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_inheritance_expander.cpython-313-pytest-9.0.2.pyc +0 -0
  260. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_result.cpython-312-pytest-7.4.4.pyc +0 -0
  261. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_result.cpython-312-pytest-9.0.3.pyc +0 -0
  262. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_result.cpython-313-pytest-9.0.2.pyc +0 -0
  263. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-7.4.4.pyc +0 -0
  264. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-9.0.3.pyc +0 -0
  265. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/__pycache__/test_run_all.cpython-313-pytest-9.0.2.pyc +0 -0
  266. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-7.4.4.pyc +0 -0
  267. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-9.0.3.pyc +0 -0
  268. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/commands/__pycache__/test_compare_command.cpython-313-pytest-9.0.2.pyc +0 -0
  269. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/commands/test_compare_command.py +0 -0
  270. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_assertions.cpython-313-pytest-9.0.2.pyc +0 -0
  271. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_config_loader.cpython-313-pytest-9.0.2.pyc +0 -0
  272. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-313-pytest-9.0.2.pyc +0 -0
  273. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_execution.cpython-312.pyc +0 -0
  274. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_execution.cpython-313-pytest-9.0.2.pyc +0 -0
  275. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_execution_new_features.cpython-313-pytest-9.0.2.pyc +0 -0
  276. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-7.4.4.pyc +0 -0
  277. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-9.0.3.pyc +0 -0
  278. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_history_store.cpython-313-pytest-9.0.2.pyc +0 -0
  279. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_last_run_store.cpython-312-pytest-7.4.4.pyc +0 -0
  280. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_last_run_store.cpython-312-pytest-9.0.3.pyc +0 -0
  281. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_last_run_store.cpython-313-pytest-9.0.2.pyc +0 -0
  282. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-9.0.3.pyc +0 -0
  283. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_process_worker.cpython-313-pytest-9.0.2.pyc +0 -0
  284. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-9.0.3.pyc +0 -0
  285. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_setup.cpython-313-pytest-9.0.2.pyc +0 -0
  286. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_setup.cpython-39-pytest-8.3.4.pyc +0 -0
  287. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_validation_error.cpython-313-pytest-9.0.2.pyc +0 -0
  288. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_xfail.cpython-312-pytest-7.4.4.pyc +0 -0
  289. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_xfail.cpython-312-pytest-9.0.3.pyc +0 -0
  290. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/__pycache__/test_xfail.cpython-313-pytest-9.0.2.pyc +0 -0
  291. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_case_env.py +0 -0
  292. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_config_loader.py +0 -0
  293. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_config_loader_new_features.py +0 -0
  294. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_execution.py +0 -0
  295. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_execution_new_features.py +0 -0
  296. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_history_store.py +0 -0
  297. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_last_run_store.py +0 -0
  298. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_process_worker.py +0 -0
  299. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_sequence_state.py +0 -0
  300. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_setup.py +0 -0
  301. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_validation_error.py +0 -0
  302. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/core/test_xfail.py +0 -0
  303. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/__init__.cpython-312.pyc +0 -0
  304. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-313-pytest-9.0.2.pyc +0 -0
  305. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  306. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  307. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
  308. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  309. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  310. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
  311. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-312-pytest-7.4.4.pyc +0 -0
  312. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-312-pytest-9.0.3.pyc +0 -0
  313. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-313-pytest-9.0.2.pyc +0 -0
  314. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/test_hourglass_tangent_comparator.py +0 -0
  315. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/test_script_comparator.py +0 -0
  316. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/file_comparator/test_workspace_plugins.py +0 -0
  317. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc +0 -0
  318. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312.pyc +0 -0
  319. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-313-pytest-9.0.2.pyc +0 -0
  320. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-39-pytest-8.3.4.pyc +0 -0
  321. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-9.0.3.pyc +0 -0
  322. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-313-pytest-9.0.2.pyc +0 -0
  323. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-9.0.3.pyc +0 -0
  324. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-313-pytest-9.0.2.pyc +0 -0
  325. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/test_json_yaml_runner.py +0 -0
  326. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/test_test_case_filter.py +0 -0
  327. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/runners/test_test_case_tag_filter.py +0 -0
  328. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/test_binary_comparator.py +0 -0
  329. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/test_cli.py +0 -0
  330. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/test_config_io.py +0 -0
  331. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/test_h5_comparator.py +0 -0
  332. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/test_import_expander.py +0 -0
  333. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/test_inheritance_expander.py +0 -0
  334. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/test_result.py +0 -0
  335. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/test_run_all.py +0 -0
  336. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__init__.py +0 -0
  337. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/__init__.cpython-312.pyc +0 -0
  338. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/__init__.cpython-313.pyc +0 -0
  339. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
  340. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc +0 -0
  341. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-7.4.4.pyc +0 -0
  342. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-9.0.3.pyc +0 -0
  343. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_app.cpython-313-pytest-9.0.2.pyc +0 -0
  344. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_case_controller.cpython-313-pytest-9.0.2.pyc +0 -0
  345. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-7.4.4.pyc +0 -0
  346. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-9.0.3.pyc +0 -0
  347. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_search_functions.cpython-313-pytest-9.0.2.pyc +0 -0
  348. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_tui_run_test.cpython-312-pytest-7.4.4.pyc +0 -0
  349. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_tui_run_test.cpython-312-pytest-9.0.3.pyc +0 -0
  350. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_tui_run_test.cpython-313-pytest-9.0.2.pyc +0 -0
  351. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-7.4.4.pyc +0 -0
  352. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-9.0.3.pyc +0 -0
  353. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/__pycache__/test_widgets_data.cpython-313-pytest-9.0.2.pyc +0 -0
  354. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/conftest.py +0 -0
  355. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/test_app.py +0 -0
  356. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/test_case_controller.py +0 -0
  357. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/test_search_functions.py +0 -0
  358. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/test_tui_run_test.py +0 -0
  359. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/tui/test_widgets_data.py +0 -0
  360. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-7.4.4.pyc +0 -0
  361. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-9.0.3.pyc +0 -0
  362. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-313-pytest-9.0.2.pyc +0 -0
  363. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/utils/__pycache__/test_report_generator.cpython-313-pytest-9.0.2.pyc +0 -0
  364. {symtest_cli-1.3.2 → symtest_cli-1.3.3}/tests/unit/utils/test_junit_xml_writer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: symtest-cli
3
- Version: 1.3.2
3
+ Version: 1.3.3
4
4
  Summary: Regression testing for CLI applications, with multi-step workflows and numerical file comparison.
5
5
  Home-page: https://github.com/ozil111/symtest-cli
6
6
  Author: Xiaotong Wang
@@ -248,7 +248,7 @@ test_cases:
248
248
  | `xfail_reason` | 否 | xfail 的原因说明,报告中将展示此文本(如 "Bug #42 尚未修复") |
249
249
  | `xfail_quiet` | 否 | 设为 `true` 时,xfailed 状态下报告中不输出 Command Output(stdout/stderr 大段输出),仅保留命令、返回码、失败原因等元信息 |
250
250
  | `depends_on` | 否 | 依赖的测试用例名称列表(如 `["A", "B"]`)。当前用例必须等待所有依赖用例通过后才执行。依赖失败时自动 skip 当前用例及下游。支持并行和顺序两种 runner |
251
- | `env` | 否 | case 级环境变量字典(如 `{"UEL_SYSID_SCALE": "1.0"}`),仅在执行该 case(序列模式为所有 step)时注入子进程,见 [Case 级环境变量](#case-级环境变量env) |
251
+ | `env` | 否 | case 级环境变量字典(如 `{"MYAPP_SCALE": "1.0"}`),仅在执行该 case(序列模式为所有 step)时注入子进程,见 [Case 级环境变量](#case-级环境变量env) |
252
252
  | `expected.return_code` | 否 | 期望返回码 |
253
253
  | `expected.output_contains` | 否 | 输出需包含的字符串列表 |
254
254
  | `expected.output_matches` | 否 | 输出需匹配的正则表达式(单个字符串) |
@@ -262,11 +262,11 @@ test_cases:
262
262
 
263
263
  ```json
264
264
  {
265
- "name": "UEL 缩放测试",
265
+ "name": "case 级环境变量示例",
266
266
  "command": "solver",
267
267
  "args": ["-i", "input.dat"],
268
268
  "env": {
269
- "UEL_SYSID_SCALE": "1.0",
269
+ "MYAPP_SCALE": "1.0",
270
270
  "OMP_NUM_THREADS": "8"
271
271
  },
272
272
  "expected": { "return_code": 0 }
@@ -276,11 +276,11 @@ test_cases:
276
276
  ### YAML
277
277
 
278
278
  ```yaml
279
- - name: UEL 缩放测试
279
+ - name: case 级环境变量示例
280
280
  command: solver
281
281
  args: ["-i", "input.dat"]
282
282
  env:
283
- UEL_SYSID_SCALE: "1.0"
283
+ MYAPP_SCALE: "1.0"
284
284
  expected: { return_code: 0 }
285
285
  ```
286
286
 
@@ -291,7 +291,7 @@ test_cases:
291
291
  ```json
292
292
  {
293
293
  "name": "多步骤+环境变量",
294
- "env": { "UEL_SYSID_SCALE": "1.0" },
294
+ "env": { "MYAPP_SCALE": "1.0" },
295
295
  "steps": [
296
296
  { "command": "python", "args": ["./step1.py"], "expected": { "return_code": 0 } },
297
297
  { "command": "python", "args": ["./step2.py"], "expected": { "return_code": 0 } }
@@ -814,7 +814,7 @@ symtest run test_cases.json --last-failed
814
814
 
815
815
  # 断点续跑:跳过已通过的步骤,从失败步骤继续
816
816
  symtest run test_cases.json --resume
817
- symtest run test_cases.json --resume -t BS-U_01
817
+ symtest run test_cases.json --resume -t long_pipeline
818
818
 
819
819
  # 比较失败时更新基线文件(交互运行需输入 yes)
820
820
  symtest run test_cases.json --update-baseline
@@ -865,11 +865,11 @@ symtest run config.json
865
865
  **信任模型**:`--resume` **不校验工作区产物**(输入文件、前置步骤生成的文件等)。使用 `--resume` 即表示用户确认输入文件未被修改。如果怀疑工作区被污染,应不带 `--resume` 全量重跑。
866
866
 
867
867
  ```bash
868
- # 首次全量运行,BS-U_01 的 step 4 失败(总耗时 72s)
868
+ # 首次全量运行,long_pipeline 的 step 4 失败(总耗时 72s)
869
869
  symtest run config.json
870
870
 
871
- # 修复后只重跑 BS-U_01,跳过 step 1-3(仅耗时 ~0.14s)
872
- symtest run config.json -t BS-U_01 --resume
871
+ # 修复后只重跑 long_pipeline,跳过 step 1-3(仅耗时 ~0.14s)
872
+ symtest run config.json -t long_pipeline --resume
873
873
 
874
874
  # 全部通过后,跑一次全量确认无回归
875
875
  symtest run config.json
@@ -1742,7 +1742,16 @@ CSV 比较按行列结构逐单元格比对;数值单元格在容差范围内
1742
1742
  | `mean_abs_error` | 平均绝对误差 |
1743
1743
  | `rms_abs_error` | 均方根绝对误差(RMSE) |
1744
1744
 
1745
- 统计是**流式**计算的,不依赖差异截断,覆盖全体数值单元格。仅失败的比较输出统计,通过的比较不输出。
1745
+ 统计是**流式**计算的,不依赖差异截断,覆盖全体数值单元格。默认仅失败的比较输出统计,通过的比较不输出。
1746
+
1747
+ 如需让**通过**的用例也输出统计信息(例如用于监控容差余量),可改用 `--error-analysis-all`(它会隐含启用 `--error-analysis`):
1748
+
1749
+ ```bash
1750
+ # 对所有用例(含通过的)输出误差统计
1751
+ symtest run config.json --error-analysis-all
1752
+ ```
1753
+
1754
+ 启用后,每个**通过**的用例会在 Detailed Results 区块中以 `error_stats (baseline vs actual):` 的形式列出上述统计量(与失败用例的 `error_stats` 字段一致)。通过用例的统计也同时写入 `--output json` 的 `assertion_results[].error_stats`,便于程序化消费。仅当 `--error-analysis-all` 启用时才会对通过用例产生额外输出,未启用时行为不变。
1746
1755
 
1747
1756
  **CLI 用法**:
1748
1757
 
@@ -1750,6 +1759,9 @@ CSV 比较按行列结构逐单元格比对;数值单元格在容差范围内
1750
1759
  # 启用误差分析
1751
1760
  symtest run config.json --error-analysis
1752
1761
 
1762
+ # 启用误差分析并对通过的用例也输出统计
1763
+ symtest run config.json --error-analysis-all
1764
+
1753
1765
  # 与比较参数组合使用
1754
1766
  symtest run config.json --error-analysis --csv-rtol 1e-4 --csv-data-filter '>0'
1755
1767
  ```
@@ -2005,8 +2017,8 @@ comparator = ComparatorFactory.create_comparator("foo")
2005
2017
  ```json
2006
2018
  {
2007
2019
  "type": "hourglass_tangent",
2008
- "script": "case/.../analyze_HG-M1_D1_A1e-4_tangent.py",
2009
- "case_dir": "case/.../WP31_pure/HG-M1_D1_A1e-4",
2020
+ "script": "case/.../analyze_case01_tangent.py",
2021
+ "case_dir": "case/.../case01",
2010
2022
  "pass_threshold": 1e-6,
2011
2023
  "timeout": 600
2012
2024
  }
@@ -2083,9 +2095,9 @@ python tests/run_all.py --scope unit --extra "-v -k assertions"
2083
2095
 
2084
2096
  `--extra` 接收的字符串会经 `shlex` 拆分后追加到 pytest 命令行。脚本通过当前解释器(`sys.executable -m pytest`)调用 pytest,确保使用激活的环境而非 PATH 中首个 `pytest`。
2085
2097
 
2086
- 测试环境需先激活 conda 环境:
2098
+ 测试环境需先激活你的 Python 环境(如 conda):
2087
2099
 
2088
2100
  ```bash
2089
- conda activate xiaotong
2101
+ conda activate <你的环境名>
2090
2102
  python tests/run_all.py
2091
2103
  ```
@@ -248,7 +248,7 @@ test_cases:
248
248
  | `xfail_reason` | No | Reason text for xfail, displayed in the report (e.g., "Bug #42 not yet fixed") |
249
249
  | `xfail_quiet` | No | When `true`, suppress Command Output (stdout/stderr) for xfailed cases in the report; only command, return code, and failure reason metadata retained |
250
250
  | `depends_on` | No | List of test case names this case depends on (e.g., `["A", "B"]`). The case will wait until all dependencies pass before executing. On dependency failure, the case and its downstream are auto-skipped. Works with both parallel and sequential runners |
251
- | `env` | No | Case-level environment variable mapping (e.g. `{"UEL_SYSID_SCALE": "1.0"}`), injected into the subprocess only when this case runs (all steps in sequence mode). See [Case-Level Environment Variables](#case-level-environment-variables-env) |
251
+ | `env` | No | Case-level environment variable mapping (e.g. `{"MYAPP_SCALE": "1.0"}`), injected into the subprocess only when this case runs (all steps in sequence mode). See [Case-Level Environment Variables](#case-level-environment-variables-env) |
252
252
  | `expected.return_code` | No | Expected return code |
253
253
  | `expected.output_contains` | No | List of strings the output must contain |
254
254
  | `expected.output_matches` | No | Regex pattern the output must match (single string) |
@@ -299,11 +299,11 @@ Use the `env` field (same level as `name`) to inject environment variables into
299
299
 
300
300
  ```json
301
301
  {
302
- "name": "UEL scale test",
302
+ "name": "Case-level env test",
303
303
  "command": "solver",
304
304
  "args": ["-i", "input.dat"],
305
305
  "env": {
306
- "UEL_SYSID_SCALE": "1.0",
306
+ "MYAPP_SCALE": "1.0",
307
307
  "OMP_NUM_THREADS": "8"
308
308
  },
309
309
  "expected": { "return_code": 0 }
@@ -313,11 +313,11 @@ Use the `env` field (same level as `name`) to inject environment variables into
313
313
  ### YAML
314
314
 
315
315
  ```yaml
316
- - name: UEL scale test
316
+ - name: Case-level env test
317
317
  command: solver
318
318
  args: ["-i", "input.dat"]
319
319
  env:
320
- UEL_SYSID_SCALE: "1.0"
320
+ MYAPP_SCALE: "1.0"
321
321
  expected: { return_code: 0 }
322
322
  ```
323
323
 
@@ -328,7 +328,7 @@ Use the `env` field (same level as `name`) to inject environment variables into
328
328
  ```json
329
329
  {
330
330
  "name": "multi-step with env",
331
- "env": { "UEL_SYSID_SCALE": "1.0" },
331
+ "env": { "MYAPP_SCALE": "1.0" },
332
332
  "steps": [
333
333
  { "command": "python", "args": ["./step1.py"], "expected": { "return_code": 0 } },
334
334
  { "command": "python", "args": ["./step2.py"], "expected": { "return_code": 0 } }
@@ -814,7 +814,7 @@ symtest run test_cases.json --last-failed
814
814
 
815
815
  # Resume: skip passed steps, continue from failed step
816
816
  symtest run test_cases.json --resume
817
- symtest run test_cases.json --resume -t BS-U_01
817
+ symtest run test_cases.json --resume -t long_pipeline
818
818
 
819
819
  # Update baseline files on comparison failure (type yes interactively)
820
820
  symtest run test_cases.json --update-baseline
@@ -865,11 +865,11 @@ symtest run config.json
865
865
  **Trust model**: `--resume` does **not verify workspace artifacts** (input files, files generated by prior steps, etc.). Using `--resume` means the user confirms input files are unmodified. If workspace contamination is suspected, rerun fully without `--resume`.
866
866
 
867
867
  ```bash
868
- # First full run, BS-U_01 step 4 fails (total 72s)
868
+ # First full run, long_pipeline step 4 fails (total 72s)
869
869
  symtest run config.json
870
870
 
871
- # After fixing, rerun only BS-U_01, skipping steps 1-3 (~0.14s only)
872
- symtest run config.json -t BS-U_01 --resume
871
+ # After fixing, rerun only long_pipeline, skipping steps 1-3 (~0.14s only)
872
+ symtest run config.json -t long_pipeline --resume
873
873
 
874
874
  # After all pass, do one full run to confirm no regressions
875
875
  symtest run config.json
@@ -1740,7 +1740,16 @@ When enabled, each failed file comparison appends `error_stats` to the Compare F
1740
1740
  | `mean_abs_error` | Mean absolute error |
1741
1741
  | `rms_abs_error` | Root-mean-square absolute error (RMSE) |
1742
1742
 
1743
- Statistics are computed **in streaming fashion**, independent of the difference truncation, covering all numeric cells. Only failed comparisons output statistics; passed comparisons do not.
1743
+ Statistics are computed **in streaming fashion**, independent of the difference truncation, covering all numeric cells. By default only failed comparisons output statistics; passed comparisons do not.
1744
+
1745
+ To also output statistics for **passed** cases (e.g. to monitor tolerance headroom), use `--error-analysis-all` instead (it implicitly enables `--error-analysis`):
1746
+
1747
+ ```bash
1748
+ # Output error statistics for all cases (including passed ones)
1749
+ symtest run config.json --error-analysis-all
1750
+ ```
1751
+
1752
+ When enabled, each **passed** case lists the above statistics in the Detailed Results section as `error_stats:`. For passed cases the statistics are also written to the `assertion_results[].error_stats` field of the `--output json` report for programmatic consumption. Statistics for passed cases are produced only when `--error-analysis-all` is enabled; otherwise behavior is unchanged.
1744
1753
 
1745
1754
  **CLI Usage**:
1746
1755
 
@@ -1748,6 +1757,9 @@ Statistics are computed **in streaming fashion**, independent of the difference
1748
1757
  # Enable error analysis
1749
1758
  symtest run config.json --error-analysis
1750
1759
 
1760
+ # Enable error analysis and also output statistics for passed cases
1761
+ symtest run config.json --error-analysis-all
1762
+
1751
1763
  # Combine with comparison parameters
1752
1764
  symtest run config.json --error-analysis --csv-rtol 1e-4 --csv-data-filter '>0'
1753
1765
  ```
@@ -2003,8 +2015,8 @@ comparator = ComparatorFactory.create_comparator("foo")
2003
2015
  ```json
2004
2016
  {
2005
2017
  "type": "hourglass_tangent",
2006
- "script": "case/.../analyze_HG-M1_D1_A1e-4_tangent.py",
2007
- "case_dir": "case/.../WP31_pure/HG-M1_D1_A1e-4",
2018
+ "script": "case/.../analyze_case01_tangent.py",
2019
+ "case_dir": "case/.../case01",
2008
2020
  "pass_threshold": 1e-6,
2009
2021
  "timeout": 600
2010
2022
  }
@@ -2081,9 +2093,9 @@ python tests/run_all.py --scope unit --extra "-v -k assertions"
2081
2093
 
2082
2094
  `--extra` accepts a string that is split via `shlex` and appended to the pytest command line. The script invokes pytest through the current interpreter (`sys.executable -m pytest`), ensuring the activated environment is used rather than the first `pytest` found on PATH.
2083
2095
 
2084
- Activate the conda environment before running tests:
2096
+ Activate your Python environment (e.g. conda) before running tests:
2085
2097
 
2086
2098
  ```bash
2087
- conda activate xiaotong
2099
+ conda activate <your-env>
2088
2100
  python tests/run_all.py
2089
2101
  ```
@@ -16,7 +16,7 @@ runtime. Library users can enable console logging explicitly::
16
16
  setup_console_logging(level=logging.DEBUG)
17
17
  """
18
18
 
19
- __version__ = "1.3.2"
19
+ __version__ = "1.3.3"
20
20
  __author__ = "Xiaotong Wang"
21
21
  __email__ = "xiaotongwang98@gmail.com"
22
22
 
@@ -130,6 +130,9 @@ Examples:
130
130
  help='Enable streaming error statistics for numerical file comparisons '
131
131
  '(CSV/H5): total_numeric_cells, mismatched_cells, '
132
132
  'max_abs/rel_error, mean/rms_abs_error')
133
+ run_parser.add_argument('--error-analysis-all', action='store_true',
134
+ help='Like --error-analysis, but also report error statistics for '
135
+ 'PASSED file comparisons in the report (implies --error-analysis)')
133
136
  run_parser.add_argument('--plugin-dir', action='append', default=None,
134
137
  dest='plugin_dirs',
135
138
  help='Add a directory for workspace-level comparator plugins '
@@ -273,6 +276,9 @@ def run_tests(args):
273
276
  update_baseline = getattr(args, 'update_baseline', False)
274
277
  update_history = getattr(args, 'update_history', False)
275
278
  error_analysis = getattr(args, 'error_analysis', False)
279
+ error_analysis_all = getattr(args, 'error_analysis_all', False)
280
+ if error_analysis_all:
281
+ error_analysis = True
276
282
  last_failed = getattr(args, 'last_failed', False)
277
283
  resume = getattr(args, 'resume', False)
278
284
  plugin_dirs = getattr(args, 'plugin_dirs', None)
@@ -294,6 +300,7 @@ def run_tests(args):
294
300
  update_baseline=update_baseline,
295
301
  update_history=update_history,
296
302
  error_analysis=error_analysis,
303
+ error_analysis_all=error_analysis_all,
297
304
  last_failed=last_failed,
298
305
  resume=resume,
299
306
  plugin_dirs=plugin_dirs,
@@ -312,6 +319,7 @@ def run_tests(args):
312
319
  update_baseline=update_baseline,
313
320
  update_history=update_history,
314
321
  error_analysis=error_analysis,
322
+ error_analysis_all=error_analysis_all,
315
323
  last_failed=last_failed,
316
324
  resume=resume,
317
325
  plugin_dirs=plugin_dirs,
@@ -333,6 +341,7 @@ def run_tests(args):
333
341
  update_baseline=update_baseline,
334
342
  update_history=update_history,
335
343
  error_analysis=error_analysis,
344
+ error_analysis_all=error_analysis_all,
336
345
  last_failed=last_failed,
337
346
  resume=resume,
338
347
  plugin_dirs=plugin_dirs,
@@ -349,6 +358,7 @@ def run_tests(args):
349
358
  update_baseline=update_baseline,
350
359
  update_history=update_history,
351
360
  error_analysis=error_analysis,
361
+ error_analysis_all=error_analysis_all,
352
362
  last_failed=last_failed,
353
363
  resume=resume,
354
364
  plugin_dirs=plugin_dirs,
@@ -23,6 +23,7 @@ class BaseRunner(ABC):
23
23
  update_baseline: bool = False,
24
24
  update_history: bool = False,
25
25
  error_analysis: bool = False,
26
+ error_analysis_all: bool = False,
26
27
  last_failed: bool = False,
27
28
  resume: bool = False,
28
29
  plugin_dirs: Optional[List[str]] = None):
@@ -45,7 +46,8 @@ class BaseRunner(ABC):
45
46
  self.regression_threshold = regression_threshold
46
47
  self.update_baseline = update_baseline
47
48
  self.update_history = update_history
48
- self.error_analysis = error_analysis
49
+ self.error_analysis = error_analysis or error_analysis_all
50
+ self.error_analysis_all = error_analysis_all
49
51
  self.last_failed = last_failed
50
52
  self.resume = resume
51
53
 
@@ -62,6 +64,7 @@ class BaseRunner(ABC):
62
64
  "xfailed": 0,
63
65
  "xpassed": 0,
64
66
  "updated": 0,
67
+ "error_analysis_all": error_analysis_all,
65
68
  "details": []
66
69
  }
67
70
  self.assertions = Assertions()
@@ -294,6 +294,7 @@ def _dispatch_file_compare(
294
294
  return {
295
295
  "assertion": "compare_files",
296
296
  "passed": True,
297
+ "error_stats": cf_result.get("error_stats"),
297
298
  "compare_failures": [],
298
299
  "baseline_updated": [baseline_path],
299
300
  "message": "",
@@ -301,6 +302,7 @@ def _dispatch_file_compare(
301
302
  return {
302
303
  "assertion": "compare_files",
303
304
  "passed": True,
305
+ "error_stats": cf_result.get("error_stats"),
304
306
  "compare_failures": [],
305
307
  "baseline_updated": [],
306
308
  "message": "",
@@ -325,7 +327,9 @@ def _execute_command_once(
325
327
  output_max_chars: int = DEFAULT_OUTPUT_MAX_CHARS,
326
328
  ) -> TestResultData:
327
329
  """Execute a single command once (no retry logic)."""
328
- start_time = time.time()
330
+ # perf_counter: high-resolution monotonic clock; on Windows, time.time()
331
+ # has ~15.6ms granularity and can yield duration == 0.0 for fast commands.
332
+ start_time = time.perf_counter()
329
333
  cmd_list = _normalize_cmd_list(case["command"], [str(arg) for arg in case["args"]])
330
334
  timeout_limit = case.get("timeout", 3600)
331
335
 
@@ -434,7 +438,7 @@ def _execute_command_once(
434
438
  result["failure_kind"] = "execution_error"
435
439
  result["next_action_hint"] = _build_next_action_hint("execution_error")
436
440
  finally:
437
- result["duration"] = time.time() - start_time
441
+ result["duration"] = time.perf_counter() - start_time
438
442
 
439
443
  return result
440
444
 
@@ -95,10 +95,11 @@ class ParallelRunner(BaseRunner):
95
95
  **kwargs: 透传给 BaseRunner 的额外参数
96
96
  (test_case_filter, test_case_tag_filter, history_dir, regression_threshold)
97
97
  """
98
+ error_analysis_all = kwargs.get('error_analysis_all', False)
98
99
  super().__init__(config_file, workspace, **kwargs)
99
100
  self.max_workers = max_workers
100
101
  self.execution_mode = execution_mode
101
- self.error_analysis = error_analysis
102
+ self.error_analysis = error_analysis or error_analysis_all
102
103
  self.lock = threading.Lock() # 用于线程安全的结果更新
103
104
 
104
105
  def run_tests(self) -> bool:
@@ -10,10 +10,11 @@
10
10
 
11
11
  import csv
12
12
  import io
13
- import math
14
13
  import re
14
+ import numpy as np
15
15
  from .text_comparator import TextComparator
16
16
  from .result import Difference
17
+ from .numeric_compare import compare_numeric, parse_data_filter
17
18
 
18
19
  class CsvComparator(TextComparator):
19
20
  """
@@ -107,16 +108,13 @@ class CsvComparator(TextComparator):
107
108
  differences = []
108
109
  max_diffs = 10
109
110
 
110
- # ── Error analysis accumulators ──
111
- total_numeric_cells = 0
112
- mismatched_cells = 0
113
- sum_abs_error = 0.0
114
- sum_sq_abs_error = 0.0
115
- max_abs_error = None
116
- max_abs_error_at = None
117
- max_rel_error = None
118
- max_rel_error_at = None
119
-
111
+ # ── Numeric core accumulators ──
112
+ # error_analysis mode collects ALL filtered numeric cells (matching or not)
113
+ # and delegates statistics to the shared numeric core.
114
+ stats_exp = []
115
+ stats_act = []
116
+ stats_pos = [] # (row, col) 0-based, aligned with stats_exp/stats_act
117
+
120
118
  # Check row count
121
119
  if len(content1) != len(content2):
122
120
  differences.append(Difference(
@@ -140,42 +138,65 @@ class CsvComparator(TextComparator):
140
138
  if not self.error_analysis and len(differences) >= max_diffs:
141
139
  break
142
140
 
143
- # Compare column values
141
+ # Collect numeric cells in this row (for delegated closeness check)
142
+ row_exp = []
143
+ row_act = []
144
+ row_pos = [] # (row, col) 0-based
144
145
  for j, (cell1, cell2) in enumerate(zip(row1, row2)):
145
- if cell1 != cell2:
146
- # Try numeric tolerance comparison
147
- try:
148
- num1 = float(cell1)
149
- num2 = float(cell2)
150
- # Apply data filter
151
- if self.filter_func:
152
- if not (self.filter_func(num1) and self.filter_func(num2)):
153
- continue
154
- total_numeric_cells += 1
155
- abs_err = abs(num2 - num1)
156
- if math.isclose(num1, num2, rel_tol=self.rtol, abs_tol=self.atol):
157
- continue # Within tolerance
158
-
159
- # Mismatched numeric cell
160
- mismatched_cells += 1
161
- sum_abs_error += abs_err
162
- sum_sq_abs_error += abs_err * abs_err
163
- rel_err = abs_err / max(abs(num1), 1e-300) if abs(num1) > 0 else float("inf")
164
-
165
- if max_abs_error is None or abs_err > max_abs_error:
166
- max_abs_error = abs_err
167
- max_abs_error_at = f"row {i+1}, column {j+1}"
168
- if max_rel_error is None or rel_err > max_rel_error:
169
- max_rel_error = rel_err
170
- max_rel_error_at = f"row {i+1}, column {j+1}"
171
- except (ValueError, TypeError):
172
- pass # Non-numeric, fall through
173
-
174
- if len(differences) < max_diffs:
146
+ num1 = num2 = None
147
+ try:
148
+ num1 = float(cell1)
149
+ num2 = float(cell2)
150
+ except (ValueError, TypeError):
151
+ pass # Non-numeric
152
+
153
+ is_numeric = num1 is not None and num2 is not None
154
+ passes_filter = True
155
+ if is_numeric and self.filter_func:
156
+ # vectorized filter applied element-wise on scalar input
157
+ if not (bool(self.filter_func(np.asarray(num1))) and
158
+ bool(self.filter_func(np.asarray(num2)))):
159
+ passes_filter = False
160
+
161
+ if is_numeric and passes_filter:
162
+ # Counted as a numeric cell (regardless of text equality)
163
+ row_exp.append(num1)
164
+ row_act.append(num2)
165
+ row_pos.append((i, j))
166
+ if self.error_analysis:
167
+ stats_exp.append(num1)
168
+ stats_act.append(num2)
169
+ stats_pos.append((i, j))
170
+
171
+ if cell1 == cell2:
172
+ continue
173
+ if is_numeric:
174
+ # Numeric cell: within-tolerance decisions are made below via the core.
175
+ # Filtered-out numeric cells are skipped entirely (no difference).
176
+ continue
177
+
178
+ # Non-numeric text mismatch
179
+ if len(differences) < max_diffs:
180
+ differences.append(Difference(
181
+ position=f"row {i+1}, column {j+1}",
182
+ expected=cell1,
183
+ actual=cell2,
184
+ diff_type="cell_mismatch"
185
+ ))
186
+
187
+ # Determine closeness for this row's numeric cells via the shared core.
188
+ if row_exp:
189
+ row_res = compare_numeric(
190
+ row_exp, row_act, rtol=self.rtol, atol=self.atol,
191
+ filter_func=self.filter_func, collect_stats=False,
192
+ )
193
+ for k, is_mismatch in enumerate(row_res.mismatch_mask):
194
+ if is_mismatch and len(differences) < max_diffs:
195
+ ri, cj = row_pos[k]
175
196
  differences.append(Difference(
176
- position=f"row {i+1}, column {j+1}",
177
- expected=cell1,
178
- actual=cell2,
197
+ position=f"row {ri+1}, column {cj+1}",
198
+ expected=content1[ri][cj],
199
+ actual=content2[ri][cj],
179
200
  diff_type="cell_mismatch"
180
201
  ))
181
202
 
@@ -184,17 +205,31 @@ class CsvComparator(TextComparator):
184
205
 
185
206
  truncated = len(differences) >= max_diffs
186
207
 
187
- # ── Store error stats ──
188
- if self.error_analysis and total_numeric_cells > 0:
208
+ # ── Store error stats via the shared numeric core ──
209
+ if self.error_analysis and stats_exp:
210
+ res = compare_numeric(
211
+ stats_exp, stats_act, rtol=self.rtol, atol=self.atol,
212
+ filter_func=self.filter_func, collect_stats=True,
213
+ )
214
+ max_abs_error = res.max_abs_error
215
+ max_rel_error = res.max_rel_error
216
+ max_abs_error_at = None
217
+ max_rel_error_at = None
218
+ if max_abs_error is not None:
219
+ ri, cj = stats_pos[res.max_abs_error_index]
220
+ max_abs_error_at = f"row {ri+1}, column {cj+1}"
221
+ if max_rel_error is not None:
222
+ ri, cj = stats_pos[res.max_rel_error_index]
223
+ max_rel_error_at = f"row {ri+1}, column {cj+1}"
189
224
  self._error_stats = {
190
- "total_numeric_cells": total_numeric_cells,
191
- "mismatched_cells": mismatched_cells,
225
+ "total_numeric_cells": res.total,
226
+ "mismatched_cells": res.mismatched,
192
227
  "max_abs_error": max_abs_error,
193
228
  "max_abs_error_at": max_abs_error_at,
194
229
  "max_rel_error": max_rel_error,
195
230
  "max_rel_error_at": max_rel_error_at,
196
- "mean_abs_error": sum_abs_error / mismatched_cells if mismatched_cells > 0 else 0.0,
197
- "rms_abs_error": math.sqrt(sum_sq_abs_error / mismatched_cells) if mismatched_cells > 0 else 0.0,
231
+ "mean_abs_error": res.mean_abs_error,
232
+ "rms_abs_error": res.rms_abs_error,
198
233
  }
199
234
 
200
235
  if not differences:
@@ -202,40 +237,5 @@ class CsvComparator(TextComparator):
202
237
  return False, differences, truncated
203
238
 
204
239
  def _parse_filter(self):
205
- """Parse data filter string and return a scalar filter function"""
206
- if not self.data_filter:
207
- return None
208
- self.logger.debug(f"Parsing data filter: {self.data_filter}")
209
- try:
210
- match = re.match(
211
- r"^(abs)?([><]=?|==)([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)$",
212
- self.data_filter.replace(" ", ""),
213
- )
214
- if not match:
215
- self.logger.warning(
216
- f"Invalid data filter format: {self.data_filter}. Ignoring filter."
217
- )
218
- return None
219
- use_abs, op, value_str = match.groups()
220
- value = float(value_str)
221
- op_map = {
222
- ">": lambda x: x > value,
223
- ">=": lambda x: x >= value,
224
- "<": lambda x: x < value,
225
- "<=": lambda x: x <= value,
226
- "==": lambda x: x == value,
227
- }
228
-
229
- def filter_func(x):
230
- target = abs(x) if use_abs else x
231
- return op_map[op](target)
232
-
233
- self.logger.debug(
234
- f"Created filter function for pattern: {use_abs or ''}{op}{value}"
235
- )
236
- return filter_func
237
- except Exception as e:
238
- self.logger.error(
239
- f"Failed to parse data filter '{self.data_filter}': {e}. Ignoring filter."
240
- )
241
- return None
240
+ """Parse data filter string and return a filter function (delegates to numeric core)"""
241
+ return parse_data_filter(self.data_filter, logger=self.logger)