symtest-cli 1.4.0__tar.gz → 1.5.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 (425) hide show
  1. {symtest_cli-1.4.0/src/symtest_cli.egg-info → symtest_cli-1.5.0}/PKG-INFO +1 -1
  2. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/docs/design.md +44 -28
  3. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/docs/design_en.md +1 -20
  4. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/docs/user_manual.md +177 -27
  5. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/docs/user_manual_en.md +184 -23
  6. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/__init__.py +1 -1
  7. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/cli.py +16 -0
  8. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/commands/compare.py +27 -15
  9. symtest_cli-1.5.0/src/symtest/commands/migrate.py +160 -0
  10. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/config/config_schema.py +86 -10
  11. symtest_cli-1.5.0/src/symtest/config/normalize.py +43 -0
  12. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/base_runner.py +0 -19
  13. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/config_loader.py +28 -26
  14. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/orchestration/sequence.py +11 -23
  15. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/orchestration/single.py +2 -13
  16. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/parallel_runner.py +0 -2
  17. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/process_worker.py +4 -4
  18. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/test_case.py +88 -20
  19. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/validation/assertions.py +50 -2
  20. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/validation/validator.py +48 -9
  21. symtest_cli-1.5.0/src/symtest/file_comparator/__init__.py +44 -0
  22. symtest_cli-1.5.0/src/symtest/file_comparator/base_comparator.py +128 -0
  23. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/file_comparator/binary_comparator.py +6 -6
  24. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/file_comparator/csv_comparator.py +6 -5
  25. symtest_cli-1.5.0/src/symtest/file_comparator/extractor_comparator.py +199 -0
  26. symtest_cli-1.5.0/src/symtest/file_comparator/factory.py +341 -0
  27. symtest_cli-1.4.0/src/symtest/file_comparator/base_comparator.py → symtest_cli-1.5.0/src/symtest/file_comparator/file_comparator_base.py +57 -30
  28. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/file_comparator/h5_comparator.py +14 -8
  29. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/file_comparator/json_comparator.py +3 -4
  30. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/file_comparator/numeric_compare.py +43 -40
  31. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/file_comparator/result.py +66 -0
  32. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/file_comparator/script_comparator.py +22 -41
  33. symtest_cli-1.5.0/src/symtest/file_comparator/script_extract_comparator.py +160 -0
  34. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/file_comparator/text_comparator.py +2 -2
  35. symtest_cli-1.5.0/src/symtest/reporting/__init__.py +17 -0
  36. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/reporting/diagnosis.py +65 -2
  37. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/tui/controllers/case_controller.py +15 -5
  38. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/tui/widgets/steps_editor.py +5 -5
  39. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/utils/report_generator.py +80 -17
  40. {symtest_cli-1.4.0 → symtest_cli-1.5.0/src/symtest_cli.egg-info}/PKG-INFO +1 -1
  41. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest_cli.egg-info/SOURCES.txt +14 -1
  42. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
  43. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
  44. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-7.4.4.pyc +0 -0
  45. symtest_cli-1.5.0/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-9.0.3.pyc +0 -0
  46. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-7.4.4.pyc +0 -0
  47. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/__pycache__/test_history_feature.cpython-312-pytest-9.0.3.pyc +0 -0
  48. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/__pycache__/test_new_cli_features.cpython-312-pytest-7.4.4.pyc +0 -0
  49. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/__pycache__/test_new_cli_features.cpython-312-pytest-9.0.3.pyc +0 -0
  50. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-7.4.4.pyc +0 -0
  51. symtest_cli-1.5.0/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-9.0.3.pyc +0 -0
  52. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/__pycache__/test_sequence.cpython-312-pytest-7.4.4.pyc +0 -0
  53. symtest_cli-1.5.0/tests/integration/__pycache__/test_sequence.cpython-312-pytest-9.0.3.pyc +0 -0
  54. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  55. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  56. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  57. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  58. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  59. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  60. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  61. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  62. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  63. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  64. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  65. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  66. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/test_csv_compare.py +2 -2
  67. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/test_text_compare.py +8 -1
  68. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/parallel/__pycache__/test_depends_on.cpython-312-pytest-7.4.4.pyc +0 -0
  69. symtest_cli-1.5.0/tests/integration/parallel/__pycache__/test_depends_on.cpython-312-pytest-9.0.3.pyc +0 -0
  70. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  71. symtest_cli-1.5.0/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-9.0.3.pyc +0 -0
  72. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-7.4.4.pyc +0 -0
  73. symtest_cli-1.5.0/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-9.0.3.pyc +0 -0
  74. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/test_sequence.py +8 -8
  75. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_binary_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  76. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_binary_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  77. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_cli.cpython-312-pytest-7.4.4.pyc +0 -0
  78. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_cli.cpython-312-pytest-9.0.3.pyc +0 -0
  79. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_config_io.cpython-312-pytest-7.4.4.pyc +0 -0
  80. symtest_cli-1.5.0/tests/unit/__pycache__/test_config_io.cpython-312-pytest-9.0.3.pyc +0 -0
  81. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  82. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_h5_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  83. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-7.4.4.pyc +0 -0
  84. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_import_expander.cpython-312-pytest-9.0.3.pyc +0 -0
  85. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_inheritance_expander.cpython-312-pytest-7.4.4.pyc +0 -0
  86. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_inheritance_expander.cpython-312-pytest-9.0.3.pyc +0 -0
  87. symtest_cli-1.5.0/tests/unit/__pycache__/test_migrate.cpython-312-pytest-7.4.4.pyc +0 -0
  88. symtest_cli-1.5.0/tests/unit/__pycache__/test_migrate.cpython-312-pytest-9.0.3.pyc +0 -0
  89. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_result.cpython-312-pytest-7.4.4.pyc +0 -0
  90. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_result.cpython-312-pytest-9.0.3.pyc +0 -0
  91. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-7.4.4.pyc +0 -0
  92. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/commands/__pycache__/test_compare_command.cpython-312-pytest-9.0.3.pyc +0 -0
  93. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_architecture_guard.cpython-312-pytest-7.4.4.pyc +0 -0
  94. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_architecture_guard.cpython-312-pytest-9.0.3.pyc +0 -0
  95. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-7.4.4.pyc +0 -0
  96. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_assertions.cpython-312-pytest-9.0.3.pyc +0 -0
  97. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_case_env.cpython-312-pytest-7.4.4.pyc +0 -0
  98. symtest_cli-1.5.0/tests/unit/core/__pycache__/test_case_env.cpython-312-pytest-9.0.3.pyc +0 -0
  99. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-7.4.4.pyc +0 -0
  100. symtest_cli-1.5.0/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc +0 -0
  101. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-312-pytest-7.4.4.pyc +0 -0
  102. symtest_cli-1.5.0/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-312-pytest-9.0.3.pyc +0 -0
  103. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-7.4.4.pyc +0 -0
  104. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_execution.cpython-312-pytest-9.0.3.pyc +0 -0
  105. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_execution_new_features.cpython-312-pytest-7.4.4.pyc +0 -0
  106. symtest_cli-1.5.0/tests/unit/core/__pycache__/test_execution_new_features.cpython-312-pytest-9.0.3.pyc +0 -0
  107. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-7.4.4.pyc +0 -0
  108. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_history_store.cpython-312-pytest-9.0.3.pyc +0 -0
  109. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_last_run_store.cpython-312-pytest-7.4.4.pyc +0 -0
  110. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_last_run_store.cpython-312-pytest-9.0.3.pyc +0 -0
  111. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_model_v2.cpython-312-pytest-7.4.4.pyc +0 -0
  112. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_model_v2.cpython-312-pytest-9.0.3.pyc +0 -0
  113. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_orchestration_accept.cpython-312-pytest-7.4.4.pyc +0 -0
  114. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_orchestration_accept.cpython-312-pytest-9.0.3.pyc +0 -0
  115. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-7.4.4.pyc +0 -0
  116. symtest_cli-1.5.0/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-9.0.3.pyc +0 -0
  117. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_sequence_state.cpython-312-pytest-7.4.4.pyc +0 -0
  118. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_sequence_state.cpython-312-pytest-9.0.3.pyc +0 -0
  119. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-7.4.4.pyc +0 -0
  120. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_setup.cpython-312-pytest-9.0.3.pyc +0 -0
  121. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_validation_error.cpython-312-pytest-7.4.4.pyc +0 -0
  122. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_validation_error.cpython-312-pytest-9.0.3.pyc +0 -0
  123. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_xfail.cpython-312-pytest-7.4.4.pyc +0 -0
  124. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_xfail.cpython-312-pytest-9.0.3.pyc +0 -0
  125. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_architecture_guard.py +5 -5
  126. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_assertions.py +20 -5
  127. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_case_env.py +4 -4
  128. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_config_loader.py +3 -3
  129. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_config_loader_new_features.py +13 -10
  130. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_execution_new_features.py +31 -27
  131. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_model_v2.py +9 -9
  132. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_orchestration_accept.py +11 -3
  133. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_process_worker.py +6 -6
  134. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_sequence_state.py +3 -3
  135. symtest_cli-1.5.0/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-312-pytest-7.4.4.pyc +0 -0
  136. symtest_cli-1.5.0/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-312-pytest-9.0.3.pyc +0 -0
  137. symtest_cli-1.5.0/tests/unit/file_comparator/__pycache__/test_extractor_channels.cpython-312-pytest-7.4.4.pyc +0 -0
  138. symtest_cli-1.5.0/tests/unit/file_comparator/__pycache__/test_extractor_channels.cpython-312-pytest-9.0.3.pyc +0 -0
  139. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/__pycache__/test_numeric_compare.cpython-312-pytest-7.4.4.pyc +0 -0
  140. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/__pycache__/test_numeric_compare.cpython-312-pytest-9.0.3.pyc +0 -0
  141. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/__pycache__/test_numeric_parity.cpython-312-pytest-7.4.4.pyc +0 -0
  142. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/__pycache__/test_numeric_parity.cpython-312-pytest-9.0.3.pyc +0 -0
  143. symtest_cli-1.5.0/tests/unit/file_comparator/__pycache__/test_plugin_lifecycle.cpython-312-pytest-7.4.4.pyc +0 -0
  144. symtest_cli-1.5.0/tests/unit/file_comparator/__pycache__/test_plugin_lifecycle.cpython-312-pytest-9.0.3.pyc +0 -0
  145. symtest_cli-1.5.0/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  146. symtest_cli-1.5.0/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  147. symtest_cli-1.5.0/tests/unit/file_comparator/__pycache__/test_script_extract.cpython-312-pytest-7.4.4.pyc +0 -0
  148. symtest_cli-1.5.0/tests/unit/file_comparator/__pycache__/test_script_extract.cpython-312-pytest-9.0.3.pyc +0 -0
  149. symtest_cli-1.5.0/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-312-pytest-7.4.4.pyc +0 -0
  150. symtest_cli-1.5.0/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-312-pytest-9.0.3.pyc +0 -0
  151. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/test_error_analysis.py +24 -2
  152. symtest_cli-1.5.0/tests/unit/file_comparator/test_extractor_channels.py +253 -0
  153. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/test_numeric_compare.py +5 -3
  154. symtest_cli-1.5.0/tests/unit/file_comparator/test_plugin_lifecycle.py +390 -0
  155. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/test_script_comparator.py +10 -9
  156. symtest_cli-1.5.0/tests/unit/file_comparator/test_script_extract.py +187 -0
  157. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/test_workspace_plugins.py +29 -48
  158. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-7.4.4.pyc +0 -0
  159. symtest_cli-1.5.0/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc +0 -0
  160. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-7.4.4.pyc +0 -0
  161. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-312-pytest-9.0.3.pyc +0 -0
  162. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-7.4.4.pyc +0 -0
  163. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-312-pytest-9.0.3.pyc +0 -0
  164. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/test_migrate.py +199 -4
  165. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-7.4.4.pyc +0 -0
  166. symtest_cli-1.5.0/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
  167. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-7.4.4.pyc +0 -0
  168. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_app.cpython-312-pytest-9.0.3.pyc +0 -0
  169. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-7.4.4.pyc +0 -0
  170. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_case_controller.cpython-312-pytest-9.0.3.pyc +0 -0
  171. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-7.4.4.pyc +0 -0
  172. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_search_functions.cpython-312-pytest-9.0.3.pyc +0 -0
  173. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_tui_run_test.cpython-312-pytest-7.4.4.pyc +0 -0
  174. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_tui_run_test.cpython-312-pytest-9.0.3.pyc +0 -0
  175. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-7.4.4.pyc +0 -0
  176. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_widgets_data.cpython-312-pytest-9.0.3.pyc +0 -0
  177. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/conftest.py +3 -3
  178. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/test_case_controller.py +18 -12
  179. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/test_tui_run_test.py +3 -3
  180. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/test_widgets_data.py +2 -2
  181. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-7.4.4.pyc +0 -0
  182. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-312-pytest-9.0.3.pyc +0 -0
  183. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-7.4.4.pyc +0 -0
  184. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/utils/__pycache__/test_report_generator.cpython-312-pytest-9.0.3.pyc +0 -0
  185. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/utils/test_report_generator.py +177 -0
  186. symtest_cli-1.4.0/docs/design_1_4.md +0 -305
  187. symtest_cli-1.4.0/src/symtest/commands/migrate.py +0 -63
  188. symtest_cli-1.4.0/src/symtest/file_comparator/__init__.py +0 -10
  189. symtest_cli-1.4.0/src/symtest/file_comparator/factory.py +0 -191
  190. symtest_cli-1.4.0/src/symtest/reporting/__init__.py +0 -10
  191. symtest_cli-1.4.0/tests/e2e/__pycache__/test_user_flows.cpython-312-pytest-9.0.3.pyc +0 -0
  192. symtest_cli-1.4.0/tests/integration/__pycache__/test_real_command_execution.cpython-312-pytest-9.0.3.pyc +0 -0
  193. symtest_cli-1.4.0/tests/integration/__pycache__/test_sequence.cpython-312-pytest-9.0.3.pyc +0 -0
  194. symtest_cli-1.4.0/tests/integration/parallel/__pycache__/test_depends_on.cpython-312-pytest-9.0.3.pyc +0 -0
  195. symtest_cli-1.4.0/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-312-pytest-9.0.3.pyc +0 -0
  196. symtest_cli-1.4.0/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-312-pytest-9.0.3.pyc +0 -0
  197. symtest_cli-1.4.0/tests/unit/__pycache__/test_config_io.cpython-312-pytest-9.0.3.pyc +0 -0
  198. symtest_cli-1.4.0/tests/unit/__pycache__/test_migrate.cpython-312-pytest-7.4.4.pyc +0 -0
  199. symtest_cli-1.4.0/tests/unit/core/__pycache__/test_case_env.cpython-312-pytest-9.0.3.pyc +0 -0
  200. symtest_cli-1.4.0/tests/unit/core/__pycache__/test_config_loader.cpython-312-pytest-9.0.3.pyc +0 -0
  201. symtest_cli-1.4.0/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-312-pytest-9.0.3.pyc +0 -0
  202. symtest_cli-1.4.0/tests/unit/core/__pycache__/test_execution_new_features.cpython-312-pytest-9.0.3.pyc +0 -0
  203. symtest_cli-1.4.0/tests/unit/core/__pycache__/test_process_worker.cpython-312-pytest-9.0.3.pyc +0 -0
  204. symtest_cli-1.4.0/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-312-pytest-7.4.4.pyc +0 -0
  205. symtest_cli-1.4.0/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-312-pytest-9.0.3.pyc +0 -0
  206. symtest_cli-1.4.0/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  207. symtest_cli-1.4.0/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  208. symtest_cli-1.4.0/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-312-pytest-7.4.4.pyc +0 -0
  209. symtest_cli-1.4.0/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-312-pytest-9.0.3.pyc +0 -0
  210. symtest_cli-1.4.0/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312-pytest-9.0.3.pyc +0 -0
  211. symtest_cli-1.4.0/tests/unit/tui/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc +0 -0
  212. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/LICENSE +0 -0
  213. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/MANIFEST.in +0 -0
  214. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/README.md +0 -0
  215. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/docs/tui_and_config_split_design.md +0 -0
  216. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/pyproject.toml +0 -0
  217. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/setup.cfg +0 -0
  218. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/setup.py +0 -0
  219. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/commands/__init__.py +0 -0
  220. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/config/__init__.py +0 -0
  221. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/config/config_io.py +0 -0
  222. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/config/import_expander.py +0 -0
  223. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/config/inheritance_expander.py +0 -0
  224. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/config/migrate.py +0 -0
  225. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/__init__.py +0 -0
  226. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/execution/__init__.py +0 -0
  227. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/execution/executor.py +0 -0
  228. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/execution/result.py +0 -0
  229. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/history_store.py +0 -0
  230. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/last_run_store.py +0 -0
  231. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/orchestration/__init__.py +0 -0
  232. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/orchestration/accept.py +0 -0
  233. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/result.py +0 -0
  234. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/sequence_state.py +0 -0
  235. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/setup.py +0 -0
  236. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/types.py +0 -0
  237. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/validation/__init__.py +0 -0
  238. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/core/validation/result.py +0 -0
  239. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/file_comparator/xml_comparator.py +0 -0
  240. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/logging_config.py +0 -0
  241. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/runners/__init__.py +0 -0
  242. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/runners/config_runner.py +0 -0
  243. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/runners/json_runner.py +0 -0
  244. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/runners/parallel_config_runner.py +0 -0
  245. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/runners/parallel_json_runner.py +0 -0
  246. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/runners/parallel_yaml_runner.py +0 -0
  247. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/runners/yaml_runner.py +0 -0
  248. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/tui/__init__.py +0 -0
  249. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/tui/app.py +0 -0
  250. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/tui/controllers/__init__.py +0 -0
  251. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/tui/screens/__init__.py +0 -0
  252. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/tui/screens/case_editor.py +0 -0
  253. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/tui/screens/case_list.py +0 -0
  254. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/tui/widgets/__init__.py +0 -0
  255. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/tui/widgets/case_table.py +0 -0
  256. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/tui/widgets/expected_editor.py +0 -0
  257. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/tui/widgets/search_bar.py +0 -0
  258. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/utils/__init__.py +0 -0
  259. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/utils/junit_xml_writer.py +0 -0
  260. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest/utils/path_resolver.py +0 -0
  261. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest_cli.egg-info/dependency_links.txt +0 -0
  262. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest_cli.egg-info/entry_points.txt +0 -0
  263. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest_cli.egg-info/requires.txt +0 -0
  264. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/src/symtest_cli.egg-info/top_level.txt +0 -0
  265. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/README.md +0 -0
  266. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/__init__.py +0 -0
  267. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/__pycache__/__init__.cpython-312.pyc +0 -0
  268. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/__pycache__/__init__.cpython-313.pyc +0 -0
  269. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/__pycache__/__init__.cpython-39.pyc +0 -0
  270. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc +0 -0
  271. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/__pycache__/conftest.cpython-39-pytest-8.3.4.pyc +0 -0
  272. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/__pycache__/run_all.cpython-312.pyc +0 -0
  273. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/__pycache__/run_all.cpython-313.pyc +0 -0
  274. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/__pycache__/run_all.cpython-39.pyc +0 -0
  275. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/__pycache__/test_setup_module.cpython-312-pytest-7.4.4.pyc +0 -0
  276. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/conftest.py +0 -0
  277. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/demos/h5_filter_demo.py +0 -0
  278. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/demos/manual_report_example.py +0 -0
  279. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/demos/perf_parallel.py +0 -0
  280. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/e2e/__init__.py +0 -0
  281. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/e2e/__pycache__/__init__.cpython-312.pyc +0 -0
  282. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/e2e/__pycache__/__init__.cpython-313.pyc +0 -0
  283. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/e2e/__pycache__/__init__.cpython-39.pyc +0 -0
  284. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/e2e/__pycache__/test_user_flows.cpython-313-pytest-9.0.2.pyc +0 -0
  285. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/e2e/__pycache__/test_user_flows.cpython-39-pytest-8.3.4.pyc +0 -0
  286. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/e2e/test_user_flows.py +0 -0
  287. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/circular_config_a.json +0 -0
  288. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/circular_config_b.json +0 -0
  289. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/hourglass_stdout_mismatch.txt +0 -0
  290. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/hourglass_stdout_sample.txt +0 -0
  291. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/inheritance_base.json +0 -0
  292. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/inheritance_chain.json +0 -0
  293. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/inheritance_circular.json +0 -0
  294. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/main_config.json +0 -0
  295. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/circular_config_a.json +0 -0
  296. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/circular_config_b.json +0 -0
  297. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/inheritance_base.json +0 -0
  298. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/inheritance_chain.json +0 -0
  299. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/inheritance_circular.json +0 -0
  300. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/main_config.json +0 -0
  301. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/missing_fields.json +0 -0
  302. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/setup_main.json +0 -0
  303. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/setup_sub.json +0 -0
  304. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/skill_test_cases_golden_file.json +0 -0
  305. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/skill_test_cases_simple.json +0 -0
  306. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/skill_test_cases_simple.yaml +0 -0
  307. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/skill_test_cases_steps.json +0 -0
  308. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/sub_json_tests.yaml +0 -0
  309. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/sub_text_tests.json +0 -0
  310. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/test_cases.json +0 -0
  311. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/test_cases.yaml +0 -0
  312. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/test_cases1.json +0 -0
  313. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/test_with_setup.json +0 -0
  314. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/migration/v1/test_with_setup.yaml +0 -0
  315. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/missing_fields.json +0 -0
  316. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/mock_fail_script.py +0 -0
  317. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/mock_pass_script.py +0 -0
  318. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/setup_main.json +0 -0
  319. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/setup_sub.json +0 -0
  320. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/sub_json_tests.yaml +0 -0
  321. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/sub_text_tests.json +0 -0
  322. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/test_cases.json +0 -0
  323. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/test_cases.yaml +0 -0
  324. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/test_cases1.json +0 -0
  325. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/test_with_setup.json +0 -0
  326. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/fixtures/test_with_setup.yaml +0 -0
  327. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/__pycache__/test_history_feature.cpython-313-pytest-9.0.2.pyc +0 -0
  328. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/__pycache__/test_new_cli_features.cpython-313-pytest-9.0.2.pyc +0 -0
  329. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/__pycache__/test_real_command_execution.cpython-313-pytest-9.0.2.pyc +0 -0
  330. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/__pycache__/test_sequence.cpython-313-pytest-9.0.2.pyc +0 -0
  331. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  332. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_binary_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  333. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_csv_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  334. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  335. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_h5_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  336. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  337. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_json_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  338. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  339. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_text_compare.cpython-39-pytest-8.3.4.pyc +0 -0
  340. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/__pycache__/test_xml_compare.cpython-313-pytest-9.0.2.pyc +0 -0
  341. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/test_binary_compare.py +0 -0
  342. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/test_h5_compare.py +0 -0
  343. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/test_json_compare.py +0 -0
  344. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/file_compare/test_xml_compare.py +0 -0
  345. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-313-pytest-9.0.2.pyc +0 -0
  346. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/parallel/__pycache__/test_parallel_runner.cpython-39-pytest-8.3.4.pyc +0 -0
  347. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/parallel/test_depends_on.py +0 -0
  348. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/parallel/test_parallel_runner.py +0 -0
  349. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-313-pytest-9.0.2.pyc +0 -0
  350. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/path_handling/__pycache__/test_spaces_in_paths.cpython-39-pytest-8.3.4.pyc +0 -0
  351. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/path_handling/test_spaces_in_paths.py +0 -0
  352. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/test_history_feature.py +0 -0
  353. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/test_new_cli_features.py +0 -0
  354. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/integration/test_real_command_execution.py +0 -0
  355. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/run_all.py +0 -0
  356. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_binary_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
  357. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.2.pyc +0 -0
  358. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_config_io.cpython-313-pytest-9.0.2.pyc +0 -0
  359. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_h5_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
  360. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_import_expander.cpython-313-pytest-9.0.2.pyc +0 -0
  361. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_inheritance_expander.cpython-313-pytest-9.0.2.pyc +0 -0
  362. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_result.cpython-313-pytest-9.0.2.pyc +0 -0
  363. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-7.4.4.pyc +0 -0
  364. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_run_all.cpython-312-pytest-9.0.3.pyc +0 -0
  365. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/__pycache__/test_run_all.cpython-313-pytest-9.0.2.pyc +0 -0
  366. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/commands/__pycache__/test_compare_command.cpython-313-pytest-9.0.2.pyc +0 -0
  367. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/commands/test_compare_command.py +0 -0
  368. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_assertions.cpython-313-pytest-9.0.2.pyc +0 -0
  369. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_config_loader.cpython-313-pytest-9.0.2.pyc +0 -0
  370. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_config_loader_new_features.cpython-313-pytest-9.0.2.pyc +0 -0
  371. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_execution.cpython-312.pyc +0 -0
  372. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_execution.cpython-313-pytest-9.0.2.pyc +0 -0
  373. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_execution_new_features.cpython-313-pytest-9.0.2.pyc +0 -0
  374. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_history_store.cpython-313-pytest-9.0.2.pyc +0 -0
  375. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_last_run_store.cpython-313-pytest-9.0.2.pyc +0 -0
  376. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_process_worker.cpython-313-pytest-9.0.2.pyc +0 -0
  377. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_setup.cpython-313-pytest-9.0.2.pyc +0 -0
  378. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_setup.cpython-39-pytest-8.3.4.pyc +0 -0
  379. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_validation_error.cpython-313-pytest-9.0.2.pyc +0 -0
  380. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/__pycache__/test_xfail.cpython-313-pytest-9.0.2.pyc +0 -0
  381. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_execution.py +0 -0
  382. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_history_store.py +0 -0
  383. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_last_run_store.py +0 -0
  384. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_setup.py +0 -0
  385. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_validation_error.py +0 -0
  386. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/core/test_xfail.py +0 -0
  387. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/__pycache__/__init__.cpython-312.pyc +0 -0
  388. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/__pycache__/test_error_analysis.cpython-313-pytest-9.0.2.pyc +0 -0
  389. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-312-pytest-7.4.4.pyc +0 -0
  390. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-312-pytest-9.0.3.pyc +0 -0
  391. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/__pycache__/test_hourglass_tangent_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
  392. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/__pycache__/test_script_comparator.cpython-313-pytest-9.0.2.pyc +0 -0
  393. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/__pycache__/test_workspace_plugins.cpython-313-pytest-9.0.2.pyc +0 -0
  394. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/test_hourglass_tangent_comparator.py +0 -0
  395. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/file_comparator/test_numeric_parity.py +0 -0
  396. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-312.pyc +0 -0
  397. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-313-pytest-9.0.2.pyc +0 -0
  398. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/__pycache__/test_json_yaml_runner.cpython-39-pytest-8.3.4.pyc +0 -0
  399. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/__pycache__/test_test_case_filter.cpython-313-pytest-9.0.2.pyc +0 -0
  400. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/__pycache__/test_test_case_tag_filter.cpython-313-pytest-9.0.2.pyc +0 -0
  401. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/test_json_yaml_runner.py +0 -0
  402. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/test_test_case_filter.py +0 -0
  403. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/runners/test_test_case_tag_filter.py +0 -0
  404. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/test_binary_comparator.py +0 -0
  405. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/test_cli.py +0 -0
  406. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/test_config_io.py +0 -0
  407. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/test_h5_comparator.py +0 -0
  408. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/test_import_expander.py +0 -0
  409. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/test_inheritance_expander.py +0 -0
  410. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/test_result.py +0 -0
  411. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/test_run_all.py +0 -0
  412. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__init__.py +0 -0
  413. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/__init__.cpython-312.pyc +0 -0
  414. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/__init__.cpython-313.pyc +0 -0
  415. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc +0 -0
  416. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_app.cpython-313-pytest-9.0.2.pyc +0 -0
  417. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_case_controller.cpython-313-pytest-9.0.2.pyc +0 -0
  418. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_search_functions.cpython-313-pytest-9.0.2.pyc +0 -0
  419. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_tui_run_test.cpython-313-pytest-9.0.2.pyc +0 -0
  420. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/__pycache__/test_widgets_data.cpython-313-pytest-9.0.2.pyc +0 -0
  421. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/test_app.py +0 -0
  422. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/tui/test_search_functions.py +0 -0
  423. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/utils/__pycache__/test_junit_xml_writer.cpython-313-pytest-9.0.2.pyc +0 -0
  424. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/tests/unit/utils/__pycache__/test_report_generator.cpython-313-pytest-9.0.2.pyc +0 -0
  425. {symtest_cli-1.4.0 → symtest_cli-1.5.0}/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.4.0
3
+ Version: 1.5.0
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
@@ -155,14 +155,11 @@ PathResolver 解析(系统命令直通、shell builtin 平台包装、复合
155
155
  → 超时 kill 整个进程组
156
156
  → 返回附带 `next_action_hint` 的结构化结果。
157
157
 
158
- 当前实现的上述行为仍聚合在一处;1.4 将按 §10 宪法重排为
159
- Executor / Validator / Orchestration 三段(迁移明细见 docs/design_1_4.md)。
160
-
161
158
  ### 4.6 断言与文件比较集成
162
159
 
163
160
  - `compare_files` 是一等断言,经 ComparatorFactory 按类型分发(详见 §6)
164
161
  - 所有断言可选;未声明的字段不做校验
165
- - `--error-analysis` 为 CSV/H5 数值比较提供流式误差统计:`total_numeric_cells` / `mismatched_cells` / `max_abs_error` / `max_rel_error` / `mean_abs_error` / `rms_abs_error`
162
+ - `--error-analysis` 为 CSV/H5 数值比较提供流式误差统计:`total_numeric_cells` / `mismatched_cells` / `max_abs_error` / `max_rel_error` / `mean_abs_error` / `rms_abs_error`;幅值统计(max/mean/rms)覆盖全体参与比较的数值单元格(含通过格),mean/rms 以 `total_numeric_cells` 为分母。`--error-analysis-all` 额外对通过用例输出统计,除此之外两者行为一致
166
163
 
167
164
  ## 5. 运行时状态持久化(`.symtest/`)
168
165
 
@@ -178,24 +175,57 @@ Executor / Validator / Orchestration 三段(迁移明细见 docs/design_1_4.md
178
175
 
179
176
  ## 6. 文件比较子系统
180
177
 
181
- ### 6.1 比较器分层
178
+ ### 6.1 三泳道比较器架构
179
+
180
+ 所有比较器共享根契约 `ComparatorBase.compare(ctx) -> ComparisonResult`:
181
+ 框架构建 `CompareContext`(workspace / actual / baseline / params / error_analysis);
182
+ `actual`/`baseline` 以及插件 `path_params` 声明的构造参数在**比较器构造之前**
183
+ 按 workspace 统一解析,插件不得自行对 CWD resolve。配置单一事实源:
184
+ 比较器配置只存在于构造器捕获的实例状态,`ctx` 仅承载调用级上下文。
185
+ 三条泳道职责互斥:
186
+
187
+ | 泳道 | 基类 | 契约 | verdict 归属 | 内置实例 |
188
+ |---|---|---|---|---|
189
+ | 文件泳道 | `FileComparator` | `read_content` + `compare_content`(两文件模型,行列窗口、line N 偏移、chunk_size、similarity 均属本泳道) | 插件 | text / json / csv / xml / h5 / binary |
190
+ | 数据泳道 | `ExtractorComparator` | `extract(ctx) -> {channel: ChannelData}`;框架逐通道跑 `compare_numeric`,per-channel 容差(`channels` / `default_channel`),聚合 `ChannelResult` | **框架**(容差语义对 AI 消费端可预期) | script_extract、extractor 插件 |
191
+ | 自主泳道 | 直接继承根 | `compare(ctx)` 全权判定 | 插件 | script、hourglass 式分析插件 |
192
+
193
+ - 文本系共享 difflib 行级基底,json / csv / xml 为其结构化特化;h5 面向科学数据集;binary 流式分块 + LCS 相似度
194
+ - 统一返回 `ComparisonResult`(identical / differences / error / error_stats / command_output / channels),支持 text / json / html 渲染
195
+ - 数据泳道插件可通过 `ChannelData.extra_stats` 附带自定义误差指标,存放在独立命名空间(`ChannelResult.extra_stats`),不可覆盖框架规范指标;但 verdict 仍由框架容差持有——需要自定 verdict 的走自主泳道
196
+
197
+ ### 6.2 通道协议(数据泳道)
198
+
199
+ - 通道判定:`identical = all(channels.passed)`;差异 position 带通道前缀(`channel S33`);`error_stats` 按通道名嵌套
200
+ - 内置 `script_extract` 类型:子进程执行用户脚本(零改动接入),脚本 stdout 输出约定 JSON:
201
+
202
+ ```json
203
+ {"channels": {"S11": {"expected": [...], "actual": [...], "extra_stats": {...}}}}
204
+ ```
182
205
 
183
- - 文本系比较器共享 difflib 行级基底,json / csv / xml 为其结构化特化(键对齐 / 列结构 / DOM 对齐)
184
- - h5 面向科学数据集;binary 流式分块 + LCS 相似度;script 委托外部脚本
185
- - 统一返回 ComparisonResult(identical / differences / error / script command_output),支持 text / json / html 渲染;支持行列窗口范围参数截取后比较
206
+ 非零退出、超时、畸形 JSON 一律判为比较 error(绝不静默通过);`actual`/`baseline` 按惯例以 baseline 在前的顺序追加为尾部 argv 槽位(可缺省)
207
+ - 结果粒度:一条 compareSpec = 一条断言;`ComparisonResult.channels` 携带通道级子结果,报告逐通道展示 pass/fail + stats;JSON 输出中通道 differences 按 per-channel 配额截断
186
208
 
187
- ### 6.2 工厂与插件发现
209
+ ### 6.3 工厂与插件发现
188
210
 
189
- - `file_type` 取值:`text` / `json` / `csv` / `xml` / `h5` / `binary` / `script`;工厂按类型分发,支持动态注册与全局 reset(测试用)
211
+ - `file_type` 取值:`text` / `json` / `csv` / `xml` / `h5` / `binary` / `script` / `script_extract`;工厂按类型分发,支持动态注册与全局 reset(测试用)
190
212
  - 插件发现四处来源:内置 `*_comparator.py` 自动发现、`workspace/comparators/` 自动扫描、`--plugin-dir` CLI 参数、`CLITEST_PLUGIN_DIRS` 环境变量(供进程模式 worker 使用)
191
- - 命名约定:`*_comparator.py` + `*Comparator` 类名
213
+ - 命名约定:`*_comparator.py` + `*Comparator` 类名;可用类属性 `comparator_type` 显式指定类型名(如 `script_extract`);抽象基类自动跳过注册
214
+ - 配置传递与严格校验:`actual`/`baseline`/`type`/`options` 之外的键转发给比较器构造函数(kwargs);构造器参数是**严格**的——未声明的键(拼写错误)在构造时大声失败并给出支持参数清单。`options` 是框架持有的插件配置命名空间(并入构造参数,显式顶层键优先),核心 schema 不为单个插件增加专属字段;`channels`/`default_channel` 属数据泳道框架结构
192
215
 
193
- ### 6.3 script 比较协议(对外契约)
216
+ ### 6.4 script 比较协议(自主泳道对外契约)
194
217
 
195
- - 子进程方式执行 `<interpreter> <script> <actual> <baseline>`
218
+ - 子进程方式执行 `<interpreter> <script> <baseline> <actual>`(文件槽位可缺省)
196
219
  - 默认 exit code 0 → 通过;可选 `pass_pattern` / `fail_pattern` 正则匹配 stdout 细化判定
197
220
  - 超时可配
198
221
 
222
+ ### 6.5 插件公共 API
223
+
224
+ `symtest.file_comparator` 包导出:`ComparatorBase` / `CompareContext` /
225
+ `FileComparator` / `ExtractorComparator` / `ChannelData` / `ChannelResult` /
226
+ `compare_numeric` / `NumericComparisonStats` / `parse_data_filter`。
227
+ 数据泳道插件只需依赖 `ExtractorComparator` + `ChannelData`,数值判定全部复用框架核心。
228
+
199
229
  ## 7. TUI 子系统
200
230
 
201
231
  基于 Textual 的终端交互界面:App + Controller(load / create / update /
@@ -213,7 +243,7 @@ TUI 与 runner 共用同一解析器;宽松的展示形态在 TUI 侧自行处
213
243
  | 新配置格式 | `BaseRunner` | 支持新的测试定义格式(如 XML、TOML) |
214
244
  | 自定义 Setup | `BaseSetup` | 数据库初始化、服务启停等 |
215
245
  | 自定义断言 | 扩展 `Assertions` | 特定业务校验逻辑 |
216
- | 新比较器 | `BaseComparator` | 支持新的文件格式比较,放入 `comparators/` 目录自动发现 |
246
+ | 新比较器 | `FileComparator` / `ExtractorComparator` / `ComparatorBase` | 按泳道选择基类(文件格式 / 数据提取+通道 / 全权分析),放入 `comparators/` 目录自动发现 |
217
247
  | 新 Runner | `ParallelRunner` / `BaseRunner` | 自定义并行调度策略 |
218
248
  | TUI 扩展 | `CaseController` / Widgets | 扩展终端管理界面 |
219
249
 
@@ -252,7 +282,6 @@ TUI 与 runner 共用同一解析器;宽松的展示形态在 TUI 侧自行处
252
282
  > **地位与效力**:本节自 Symtest 1.4 Phase 0 评审定稿,是本项目的核心架构契约,
253
283
  > 对所有后续 feature 具有最高约束力——任何功能需求先对照本宪法确定归属,再写代码。
254
284
  > 修订宪法必须在变更说明中显式指出所放宽/违反的条款及理由。
255
- > 定稿前的演进推导见开发阶段文档 docs/design_1_4.md。
256
285
 
257
286
  ### 10.1 数据流主线
258
287
 
@@ -373,16 +402,3 @@ Reporter 的合法输入只能是 Result 类型;`next_action_hint` 属于 resu
373
402
  `reporter`;
374
403
  - guard 测试纳入常规回归套件(`python tests\run_all.py`),违规即失败;
375
404
  - 冲突裁决次序:guard 测试 > 本节文字 > 个人偏好。
376
-
377
- ### 10.6 现状差距与收敛路径
378
-
379
- 定稿时刻(1.4 Phase 0)现行实现与本宪法的已知偏差如下,将在 1.4 对应 Phase 内
380
- 逐项收敛(迁移明细见 docs/design_1_4.md):
381
-
382
- | 现状 | 违反 | 收敛 |
383
- |---|---|---|
384
- | `execution.py::validate_result` 住在执行层 | 原则 2 | Phase 2 迁入 `validation/validator.py` |
385
- | `next_action_hint` 在 execution 层构造 | 原则 5 | Phase 2 迁入 `reporting/diagnosis.py` |
386
- | retry 循环在 executor 内部 | 原则 2 / 4 | Phase 2 上移编排层 |
387
- | Validator 侧 update_baseline 写文件 | 原则 3 | Phase 2 改为 runner 独立 accept 步骤 |
388
- | `parse_test_cases` TUI mode 后门 | 原则 6 | Phase 2 拆除,单一解析器 |
@@ -164,10 +164,6 @@ stdout / stderr / returncode / duration) → assertions (return_code / contains
164
164
  matches / compare_files) → retries on failure up to `retry_count` → kills the
165
165
  whole process group on timeout → structured result with `next_action_hint`.
166
166
 
167
- Today these behaviors are aggregated in one place; 1.4 rearranges them into
168
- Executor / Validator / Orchestration per the §10 Constitution (migration details
169
- in docs/design_1_4.md).
170
-
171
167
  ### 4.6 Assertions and File Comparison Integration
172
168
 
173
169
  - `compare_files` is a first-class assertion dispatched via ComparatorFactory (see §6)
@@ -266,8 +262,7 @@ TUI side itself (§10 Principle 6).
266
262
  > project's core architectural contract with supreme authority over all future
267
263
  > features — resolve ownership against this constitution before writing any code.
268
264
  > Amending it requires explicitly naming the clause being relaxed/waived and the
269
- > rationale in the change description. Pre-ratification evolution history lives in
270
- > the development-phase document docs/design_1_4.md.
265
+ > rationale in the change description.
271
266
 
272
267
  ### 10.1 Data Flow Spine
273
268
 
@@ -398,17 +393,3 @@ architecture guard tests enforced by CI:
398
393
  - Guard tests are part of the regular regression suite
399
394
  (`python tests\run_all.py`); violations fail the build;
400
395
  - Conflict resolution order: guard tests > this text > personal preference.
401
-
402
- ### 10.6 Current Gap to This Constitution
403
-
404
- Known deviations of the current implementation from this constitution as of
405
- ratification (1.4 Phase 0). Each item converges during the corresponding 1.4
406
- phase (migration details in docs/design_1_4.md):
407
-
408
- | Current state | Violated | Convergence |
409
- |---|---|---|
410
- | `execution.py::validate_result` lives in the execution layer | Principle 2 | Phase 2: move to `validation/validator.py` |
411
- | `next_action_hint` built in the execution layer | Principle 5 | Phase 2: move to `reporting/diagnosis.py` |
412
- | Retry loop inside the executor | Principles 2 / 4 | Phase 2: lift to orchestration |
413
- | update_baseline writes files inside validation | Principle 3 | Phase 2: runner-side independent accept step |
414
- | `parse_test_cases` TUI-mode back door | Principle 6 | Phase 2: remove; single parser |
@@ -48,7 +48,7 @@ HDF5 文件比较依赖 `h5py`(已随框架安装)。如需在无 HDF5 环
48
48
 
49
49
  ## 测试用例定义
50
50
 
51
- > **Schema v2(1.4)**:配置采用分层 DSL——执行相关字段(`command`、`args`、`timeout`、`retry_count`、`env`、`steps`)位于 `execution` 块,调度相关字段(`depends_on`、`resources`)位于 `scheduling` 块,`expected` 保持在顶层。旧的扁平布局已移除,可使用 `symtest migrate` 迁移。
51
+ > **Schema v2(1.4)**:配置采用分层 DSL——执行相关字段(`command`、`args`、`timeout`、`retry_count`、`env`、`steps`)位于 `execution` 块,调度相关字段(`depends_on`、`resources`)位于 `scheduling` 块,`expected` 保持在顶层。旧的扁平布局已移除,可使用 `symtest migrate` 迁移。迁移会递归处理整棵 `import` 树:默认为每个文件生成 `<stem>.v2<ext>` 副本并自动重写父文件中的 import 路径;`--in-place` 则原地覆盖所有文件(与 `--output` 互斥)。
52
52
 
53
53
  ### JSON 格式
54
54
 
@@ -275,6 +275,13 @@ test_cases:
275
275
  | `expected.output_matches` | 否 | 输出需匹配的正则表达式(单个字符串) |
276
276
  | `expected.compare_files` | 否 | 文件比较断言列表,见下文 |
277
277
 
278
+ ### execution 二选一(互斥)
279
+
280
+ `execution` 有两种形态,**二选一**且互斥,同时声明两种形态属于配置错误:
281
+
282
+ - **单命令形态**:`command` + `args`(`timeout` / `retry_count` / `env` 可选)
283
+ - **序列形态**:`steps`(列表,每个 step 为 `command + args + expected`);`command` / `args` 不得与 `steps` 并存
284
+
278
285
  ## Case 级环境变量(env)
279
286
 
280
287
  通过 `execution` 内与 `command`、`steps` 同级的 `env` 字段,可为单个用例注入环境变量,仅在该用例(序列模式为所有 step)的子进程内生效,不影响其他用例。
@@ -1788,12 +1795,12 @@ CSV 比较按行列结构逐单元格比对;数值单元格在容差范围内
1788
1795
  |---|---|
1789
1796
  | `total_numeric_cells` | 参与数值比较的单元格总数 |
1790
1797
  | `mismatched_cells` | 超出容差的单元格数 |
1791
- | `max_abs_error` | 最大绝对误差及其位置 |
1792
- | `max_rel_error` | 最大相对误差及其位置 |
1793
- | `mean_abs_error` | 平均绝对误差 |
1794
- | `rms_abs_error` | 均方根绝对误差(RMSE) |
1798
+ | `max_abs_error` | 全体数值单元格中的最大绝对误差及其位置 |
1799
+ | `max_rel_error` | 全体数值单元格中的最大相对误差及其位置 |
1800
+ | `mean_abs_error` | 全体数值单元格的平均绝对误差(分母为 `total_numeric_cells`) |
1801
+ | `rms_abs_error` | 全体数值单元格的均方根绝对误差(RMSE,分母为 `total_numeric_cells`) |
1795
1802
 
1796
- 统计是**流式**计算的,不依赖差异截断,覆盖全体数值单元格。默认仅失败的比较输出统计,通过的比较不输出。
1803
+ 统计是**流式**计算的,不依赖差异截断,幅值统计(max/mean/rms)覆盖**全体**参与比较的数值单元格(含在容差内通过的单元格),可用于观察通过格离容差的余量;非有限值(NaN/inf)单元格不参与幅值统计。两个参数的统计口径完全一致,区别仅在于:默认仅失败的比较输出统计,通过的比较不输出。
1797
1804
 
1798
1805
  如需让**通过**的用例也输出统计信息(例如用于监控容差余量),可改用 `--error-analysis-all`(它会隐含启用 `--error-analysis`):
1799
1806
 
@@ -1965,11 +1972,31 @@ class MySetup(BaseSetup):
1965
1972
 
1966
1973
  ### 自定义文件比较器
1967
1974
 
1968
- 框架支持三种方式扩展比较能力:
1975
+ #### 三泳道架构(v2)
1976
+
1977
+ 比较器插件体系围绕根契约 `ComparatorBase.compare(ctx) -> ComparisonResult` 组织,
1978
+ 按判定权归属分为三条泳道:
1979
+
1980
+ | 泳道 | 基类 | 适用场景 | verdict 归属 |
1981
+ |---|---|---|---|
1982
+ | **文件泳道** | `FileComparator` | 比较两个同类文件(text/json/csv/xml/h5/binary 内置即此类) | 插件 |
1983
+ | **数据泳道** | `ExtractorComparator` | 从任意上游(文件/求解器输出/跨文件整理)提取数值数据,**复用框架数值核心**做通道化容差判定 | **框架** |
1984
+ | **自主泳道** | 直接继承 `ComparatorBase` | 独特判定逻辑(阈值组合、标签解析、渐近分析等) | 插件 |
1985
+
1986
+ 选型决策:
1969
1987
 
1970
- #### 方式一:工作区插件目录(推荐)
1988
+ - 数据本来就是 `(expected, actual)` 数值数组、只需 rtol/atol 判定 → **数据泳道**(可享受通道、per-channel 容差、统一 error_stats 与报告渲染)
1989
+ - 需要自定 verdict(比如"主分量紧、EAS 分量松"的组合判定、符号/渐近检查)→ **自主泳道**
1990
+ - 只是想让现成脚本快速接入 → 优先考虑内置 `script`(自定判定)或 `script_extract`(框架容差判定),零 Python 插件代码
1971
1991
 
1972
- 在 workspace 下创建 `comparators/` 目录,放入 `*_comparator.py` 文件(命名与内置比较器一致),框架会在首次使用时自动发现并注册其中的 `*Comparator` 类。
1992
+ **路径解析约定**:`actual`/`baseline` 以及插件用 `path_params` 类属性声明的路径参数,
1993
+ 由框架在**比较器构造之前**统一按 workspace 解析为绝对路径——构造器捕获的状态
1994
+ (`self.script`、`self.cwd` 等)持有的已是解析后的绝对路径。插件内部
1995
+ **禁止**对 CWD 做 `Path.resolve()`——并行/process 模式下 CWD 不可靠。
1996
+
1997
+ #### 插件发现方式(三种泳道通用)
1998
+
1999
+ 在 workspace 下创建 `comparators/` 目录,放入 `*_comparator.py` 文件,框架会在首次使用时自动发现并注册其中的 `*Comparator` 类。
1973
2000
 
1974
2001
  ```
1975
2002
  your-workspace/
@@ -1986,26 +2013,148 @@ symtest run test_config.json --plugin-dir ./extra_plugins
1986
2013
 
1987
2014
  插件也会通过环境变量 `CLITEST_PLUGIN_DIRS` 自动继承到 process 模式子进程。
1988
2015
 
1989
- **插件开发注意事项**:
1990
- - 继承 `symtest.file_comparator.BaseComparator`
2016
+ **命名约定**:
2017
+ - 文件名必须以 `_comparator.py` 结尾(如 `my_analysis_comparator.py`)
1991
2018
  - 类名必须以 `Comparator` 结尾(如 `MyAnalysisComparator`)
1992
- - 注册的 type 名 = 类名去掉 `Comparator` 再小写(如 `myanalysis`)
1993
- - 推荐重写 `compare_files(file1, file2, **kwargs)` 方法而非 `read_content`/`compare_content`(若比较器不使用两文件模型)
1994
- - 通过 `from symtest.file_comparator import ComparisonResult, Difference` 构造结构化结果
1995
- - `extra_kwargs` 自动从 config `compareSpec` 透传
2019
+ - 注册的 type 名 = 类名去掉 `Comparator` 再小写(如 `myanalysis`);也可用类属性 `comparator_type = "my_analysis"` 显式指定
2020
+ - 抽象基类(未实现全部抽象方法)自动跳过注册
1996
2021
 
1997
- 在配置中直接使用注册的类型名:
2022
+ 在配置中直接使用注册的类型名。比较器构造参数是**严格**的:`actual`/`baseline`/
2023
+ `type` 以外的键会透传给插件构造函数,但插件未声明的参数(如拼写错误
2024
+ `pass_threhsold`)会在构造时**大声失败**(错误信息包含比较器类型名与支持的
2025
+ 参数清单),绝不静默回退到默认值。插件自有配置建议放入 `options` 命名空间
2026
+ (其条目并入构造参数,显式顶层键优先),避免向核心 schema 增加插件专属字段:
1998
2027
 
1999
2028
  ```json
2000
2029
  {
2001
2030
  "type": "myanalysis",
2002
2031
  "actual": "optional_for_plugins",
2003
2032
  "baseline": "optional_for_plugins",
2004
- "param1": "value1"
2033
+ "options": {"param1": "value1", "param2": 42}
2034
+ }
2035
+ ```
2036
+
2037
+ #### 数据泳道:通道提取器插件
2038
+
2039
+ 适用场景:一个脚本/插件产出多通道数据(如 CSV 的不同列、不同物理量),
2040
+ 每通道需要独立的容差与误差分析。插件只负责"提取",判定完全由框架完成。
2041
+
2042
+ ```python
2043
+ # comparators/uel_stress_comparator.py
2044
+ import numpy as np
2045
+ from symtest.file_comparator import (
2046
+ ExtractorComparator, ChannelData, CompareContext,
2047
+ )
2048
+
2049
+ class UelStressComparator(ExtractorComparator):
2050
+ path_params = ("uel_csv", "ref_csv") # 由框架按 workspace 解析
2051
+
2052
+ def __init__(self, uel_csv="", ref_csv="", **kwargs):
2053
+ super().__init__(**kwargs)
2054
+ self.uel_csv = uel_csv
2055
+ self.ref_csv = ref_csv
2056
+
2057
+ def extract(self, ctx: CompareContext):
2058
+ uel = np.loadtxt(self.uel_csv, delimiter=",")
2059
+ ref = np.loadtxt(self.ref_csv, delimiter=",")
2060
+ return {
2061
+ "S11": ChannelData(expected=ref[:, 0], actual=uel[:, 0]),
2062
+ "S33": ChannelData(
2063
+ expected=ref[:, 2], actual=uel[:, 2],
2064
+ extra_stats={"hydrostatic_shift": float(uel[:, 2].mean())},
2065
+ ),
2066
+ }
2067
+ ```
2068
+
2069
+ 配置(per-channel 容差按名路由,未声明的通道用 `default_channel`):
2070
+
2071
+ ```json
2072
+ {
2073
+ "type": "uelstress",
2074
+ "uel_csv": "out/uel.csv",
2075
+ "ref_csv": "out/native.csv",
2076
+ "channels": {
2077
+ "S33": {"atol": 600.0, "data_filter": "abs>1e-12"}
2078
+ },
2079
+ "default_channel": {"rtol": 1e-5, "atol": 1e-8}
2005
2080
  }
2006
2081
  ```
2007
2082
 
2008
- #### 方式二:内置 `script` 类型比较器
2083
+ **判定与结果语义**:
2084
+ - 每通道独立跑 `compare_numeric`(对称容差 `|a-b| <= max(rtol*max(|a|,|b|), atol)`)
2085
+ - `identical = 所有通道全过`;一条 compareSpec 仍是一条断言
2086
+ - 差异 position 带通道前缀(`channel S33`);`error_stats` 按通道名嵌套
2087
+ - 报告逐通道展示 pass/fail、容差与统计;JSON 输出中通道差异按 per-channel 配额截断
2088
+ - 自定义误差指标通过 `ChannelData.extra_stats` 附带,存放在**独立命名空间**
2089
+ (`ChannelResult.extra_stats`),不可能覆盖框架规范指标(`max_abs_error`、
2090
+ `total` 等);报告逐通道分别渲染两个命名空间
2091
+ - verdict 不可由插件干预——需要自定 verdict 请走自主泳道
2092
+
2093
+ #### 数据泳道:内置 `script_extract` 类型(零改动脚本接入)
2094
+
2095
+ 现成分析脚本无需包装成 Python 插件:脚本以子进程执行,向 stdout 打印约定
2096
+ JSON,各通道即进入上述框架判定管线。
2097
+
2098
+ ```json
2099
+ {
2100
+ "type": "script_extract",
2101
+ "script": "extract_channels.py",
2102
+ "args": ["--frame", "10"],
2103
+ "cwd": "case/subdir",
2104
+ "channels": {"S33": {"atol": 600.0}},
2105
+ "default_channel": {"rtol": 1e-5, "atol": 1e-8},
2106
+ "timeout": 600
2107
+ }
2108
+ ```
2109
+
2110
+ **stdout JSON 协议**:
2111
+
2112
+ ```json
2113
+ {
2114
+ "channels": {
2115
+ "S11": {"expected": [1.0, 2.0], "actual": [1.0, 2.0]},
2116
+ "S33": {"expected": [...], "actual": [...], "extra_stats": {"asymmetry": 2e-13}}
2117
+ }
2118
+ }
2119
+ ```
2120
+
2121
+ **错误语义**:非零退出码、超时、畸形 JSON、缺 `channels` 键或通道缺
2122
+ `expected`/`actual` 数组 → 一律判为比较 error(绝不静默通过)。
2123
+ `actual`/`baseline`(若配置)以 baseline 在前的顺序追加为脚本尾部参数,可缺省。
2124
+
2125
+ #### 自主泳道:全权判定插件
2126
+
2127
+ 适用场景:独特判定逻辑。插件实现 `compare(ctx)` 并直接返回结果。
2128
+
2129
+ ```python
2130
+ # comparators/my_analysis_comparator.py
2131
+ from symtest.file_comparator import ComparatorBase, CompareContext, ComparisonResult, Difference
2132
+
2133
+ class MyAnalysisComparator(ComparatorBase):
2134
+ path_params = ("script", "case_dir")
2135
+
2136
+ def __init__(self, script="", case_dir=None, pass_threshold=1e-6):
2137
+ super().__init__() # 参数严格:未声明/拼错的配置键在构造时报错
2138
+ self.script = script # 构造前已由框架按 workspace 解析
2139
+ self.case_dir = case_dir
2140
+ self.pass_threshold = pass_threshold
2141
+
2142
+ def compare(self, ctx: CompareContext) -> ComparisonResult:
2143
+ result = ComparisonResult(
2144
+ file1=ctx.baseline, # 无文件输入时保持 None,不伪造空串
2145
+ file2=ctx.actual,
2146
+ )
2147
+ # ... 执行分析、解析指标 ...
2148
+ result.identical = True # 或 False + differences
2149
+ result.error_stats = {"full_rel": 8e-8} # 自由 dict,报告通用渲染
2150
+ return result
2151
+ ```
2152
+
2153
+ `ctx` 字段(仅调用级上下文):`workspace` / `actual` / `baseline`(可空,
2154
+ 无文件输入时为 `None`)/ `params`(文件泳道窗口参数)/ `error_analysis`。
2155
+ 比较器配置的唯一权威在构造器捕获的实例状态中——`ctx` 不携带配置副本。
2156
+
2157
+ #### 内置 `script` 类型比较器(自主泳道开箱即用)
2009
2158
 
2010
2159
  适用于独立分析脚本快速接入,无需编写比较器类:
2011
2160
 
@@ -2028,8 +2177,8 @@ symtest run test_config.json --plugin-dir ./extra_plugins
2028
2177
  | 参数 | 必填 | 默认值 | 说明 |
2029
2178
  |---|---|---|---|
2030
2179
  | `script` | 是 | — | 脚本路径(相对 workspace 或绝对) |
2031
- | `actual` | 否 | — | 传给脚本的第一个文件参数 |
2032
- | `baseline` | 否 | — | 传给脚本的第二个文件参数 |
2180
+ | `actual` | 否 | — | 传给脚本的文件参数(尾部第二位) |
2181
+ | `baseline` | 否 | — | 传给脚本的文件参数(尾部第一位) |
2033
2182
  | `cwd` | 否 | — | 脚本工作目录 |
2034
2183
  | `interpreter` | 否 | `sys.executable` | Python 解释器 |
2035
2184
  | `pass_exit_code` | 否 | `0` | 判定为通过的退出码 |
@@ -2045,15 +2194,15 @@ symtest run test_config.json --plugin-dir ./extra_plugins
2045
2194
 
2046
2195
  脚本的 stdout 和 stderr 会完整捕获到 `Comparator Output` 区块中,在报告渲染时限 20 行展示。
2047
2196
 
2048
- #### 方式三:手动注册(编程方式)
2197
+ #### 手动注册(编程方式)
2049
2198
 
2050
2199
  ```python
2051
- from symtest.file_comparator import ComparatorFactory
2052
- from symtest.file_comparator.base_comparator import BaseComparator
2200
+ from symtest.file_comparator import ComparatorFactory, ComparatorBase, CompareContext
2201
+ from symtest.file_comparator.result import ComparisonResult
2053
2202
 
2054
- class FooComparator(BaseComparator):
2055
- # 实现 read_content / compare_content 等方法
2056
- pass
2203
+ class FooComparator(ComparatorBase):
2204
+ def compare(self, ctx: CompareContext) -> ComparisonResult:
2205
+ ...
2057
2206
 
2058
2207
  ComparatorFactory.register_comparator("foo", FooComparator)
2059
2208
 
@@ -2063,7 +2212,7 @@ comparator = ComparatorFactory.create_comparator("foo")
2063
2212
 
2064
2213
  #### 专用插件示例:hourglass 切线刚度分析
2065
2214
 
2066
- `examples/plugins/hourglass_tangent_comparator.py` 是一个完整的工作区插件示例,展示了如何将专用的 `analyze_*_tangent.py` 分析脚本接入框架:
2215
+ `examples/plugins/hourglass_tangent_comparator.py` 是一个完整的自主泳道工作区插件示例,展示了如何将专用的 `analyze_*_tangent.py` 分析脚本接入框架:
2067
2216
 
2068
2217
  ```json
2069
2218
  {
@@ -2078,6 +2227,7 @@ comparator = ComparatorFactory.create_comparator("foo")
2078
2227
  **特点**:
2079
2228
  - 通过 subprocess 调分析脚本(**零改动** analyze 代码),捕获 stdout 后用正则解析 `RESULT:` 行和 `full_rel`/`aa_rel`/`hh_rel`/`asymmetry` 等数值指标
2080
2229
  - 构造结构化 `ComparisonResult`:`identical` 基于 `full_rel < pass_threshold` 判定;`differences` 列出超限指标;`error_stats` 包含全部数值
2230
+ - `path_params` 声明 `script`/`case_dir`,路径由框架按 workspace 解析
2081
2231
  - 脚本 stdout 进入 `Comparator Output` 区块
2082
2232
 
2083
2233
  使用方法:将插件文件复制到 workspace 的 `comparators/` 目录下即可自动发现,无需改框架代码。