PyBreeze 1.0.25__tar.gz → 1.0.26__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 (183) hide show
  1. {pybreeze-1.0.25 → pybreeze-1.0.26}/PKG-INFO +7 -3
  2. {pybreeze-1.0.25 → pybreeze-1.0.26}/README.md +6 -2
  3. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend_multi_language/extend_english.py +70 -0
  4. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend_multi_language/extend_traditional_chinese.py +70 -0
  5. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/tools/tools_menu.py +41 -0
  6. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/curl_import_gui.py +39 -6
  7. pybreeze-1.0.26/pybreeze/pybreeze_ui/tools_gui/header_analyzer_gui.py +108 -0
  8. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/response_inspector_gui.py +27 -13
  9. pybreeze-1.0.26/pybreeze/pybreeze_ui/tools_gui/tool_tabs.py +31 -0
  10. pybreeze-1.0.26/pybreeze/pybreeze_ui/tools_gui/url_builder_gui.py +89 -0
  11. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/curl_import/curl_parser.py +186 -20
  12. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/curl_import/request_codegen.py +8 -0
  13. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/curl_import/script_templates.py +6 -1
  14. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/exception/exception_tags.py +4 -0
  15. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/exception/exceptions.py +6 -0
  16. pybreeze-1.0.26/pybreeze/utils/header_tools/header_analyzer.py +318 -0
  17. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/response_inspector/response_analyzer.py +2 -3
  18. pybreeze-1.0.26/pybreeze/utils/timestamp_tools/__init__.py +0 -0
  19. pybreeze-1.0.26/pybreeze/utils/url_tools/__init__.py +0 -0
  20. pybreeze-1.0.26/pybreeze/utils/url_tools/url_convert.py +117 -0
  21. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze.egg-info/PKG-INFO +7 -3
  22. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze.egg-info/SOURCES.txt +8 -1
  23. {pybreeze-1.0.25 → pybreeze-1.0.26}/pyproject.toml +1 -1
  24. {pybreeze-1.0.25 → pybreeze-1.0.26}/LICENSE +0 -0
  25. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/__init__.py +0 -0
  26. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/__main__.py +0 -0
  27. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/__init__.py +0 -0
  28. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/mail_thunder_extend/__init__.py +0 -0
  29. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/mail_thunder_extend/mail_thunder_setting.py +0 -0
  30. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/__init__.py +0 -0
  31. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/api_testka/__init__.py +0 -0
  32. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/api_testka/api_testka_process.py +0 -0
  33. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/auto_control/__init__.py +0 -0
  34. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/auto_control/auto_control_process.py +0 -0
  35. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/file_automation/__init__.py +0 -0
  36. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/file_automation/file_automation_process.py +0 -0
  37. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/file_runner_process.py +0 -0
  38. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/load_density/__init__.py +0 -0
  39. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/load_density/load_density_process.py +0 -0
  40. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/mail_thunder/__init__.py +0 -0
  41. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/mail_thunder/mail_thunder_process.py +0 -0
  42. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/process_executor_utils.py +0 -0
  43. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/python_task_process_manager.py +0 -0
  44. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/queue_pump.py +0 -0
  45. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/test_pioneer/__init__.py +0 -0
  46. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/test_pioneer/test_pioneer_process_manager.py +0 -0
  47. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/web_runner/__init__.py +0 -0
  48. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/web_runner/web_runner_process.py +0 -0
  49. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend_multi_language/__init__.py +0 -0
  50. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend_multi_language/update_language_dict.py +0 -0
  51. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/__init__.py +0 -0
  52. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/__init__.py +0 -0
  53. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/__init__.py +0 -0
  54. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/ssh_command_widget.py +0 -0
  55. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/ssh_file_viewer_widget.py +0 -0
  56. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/ssh_host_key_policy.py +0 -0
  57. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/ssh_key_loader.py +0 -0
  58. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/ssh_login_widget.py +0 -0
  59. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/ssh_main_widget.py +0 -0
  60. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/url/__init__.py +0 -0
  61. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/url/ai_code_review_gui.py +0 -0
  62. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/__init__.py +0 -0
  63. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_commands.py +0 -0
  64. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_editor_widget.py +0 -0
  65. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_items.py +0 -0
  66. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_mermaid_parser.py +0 -0
  67. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_net_utils.py +0 -0
  68. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_property_panel.py +0 -0
  69. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_scene.py +0 -0
  70. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_view.py +0 -0
  71. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/editor_main/__init__.py +0 -0
  72. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/editor_main/file_tree_context_menu.py +0 -0
  73. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/editor_main/main_ui.py +0 -0
  74. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/__init__.py +0 -0
  75. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/ai_gui_global_variable.py +0 -0
  76. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/code_review/__init__.py +0 -0
  77. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/code_review/code_review_thread.py +0 -0
  78. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/code_review/cot_code_review_gui.py +0 -0
  79. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/__init__.py +0 -0
  80. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/__init__.py +0 -0
  81. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/code_smell_detector.py +0 -0
  82. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/first_code_review.py +0 -0
  83. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/first_summary_prompt.py +0 -0
  84. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/global_rule.py +0 -0
  85. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/judge.py +0 -0
  86. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/judge_single_review.py +0 -0
  87. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/linter.py +0 -0
  88. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/step_by_step_analysis.py +0 -0
  89. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/total_summary.py +0 -0
  90. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_prompt_editor_widget.py +0 -0
  91. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/prompt_file_io.py +0 -0
  92. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/skills_prompt_editor_widget.py +0 -0
  93. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/skills_prompt_templates/__init__.py +0 -0
  94. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/skills_prompt_templates/code_explainer.py +0 -0
  95. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/skills_prompt_templates/code_review.py +0 -0
  96. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/skills/__init__.py +0 -0
  97. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/skills/skills_send_gui.py +0 -0
  98. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/jupyter_lab_gui/__init__.py +0 -0
  99. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/jupyter_lab_gui/jupyter_lab_thread.py +0 -0
  100. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/jupyter_lab_gui/jupyter_lab_widget.py +0 -0
  101. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/__init__.py +0 -0
  102. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/__init__.py +0 -0
  103. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/api_testka_menu/__init__.py +0 -0
  104. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/api_testka_menu/build_api_testka_menu.py +0 -0
  105. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/auto_control_menu/__init__.py +0 -0
  106. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/auto_control_menu/build_autocontrol_menu.py +0 -0
  107. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/automation_file_menu/__init__.py +0 -0
  108. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/automation_file_menu/build_automation_file_menu.py +0 -0
  109. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/automation_menu_factory.py +0 -0
  110. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/load_density_menu/__init__.py +0 -0
  111. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/load_density_menu/build_load_density_menu.py +0 -0
  112. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/mail_thunder_menu/__init__.py +0 -0
  113. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/mail_thunder_menu/build_mail_thunder_menu.py +0 -0
  114. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/test_pioneer_menu/__init__.py +0 -0
  115. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/test_pioneer_menu/build_test_pioneer_menu.py +0 -0
  116. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/web_runner_menu/__init__.py +0 -0
  117. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/web_runner_menu/build_webrunner_menu.py +0 -0
  118. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/build_menubar.py +0 -0
  119. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/extend_jeditor_tab_menu/__init__.py +0 -0
  120. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/extend_jeditor_tab_menu/jupyter_lab_tab.py +0 -0
  121. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/install_menu/__init__.py +0 -0
  122. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/install_menu/automation_menu/__init__.py +0 -0
  123. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/install_menu/automation_menu/build_automation_install_menu.py +0 -0
  124. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/install_menu/install_utils.py +0 -0
  125. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/install_menu/tools_menu/__init__.py +0 -0
  126. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/install_menu/tools_menu/build_tool_install_menu.py +0 -0
  127. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/menu_utils.py +0 -0
  128. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/plugin_menu/__init__.py +0 -0
  129. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/plugin_menu/build_plugin_menu.py +0 -0
  130. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/plugin_menu/build_run_with_menu.py +0 -0
  131. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/tools/__init__.py +0 -0
  132. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/show_code_window/__init__.py +0 -0
  133. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/show_code_window/code_window.py +0 -0
  134. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/syntax/__init__.py +0 -0
  135. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/syntax/syntax_extend.py +0 -0
  136. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/syntax/syntax_keyword.py +0 -0
  137. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/__init__.py +0 -0
  138. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/diff_gui.py +0 -0
  139. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/hash_gui.py +0 -0
  140. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/http_status_gui.py +0 -0
  141. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/json_format_gui.py +0 -0
  142. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/jwt_decoder_gui.py +0 -0
  143. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/output_actions.py +0 -0
  144. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/query_json_gui.py +0 -0
  145. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/regex_gui.py +0 -0
  146. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/timestamp_gui.py +0 -0
  147. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/__init__.py +0 -0
  148. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/app_dirs.py +0 -0
  149. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/curl_import/__init__.py +0 -0
  150. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/curl_import/request_body.py +0 -0
  151. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/diff_tools/__init__.py +0 -0
  152. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/diff_tools/text_diff.py +0 -0
  153. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/exception/__init__.py +0 -0
  154. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/file_process/__init__.py +0 -0
  155. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/file_process/get_dir_file_list.py +0 -0
  156. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/hash_tools/__init__.py +0 -0
  157. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/hash_tools/hash_text.py +0 -0
  158. {pybreeze-1.0.25/pybreeze/utils/http_reference → pybreeze-1.0.26/pybreeze/utils/header_tools}/__init__.py +0 -0
  159. {pybreeze-1.0.25/pybreeze/utils/jwt_tools → pybreeze-1.0.26/pybreeze/utils/http_reference}/__init__.py +0 -0
  160. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/http_reference/status_codes.py +0 -0
  161. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/json_format/__init__.py +0 -0
  162. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/json_format/json_process.py +0 -0
  163. {pybreeze-1.0.25/pybreeze/utils/logging → pybreeze-1.0.26/pybreeze/utils/jwt_tools}/__init__.py +0 -0
  164. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/jwt_tools/jwt_decoder.py +0 -0
  165. {pybreeze-1.0.25/pybreeze/utils/manager → pybreeze-1.0.26/pybreeze/utils/logging}/__init__.py +0 -0
  166. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/logging/logger.py +0 -0
  167. {pybreeze-1.0.25/pybreeze/utils/manager/package_manager → pybreeze-1.0.26/pybreeze/utils/manager}/__init__.py +0 -0
  168. {pybreeze-1.0.25/pybreeze/utils/network → pybreeze-1.0.26/pybreeze/utils/manager/package_manager}/__init__.py +0 -0
  169. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/manager/package_manager/package_manager_class.py +0 -0
  170. {pybreeze-1.0.25/pybreeze/utils/query_tools → pybreeze-1.0.26/pybreeze/utils/network}/__init__.py +0 -0
  171. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/network/http_client.py +0 -0
  172. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/network/url_validation.py +0 -0
  173. {pybreeze-1.0.25/pybreeze/utils/regex_tools → pybreeze-1.0.26/pybreeze/utils/query_tools}/__init__.py +0 -0
  174. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/query_tools/query_convert.py +0 -0
  175. {pybreeze-1.0.25/pybreeze/utils/response_inspector → pybreeze-1.0.26/pybreeze/utils/regex_tools}/__init__.py +0 -0
  176. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/regex_tools/regex_tester.py +0 -0
  177. {pybreeze-1.0.25/pybreeze/utils/timestamp_tools → pybreeze-1.0.26/pybreeze/utils/response_inspector}/__init__.py +0 -0
  178. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/subprocess_util.py +0 -0
  179. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/timestamp_tools/timestamp_converter.py +0 -0
  180. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze.egg-info/dependency_links.txt +0 -0
  181. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze.egg-info/requires.txt +0 -0
  182. {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze.egg-info/top_level.txt +0 -0
  183. {pybreeze-1.0.25 → pybreeze-1.0.26}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pybreeze
3
- Version: 1.0.25
3
+ Version: 1.0.26
4
4
  Summary: IDE for multi automation
5
5
  Author-email: JE-Chen <jechenmailman@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/Intergration-Automation-Testing/AutomationEditor
@@ -109,16 +109,18 @@ PyBreeze is not just a code editor — it is a command center for the automation
109
109
  - Mermaid `flowchart` / `graph` import
110
110
  - Save/Open as `.diagram.json`, export to PNG or SVG
111
111
  - Undo/redo, align, distribute, grid, snap, and zoom controls
112
- - **cURL Import** — Paste a `curl` command copied from your browser's dev tools and generate a ready-to-run script for the target of your choice: **Python `requests`**, an **APITestka Python** snippet (`test_api_method_requests(...)`), an **APITestka JSON action** (`[["AT_test_api_method", {...}]]`) that `execute_files` runs directly, or a **LoadDensity** Locust load-test (`start_test(...)`). (These are the HTTP-oriented modules; a curl request has no meaningful mapping to the browser or desktop-GUI automation modules.) Parses the method, URL, headers, body, basic auth, `-G` query parameters, `-F` multipart form fields (file uploads become `files=open(...)`), the `--json` shortcut (which also sets the JSON `Content-Type`/`Accept`), and `-d @file` bodies (which become `open(...).read()`, while `--data-raw` stays literal) — all with multi-line `\` / `^` continuations. It knows the arity of curl's common flags, so value-taking options like `--max-time 30` or `-o out.json` never leak into the URL; it URL-encodes `--data-urlencode` values the way curl does; and it infers `POST` when a body or form is present and sends JSON bodies as JSON. Targets include Python `requests`, a ready-to-run **pytest test** (a named `test_...` function that sends the request and asserts the status), APITestka (Python and JSON action), and a LoadDensity load test. Pick one from the dropdown, then copy the result, **open it straight into a new editor tab**, or **save it to a `.py` / `.json` file** (the extension follows the chosen target). The parser is pure logic and never executes the command.
112
+ - **cURL Import** — Paste a `curl` command copied from your browser's dev tools and generate a ready-to-run script for the target of your choice: **Python `requests`**, an **APITestka Python** snippet (`test_api_method_requests(...)`), an **APITestka JSON action** (`[["AT_test_api_method", {...}]]`) that `execute_files` runs directly, or a **LoadDensity** Locust load-test (`start_test(...)`). (These are the HTTP-oriented modules; a curl request has no meaningful mapping to the browser or desktop-GUI automation modules.) Parses the method, URL, headers, body, basic auth, `-G` query parameters, `-F` multipart form fields (file uploads become `files=open(...)`), the `--json` shortcut (which also sets the JSON `Content-Type`/`Accept`), and `-d @file` bodies (which become `open(...).read()`, while `--data-raw` stays literal) — all with multi-line `\` / `^` continuations. It knows the arity of curl's common flags, so value-taking options like `--max-time 30` or `-o out.json` never leak into the URL; it URL-encodes `--data-urlencode` values the way curl does; and it infers `POST` when a body or form is present and sends JSON bodies as JSON. Targets include Python `requests`, a ready-to-run **pytest test** (a named `test_...` function that sends the request and asserts the status), APITestka (Python and JSON action), and a LoadDensity load test. Pick one from the dropdown, then copy the result, **open it straight into a new editor tab**, or **save it to a `.py` / `.json` file** (the extension follows the chosen target). A repeated `-H` is handled the way HTTP handles it — the values are combined into one header (with `; ` for cookies) rather than the last one silently winning, and names are matched case-insensitively so an explicit header always beats one implied by another flag. One click also **hands the parsed URL to the URL parser/builder**, query string and all. The parser is pure logic and never executes the command.
113
113
  - **JWT Decoder** — Paste a JSON Web Token and read its header and payload as pretty-printed JSON, with standard timestamp claims (`exp`, `iat`, `nbf`, `auth_time`) rendered as readable UTC times. Inspection only — the signature is never verified and the token is never trusted.
114
114
  - **Timestamp Converter** — Enter a Unix epoch value (seconds or milliseconds, auto-detected) or an ISO-8601 date-time (with `Z` or an offset) and get every representation back in UTC. Deterministic and independent of the local time zone.
115
115
  - **Hash Generator** — Compute SHA-256, SHA-512, SHA-1 and MD5 digests of any text at once. A general-purpose checksum tool (MD5/SHA-1 are provided for interoperability with `usedforsecurity=False`, never for security decisions).
116
116
  - **Query ⇄ JSON** — Convert an `application/x-www-form-urlencoded` query string to pretty JSON and back, URL-decoding and -encoding as needed. Repeated keys become JSON arrays and vice versa. Copy the result, open it in an editor tab, or save it to a file.
117
+ - **URL Parser / Builder** — Paste a URL to see its scheme, host, port, path, query, fragment and credentials as an editable JSON object, tweak any part, and turn it back into a URL. Round-trips both ways, brackets IPv6 literals, and re-encodes query parameters for you. The cURL importer can send a request's URL straight here.
118
+ - **HTTP Header Analyzer** — Paste a request or response header block (from dev tools, `curl -i`, or a proxy log) and read back every field plus what is worth knowing about it: names sent more than once, `Set-Cookie` entries missing `Secure` / `HttpOnly` / `SameSite`, a wildcard CORS policy (and the wildcard-plus-credentials combination browsers reject outright), an HSTS `max-age` too short to survive a restart, CSP `unsafe-inline` / `unsafe-eval`, product banners, deprecated headers, and — for responses — the security headers that are absent. Headers carrying credentials are reported by name only; their values are never copied into the report. The Response Inspector hands its headers here in one click.
117
119
  - **Regex Tester** — Try a regular expression against sample text with `IGNORECASE` / `MULTILINE` / `DOTALL` / `VERBOSE` flags, and see every match with its offsets, numbered groups and named groups. Invalid patterns report a friendly error instead of crashing.
118
120
  - **HTTP Status Reference** — Search the full HTTP status code table (sourced from the standard library, so it stays current) by code prefix or keyword, with the reason phrase, description and status class for each.
119
121
  - **Text Diff** — Compare two pieces of text (for example an expected vs. actual API response) side by side and get a unified diff plus a one-line summary of how many lines were added or removed. Copy the diff, open it in an editor tab, or save it to a file.
120
122
  - **JSON Format** — Pretty-print or minify a JSON payload, with a clear validation error when the input is not valid JSON. Copy the result, open it in a new editor tab, or save it to a file.
121
- - **Response Inspector** — Paste a raw HTTP response and get a decoded summary in one step: the status code is looked up in the HTTP reference, headers are parsed, a JSON body is pretty-printed, and any JWTs anywhere in the text (for example an `Authorization: Bearer` header) are decoded with their timestamp claims shown in UTC. Ties the HTTP-status, JSON-format and JWT tools together, and can open a found status code or JWT directly in its dedicated tool tab, pre-filled.
123
+ - **Response Inspector** — Paste a raw HTTP response and get a decoded summary in one step: the status code is looked up in the HTTP reference, headers are parsed, a JSON body is pretty-printed, and any JWTs anywhere in the text (for example an `Authorization: Bearer` header) are decoded with their timestamp claims shown in UTC. Ties the HTTP-status, JSON-format and JWT tools together, and can open a found status code, JWT, or the whole header block directly in its dedicated tool tab, pre-filled.
122
124
  - **File Tree Context Menu** — Right-click any file or folder in the project tree to create files/folders, rename, delete, copy absolute or relative paths, or reveal the item in your platform file manager. Renaming or deleting a file that is currently open in an editor tab keeps the tab in sync.
123
125
  - **Package Manager** — Install automation modules and build tools directly from the IDE menu without leaving the editor.
124
126
  - **Integrated Documentation** — Quick access to documentation and GitHub pages for each automation module directly from the menu bar.
@@ -254,6 +256,8 @@ PyBreeze UI (PySide6)
254
256
  │ ├── Timestamp Converter (epoch ⇄ ISO-8601)
255
257
  │ ├── Hash Generator (SHA-256/512, SHA-1, MD5)
256
258
  │ ├── Query ⇄ JSON Converter
259
+ │ ├── URL Parser / Builder (URL ⇄ JSON parts)
260
+ │ ├── HTTP Header Analyzer (duplicates, cookie flags, security headers)
257
261
  │ ├── Regex Tester
258
262
  │ ├── HTTP Status Reference
259
263
  │ ├── Text Diff
@@ -76,16 +76,18 @@ PyBreeze is not just a code editor — it is a command center for the automation
76
76
  - Mermaid `flowchart` / `graph` import
77
77
  - Save/Open as `.diagram.json`, export to PNG or SVG
78
78
  - Undo/redo, align, distribute, grid, snap, and zoom controls
79
- - **cURL Import** — Paste a `curl` command copied from your browser's dev tools and generate a ready-to-run script for the target of your choice: **Python `requests`**, an **APITestka Python** snippet (`test_api_method_requests(...)`), an **APITestka JSON action** (`[["AT_test_api_method", {...}]]`) that `execute_files` runs directly, or a **LoadDensity** Locust load-test (`start_test(...)`). (These are the HTTP-oriented modules; a curl request has no meaningful mapping to the browser or desktop-GUI automation modules.) Parses the method, URL, headers, body, basic auth, `-G` query parameters, `-F` multipart form fields (file uploads become `files=open(...)`), the `--json` shortcut (which also sets the JSON `Content-Type`/`Accept`), and `-d @file` bodies (which become `open(...).read()`, while `--data-raw` stays literal) — all with multi-line `\` / `^` continuations. It knows the arity of curl's common flags, so value-taking options like `--max-time 30` or `-o out.json` never leak into the URL; it URL-encodes `--data-urlencode` values the way curl does; and it infers `POST` when a body or form is present and sends JSON bodies as JSON. Targets include Python `requests`, a ready-to-run **pytest test** (a named `test_...` function that sends the request and asserts the status), APITestka (Python and JSON action), and a LoadDensity load test. Pick one from the dropdown, then copy the result, **open it straight into a new editor tab**, or **save it to a `.py` / `.json` file** (the extension follows the chosen target). The parser is pure logic and never executes the command.
79
+ - **cURL Import** — Paste a `curl` command copied from your browser's dev tools and generate a ready-to-run script for the target of your choice: **Python `requests`**, an **APITestka Python** snippet (`test_api_method_requests(...)`), an **APITestka JSON action** (`[["AT_test_api_method", {...}]]`) that `execute_files` runs directly, or a **LoadDensity** Locust load-test (`start_test(...)`). (These are the HTTP-oriented modules; a curl request has no meaningful mapping to the browser or desktop-GUI automation modules.) Parses the method, URL, headers, body, basic auth, `-G` query parameters, `-F` multipart form fields (file uploads become `files=open(...)`), the `--json` shortcut (which also sets the JSON `Content-Type`/`Accept`), and `-d @file` bodies (which become `open(...).read()`, while `--data-raw` stays literal) — all with multi-line `\` / `^` continuations. It knows the arity of curl's common flags, so value-taking options like `--max-time 30` or `-o out.json` never leak into the URL; it URL-encodes `--data-urlencode` values the way curl does; and it infers `POST` when a body or form is present and sends JSON bodies as JSON. Targets include Python `requests`, a ready-to-run **pytest test** (a named `test_...` function that sends the request and asserts the status), APITestka (Python and JSON action), and a LoadDensity load test. Pick one from the dropdown, then copy the result, **open it straight into a new editor tab**, or **save it to a `.py` / `.json` file** (the extension follows the chosen target). A repeated `-H` is handled the way HTTP handles it — the values are combined into one header (with `; ` for cookies) rather than the last one silently winning, and names are matched case-insensitively so an explicit header always beats one implied by another flag. One click also **hands the parsed URL to the URL parser/builder**, query string and all. The parser is pure logic and never executes the command.
80
80
  - **JWT Decoder** — Paste a JSON Web Token and read its header and payload as pretty-printed JSON, with standard timestamp claims (`exp`, `iat`, `nbf`, `auth_time`) rendered as readable UTC times. Inspection only — the signature is never verified and the token is never trusted.
81
81
  - **Timestamp Converter** — Enter a Unix epoch value (seconds or milliseconds, auto-detected) or an ISO-8601 date-time (with `Z` or an offset) and get every representation back in UTC. Deterministic and independent of the local time zone.
82
82
  - **Hash Generator** — Compute SHA-256, SHA-512, SHA-1 and MD5 digests of any text at once. A general-purpose checksum tool (MD5/SHA-1 are provided for interoperability with `usedforsecurity=False`, never for security decisions).
83
83
  - **Query ⇄ JSON** — Convert an `application/x-www-form-urlencoded` query string to pretty JSON and back, URL-decoding and -encoding as needed. Repeated keys become JSON arrays and vice versa. Copy the result, open it in an editor tab, or save it to a file.
84
+ - **URL Parser / Builder** — Paste a URL to see its scheme, host, port, path, query, fragment and credentials as an editable JSON object, tweak any part, and turn it back into a URL. Round-trips both ways, brackets IPv6 literals, and re-encodes query parameters for you. The cURL importer can send a request's URL straight here.
85
+ - **HTTP Header Analyzer** — Paste a request or response header block (from dev tools, `curl -i`, or a proxy log) and read back every field plus what is worth knowing about it: names sent more than once, `Set-Cookie` entries missing `Secure` / `HttpOnly` / `SameSite`, a wildcard CORS policy (and the wildcard-plus-credentials combination browsers reject outright), an HSTS `max-age` too short to survive a restart, CSP `unsafe-inline` / `unsafe-eval`, product banners, deprecated headers, and — for responses — the security headers that are absent. Headers carrying credentials are reported by name only; their values are never copied into the report. The Response Inspector hands its headers here in one click.
84
86
  - **Regex Tester** — Try a regular expression against sample text with `IGNORECASE` / `MULTILINE` / `DOTALL` / `VERBOSE` flags, and see every match with its offsets, numbered groups and named groups. Invalid patterns report a friendly error instead of crashing.
85
87
  - **HTTP Status Reference** — Search the full HTTP status code table (sourced from the standard library, so it stays current) by code prefix or keyword, with the reason phrase, description and status class for each.
86
88
  - **Text Diff** — Compare two pieces of text (for example an expected vs. actual API response) side by side and get a unified diff plus a one-line summary of how many lines were added or removed. Copy the diff, open it in an editor tab, or save it to a file.
87
89
  - **JSON Format** — Pretty-print or minify a JSON payload, with a clear validation error when the input is not valid JSON. Copy the result, open it in a new editor tab, or save it to a file.
88
- - **Response Inspector** — Paste a raw HTTP response and get a decoded summary in one step: the status code is looked up in the HTTP reference, headers are parsed, a JSON body is pretty-printed, and any JWTs anywhere in the text (for example an `Authorization: Bearer` header) are decoded with their timestamp claims shown in UTC. Ties the HTTP-status, JSON-format and JWT tools together, and can open a found status code or JWT directly in its dedicated tool tab, pre-filled.
90
+ - **Response Inspector** — Paste a raw HTTP response and get a decoded summary in one step: the status code is looked up in the HTTP reference, headers are parsed, a JSON body is pretty-printed, and any JWTs anywhere in the text (for example an `Authorization: Bearer` header) are decoded with their timestamp claims shown in UTC. Ties the HTTP-status, JSON-format and JWT tools together, and can open a found status code, JWT, or the whole header block directly in its dedicated tool tab, pre-filled.
89
91
  - **File Tree Context Menu** — Right-click any file or folder in the project tree to create files/folders, rename, delete, copy absolute or relative paths, or reveal the item in your platform file manager. Renaming or deleting a file that is currently open in an editor tab keeps the tab in sync.
90
92
  - **Package Manager** — Install automation modules and build tools directly from the IDE menu without leaving the editor.
91
93
  - **Integrated Documentation** — Quick access to documentation and GitHub pages for each automation module directly from the menu bar.
@@ -221,6 +223,8 @@ PyBreeze UI (PySide6)
221
223
  │ ├── Timestamp Converter (epoch ⇄ ISO-8601)
222
224
  │ ├── Hash Generator (SHA-256/512, SHA-1, MD5)
223
225
  │ ├── Query ⇄ JSON Converter
226
+ │ ├── URL Parser / Builder (URL ⇄ JSON parts)
227
+ │ ├── HTTP Header Analyzer (duplicates, cookie flags, security headers)
224
228
  │ ├── Regex Tester
225
229
  │ ├── HTTP Status Reference
226
230
  │ ├── Text Diff
@@ -331,6 +331,7 @@ pybreeze_english_word_dict = {
331
331
  "curl_import_target_apitestka_python": "APITestka (Python)",
332
332
  "curl_import_target_apitestka_action": "APITestka (JSON action)",
333
333
  "curl_import_target_loaddensity_python": "LoadDensity (Python)",
334
+ "curl_import_open_url_button": "Open URL in parser / builder",
334
335
  # Shared output actions (copy / open in editor / save to file)
335
336
  "output_actions_copy": "Copy",
336
337
  "output_actions_open_editor": "Open in editor tab",
@@ -393,6 +394,20 @@ pybreeze_english_word_dict = {
393
394
  "query_json_output_label": "Result:",
394
395
  "query_json_error": "Could not convert: {error}",
395
396
  "query_json_empty_hint": "Enter a query string or a JSON object above.",
397
+ # URL Parser / Builder — Menu
398
+ "extend_tools_menu_url_builder_tab_action": "URL Parser / Builder Tab",
399
+ "extend_tools_menu_url_builder_tab_label": "URL Parser / Builder",
400
+ "extend_tools_menu_url_builder_dock_action": "URL Parser / Builder Dock",
401
+ "extend_tools_menu_url_builder_dock_title": "URL Parser / Builder",
402
+ # URL Parser / Builder — Widget
403
+ "url_builder_input_label": "A URL, or a JSON object of URL parts:",
404
+ "url_builder_input_placeholder":
405
+ "https://user@host:8080/path?a=1#frag or {\"scheme\": \"https\", \"host\": \"host\"}",
406
+ "url_builder_to_json_button": "URL → JSON",
407
+ "url_builder_to_url_button": "JSON → URL",
408
+ "url_builder_output_label": "Result:",
409
+ "url_builder_error": "Could not build URL: {error}",
410
+ "url_builder_empty_hint": "Enter a URL or a JSON object of URL parts above.",
396
411
  # Regex Tester — Menu
397
412
  "extend_tools_menu_regex_tab_action": "Regex Tester Tab",
398
413
  "extend_tools_menu_regex_tab_label": "Regex",
@@ -453,11 +468,66 @@ pybreeze_english_word_dict = {
453
468
  "response_output_label": "Analysis:",
454
469
  "response_open_jwt_button": "Open JWT in decoder",
455
470
  "response_open_status_button": "Open status in reference",
471
+ "response_open_headers_button": "Open headers in analyzer",
456
472
  "response_empty_hint": "Paste a response above, then click analyze.",
457
473
  "response_status_label": "== Status ==",
458
474
  "response_headers_label": "== Headers ==",
459
475
  "response_jwt_label": "== JWT(s) found ==",
460
476
  "response_body_label": "== Body ==",
477
+ # HTTP Header Analyzer — Menu
478
+ "extend_tools_menu_header_analyzer_tab_action": "HTTP Header Analyzer Tab",
479
+ "extend_tools_menu_header_analyzer_tab_label": "Header Analyzer",
480
+ "extend_tools_menu_header_analyzer_dock_action": "HTTP Header Analyzer Dock",
481
+ "extend_tools_menu_header_analyzer_dock_title": "Header Analyzer",
482
+ # HTTP Header Analyzer — Widget
483
+ "header_analyzer_input_label": "Paste request or response headers:",
484
+ "header_analyzer_input_placeholder":
485
+ "HTTP/1.1 200 OK\nContent-Type: text/html\nSet-Cookie: sid=abc; Path=/",
486
+ "header_analyzer_analyze_button": "Analyze headers",
487
+ "header_analyzer_output_label": "Analysis:",
488
+ "header_analyzer_headers_label": "== Headers ({count}) ==",
489
+ "header_analyzer_duplicates_label": "== Repeated names ==",
490
+ "header_analyzer_findings_label": "== Findings ==",
491
+ "header_analyzer_no_findings": "Nothing worth reporting.",
492
+ "header_analyzer_no_headers": "No header lines found in that text.",
493
+ "header_analyzer_empty_hint": "Paste a header block above, then click analyze.",
494
+ "header_analyzer_level_warning": "WARNING",
495
+ "header_analyzer_level_info": "INFO",
496
+ # HTTP Header Analyzer — Findings ({header} is the header, {detail} its value)
497
+ "header_finding_duplicate_header":
498
+ "{header}: sent {detail} times; the receiver joins the values into one.",
499
+ "header_finding_content_type_options_not_nosniff":
500
+ "{header}: '{detail}' has no effect, only 'nosniff' stops MIME sniffing.",
501
+ "header_finding_hsts_weak_max_age":
502
+ "{header}: max-age={detail} is short; 15552000 (180 days) is the usual minimum.",
503
+ "header_finding_csp_unsafe_directive":
504
+ "{header}: contains '{detail}', which re-allows what the policy should block.",
505
+ "header_finding_cors_wildcard_origin": "{header}: every origin is allowed (*).",
506
+ "header_finding_cors_wildcard_with_credentials":
507
+ "{header}: '*' with Access-Control-Allow-Credentials: true is rejected by browsers.",
508
+ "header_finding_cookie_not_secure":
509
+ "{header}: cookie '{detail}' has no Secure attribute, so it can travel over plain HTTP.",
510
+ "header_finding_cookie_not_httponly":
511
+ "{header}: cookie '{detail}' has no HttpOnly attribute, so scripts can read it.",
512
+ "header_finding_cookie_no_samesite":
513
+ "{header}: cookie '{detail}' has no SameSite attribute; browsers default it to Lax.",
514
+ "header_finding_content_type_no_charset":
515
+ "{header}: '{detail}' names no charset, so the client has to guess the encoding.",
516
+ "header_finding_server_banner": "{header}: '{detail}' reveals the software in use.",
517
+ "header_finding_deprecated_header":
518
+ "{header}: '{detail}' is deprecated and ignored by current browsers.",
519
+ "header_finding_sensitive_header":
520
+ "{header}: carries a credential; mask it before sharing this output.",
521
+ "header_finding_missing_hsts":
522
+ "{header}: not set, so a browser may fall back to plain HTTP.",
523
+ "header_finding_missing_csp":
524
+ "{header}: not set, so nothing limits where scripts may be loaded from.",
525
+ "header_finding_missing_content_type_options":
526
+ "{header}: not set, so a browser may MIME-sniff the response.",
527
+ "header_finding_missing_frame_options":
528
+ "{header}: not set; it (or CSP frame-ancestors) controls who may frame the page.",
529
+ "header_finding_missing_referrer_policy":
530
+ "{header}: not set, so full URLs may leak to other sites.",
461
531
  # Diagram Editor — Tools
462
532
  "diagram_editor_tool_select": "Select",
463
533
  "diagram_editor_tool_rect": "Rect",
@@ -309,6 +309,7 @@ pybreeze_traditional_chinese_word_dict = {
309
309
  "curl_import_target_apitestka_python": "APITestka(Python)",
310
310
  "curl_import_target_apitestka_action": "APITestka(JSON action)",
311
311
  "curl_import_target_loaddensity_python": "LoadDensity(Python)",
312
+ "curl_import_open_url_button": "在 URL 解析/組建器開啟網址",
312
313
  # 共用輸出動作(複製 / 開成分頁 / 存檔)
313
314
  "output_actions_copy": "複製",
314
315
  "output_actions_open_editor": "開成編輯器分頁",
@@ -371,6 +372,20 @@ pybreeze_traditional_chinese_word_dict = {
371
372
  "query_json_output_label": "結果:",
372
373
  "query_json_error": "無法轉換:{error}",
373
374
  "query_json_empty_hint": "請在上方輸入查詢字串或 JSON 物件。",
375
+ # URL 解析/組建器 — 選單
376
+ "extend_tools_menu_url_builder_tab_action": "URL 解析/組建器分頁",
377
+ "extend_tools_menu_url_builder_tab_label": "URL 解析/組建器",
378
+ "extend_tools_menu_url_builder_dock_action": "URL 解析/組建器停駐窗格",
379
+ "extend_tools_menu_url_builder_dock_title": "URL 解析/組建器",
380
+ # URL 解析/組建器 — 介面
381
+ "url_builder_input_label": "一個 URL,或描述 URL 各部分的 JSON 物件:",
382
+ "url_builder_input_placeholder":
383
+ "https://user@host:8080/path?a=1#frag 或 {\"scheme\": \"https\", \"host\": \"host\"}",
384
+ "url_builder_to_json_button": "URL → JSON",
385
+ "url_builder_to_url_button": "JSON → URL",
386
+ "url_builder_output_label": "結果:",
387
+ "url_builder_error": "無法組建 URL:{error}",
388
+ "url_builder_empty_hint": "請在上方輸入 URL 或描述 URL 各部分的 JSON 物件。",
374
389
  # 正規表示式測試器 — 選單
375
390
  "extend_tools_menu_regex_tab_action": "正規表示式測試器分頁",
376
391
  "extend_tools_menu_regex_tab_label": "Regex",
@@ -431,11 +446,66 @@ pybreeze_traditional_chinese_word_dict = {
431
446
  "response_output_label": "分析結果:",
432
447
  "response_open_jwt_button": "在解碼器開啟 JWT",
433
448
  "response_open_status_button": "在參考開啟狀態碼",
449
+ "response_open_headers_button": "在分析器開啟標頭",
434
450
  "response_empty_hint": "請先在上方貼上回應,再按分析。",
435
451
  "response_status_label": "== 狀態 Status ==",
436
452
  "response_headers_label": "== 標頭 Headers ==",
437
453
  "response_jwt_label": "== 找到的 JWT ==",
438
454
  "response_body_label": "== 內容 Body ==",
455
+ # HTTP 標頭分析器 — 選單
456
+ "extend_tools_menu_header_analyzer_tab_action": "HTTP 標頭分析器分頁",
457
+ "extend_tools_menu_header_analyzer_tab_label": "標頭分析器",
458
+ "extend_tools_menu_header_analyzer_dock_action": "HTTP 標頭分析器停駐窗格",
459
+ "extend_tools_menu_header_analyzer_dock_title": "標頭分析器",
460
+ # HTTP 標頭分析器 — 介面
461
+ "header_analyzer_input_label": "貼上請求或回應的標頭:",
462
+ "header_analyzer_input_placeholder":
463
+ "HTTP/1.1 200 OK\nContent-Type: text/html\nSet-Cookie: sid=abc; Path=/",
464
+ "header_analyzer_analyze_button": "分析標頭",
465
+ "header_analyzer_output_label": "分析結果:",
466
+ "header_analyzer_headers_label": "== 標頭({count})==",
467
+ "header_analyzer_duplicates_label": "== 重複出現的名稱 ==",
468
+ "header_analyzer_findings_label": "== 分析發現 ==",
469
+ "header_analyzer_no_findings": "沒有需要注意的項目。",
470
+ "header_analyzer_no_headers": "這段文字中找不到標頭。",
471
+ "header_analyzer_empty_hint": "請先在上方貼上標頭,再按分析。",
472
+ "header_analyzer_level_warning": "警告",
473
+ "header_analyzer_level_info": "資訊",
474
+ # HTTP 標頭分析器 — 發現({header} 為標頭名稱,{detail} 為其值)
475
+ "header_finding_duplicate_header":
476
+ "{header}:送出 {detail} 次,接收端會把這些值合併成一個。",
477
+ "header_finding_content_type_options_not_nosniff":
478
+ "{header}:'{detail}' 沒有作用,只有 'nosniff' 能阻止 MIME 探測。",
479
+ "header_finding_hsts_weak_max_age":
480
+ "{header}:max-age={detail} 太短,一般至少要 15552000(180 天)。",
481
+ "header_finding_csp_unsafe_directive":
482
+ "{header}:含有 '{detail}',等於把此政策原本要擋下的行為又放行了。",
483
+ "header_finding_cors_wildcard_origin": "{header}:允許任何來源(*)。",
484
+ "header_finding_cors_wildcard_with_credentials":
485
+ "{header}:'*' 搭配 Access-Control-Allow-Credentials: true,瀏覽器會直接拒絕。",
486
+ "header_finding_cookie_not_secure":
487
+ "{header}:cookie '{detail}' 沒有 Secure 屬性,可能以純 HTTP 傳送。",
488
+ "header_finding_cookie_not_httponly":
489
+ "{header}:cookie '{detail}' 沒有 HttpOnly 屬性,指令碼可以讀取。",
490
+ "header_finding_cookie_no_samesite":
491
+ "{header}:cookie '{detail}' 沒有 SameSite 屬性,瀏覽器會預設為 Lax。",
492
+ "header_finding_content_type_no_charset":
493
+ "{header}:'{detail}' 沒有指定 charset,用戶端只能自行猜測編碼。",
494
+ "header_finding_server_banner": "{header}:'{detail}' 洩漏了所使用的軟體。",
495
+ "header_finding_deprecated_header":
496
+ "{header}:'{detail}' 已淘汰,現行瀏覽器不再處理。",
497
+ "header_finding_sensitive_header":
498
+ "{header}:內含憑證,分享這份輸出前請先遮蔽。",
499
+ "header_finding_missing_hsts":
500
+ "{header}:未設定,瀏覽器可能退回純 HTTP。",
501
+ "header_finding_missing_csp":
502
+ "{header}:未設定,沒有任何規則限制指令碼的載入來源。",
503
+ "header_finding_missing_content_type_options":
504
+ "{header}:未設定,瀏覽器可能對回應做 MIME 探測。",
505
+ "header_finding_missing_frame_options":
506
+ "{header}:未設定;此標頭(或 CSP frame-ancestors)決定誰能將頁面內嵌成框架。",
507
+ "header_finding_missing_referrer_policy":
508
+ "{header}:未設定,完整網址可能外洩給其他網站。",
439
509
  # Diagram Editor — 工具
440
510
  "diagram_editor_tool_select": "選取",
441
511
  "diagram_editor_tool_rect": "矩形",
@@ -20,11 +20,13 @@ from pybreeze.pybreeze_ui.tools_gui.diff_gui import DiffGUI
20
20
  from pybreeze.pybreeze_ui.tools_gui.json_format_gui import JsonFormatGUI
21
21
  from pybreeze.pybreeze_ui.tools_gui.jwt_decoder_gui import JwtDecoderGUI
22
22
  from pybreeze.pybreeze_ui.tools_gui.hash_gui import HashGUI
23
+ from pybreeze.pybreeze_ui.tools_gui.header_analyzer_gui import HeaderAnalyzerGUI
23
24
  from pybreeze.pybreeze_ui.tools_gui.http_status_gui import HttpStatusGUI
24
25
  from pybreeze.pybreeze_ui.tools_gui.query_json_gui import QueryJsonGUI
25
26
  from pybreeze.pybreeze_ui.tools_gui.regex_gui import RegexGUI
26
27
  from pybreeze.pybreeze_ui.tools_gui.response_inspector_gui import ResponseInspectorGUI
27
28
  from pybreeze.pybreeze_ui.tools_gui.timestamp_gui import TimestampGUI
29
+ from pybreeze.pybreeze_ui.tools_gui.url_builder_gui import UrlBuilderGUI
28
30
 
29
31
  if TYPE_CHECKING:
30
32
  from pybreeze.pybreeze_ui.editor_main.main_ui import PyBreezeMainWindow
@@ -156,6 +158,17 @@ def build_tools_menu(ui_we_want_to_set: PyBreezeMainWindow):
156
158
  ))
157
159
  ui_we_want_to_set.tools_menu.addAction(ui_we_want_to_set.tools_query_json_action)
158
160
 
161
+ # URL Parser / Builder
162
+ ui_we_want_to_set.tools_url_builder_action = QAction(language_wrapper.language_word_dict.get(
163
+ "extend_tools_menu_url_builder_tab_action"
164
+ ))
165
+ ui_we_want_to_set.tools_url_builder_action.triggered.connect(lambda: ui_we_want_to_set.tab_widget.addTab(
166
+ UrlBuilderGUI(ui_we_want_to_set), language_wrapper.language_word_dict.get(
167
+ "extend_tools_menu_url_builder_tab_label"
168
+ )
169
+ ))
170
+ ui_we_want_to_set.tools_menu.addAction(ui_we_want_to_set.tools_url_builder_action)
171
+
159
172
  # Regex Tester
160
173
  ui_we_want_to_set.tools_regex_action = QAction(language_wrapper.language_word_dict.get(
161
174
  "extend_tools_menu_regex_tab_action"
@@ -200,6 +213,17 @@ def build_tools_menu(ui_we_want_to_set: PyBreezeMainWindow):
200
213
  ))
201
214
  ui_we_want_to_set.tools_menu.addAction(ui_we_want_to_set.tools_json_format_action)
202
215
 
216
+ # HTTP Header Analyzer
217
+ ui_we_want_to_set.tools_header_analyzer_action = QAction(language_wrapper.language_word_dict.get(
218
+ "extend_tools_menu_header_analyzer_tab_action"
219
+ ))
220
+ ui_we_want_to_set.tools_header_analyzer_action.triggered.connect(lambda: ui_we_want_to_set.tab_widget.addTab(
221
+ HeaderAnalyzerGUI(ui_we_want_to_set), language_wrapper.language_word_dict.get(
222
+ "extend_tools_menu_header_analyzer_tab_label"
223
+ )
224
+ ))
225
+ ui_we_want_to_set.tools_menu.addAction(ui_we_want_to_set.tools_header_analyzer_action)
226
+
203
227
  # Response Inspector
204
228
  ui_we_want_to_set.tools_response_action = QAction(language_wrapper.language_word_dict.get(
205
229
  "extend_tools_menu_response_tab_action"
@@ -296,6 +320,13 @@ def extend_dock_menu(ui_we_want_to_set: PyBreezeMainWindow):
296
320
  lambda: add_dock(ui_we_want_to_set, "QueryJson"))
297
321
  ui_we_want_to_set.dock_menu.addAction(ui_we_want_to_set.tools_query_json_dock_action)
298
322
 
323
+ # URL Parser / Builder Dock
324
+ ui_we_want_to_set.tools_url_builder_dock_action = QAction(language_wrapper.language_word_dict.get(
325
+ "extend_tools_menu_url_builder_dock_action"))
326
+ ui_we_want_to_set.tools_url_builder_dock_action.triggered.connect(
327
+ lambda: add_dock(ui_we_want_to_set, "UrlBuilder"))
328
+ ui_we_want_to_set.dock_menu.addAction(ui_we_want_to_set.tools_url_builder_dock_action)
329
+
299
330
  # Regex Tester Dock
300
331
  ui_we_want_to_set.tools_regex_dock_action = QAction(language_wrapper.language_word_dict.get(
301
332
  "extend_tools_menu_regex_dock_action"))
@@ -324,6 +355,13 @@ def extend_dock_menu(ui_we_want_to_set: PyBreezeMainWindow):
324
355
  lambda: add_dock(ui_we_want_to_set, "JsonFormat"))
325
356
  ui_we_want_to_set.dock_menu.addAction(ui_we_want_to_set.tools_json_format_dock_action)
326
357
 
358
+ # HTTP Header Analyzer Dock
359
+ ui_we_want_to_set.tools_header_analyzer_dock_action = QAction(language_wrapper.language_word_dict.get(
360
+ "extend_tools_menu_header_analyzer_dock_action"))
361
+ ui_we_want_to_set.tools_header_analyzer_dock_action.triggered.connect(
362
+ lambda: add_dock(ui_we_want_to_set, "HeaderAnalyzer"))
363
+ ui_we_want_to_set.dock_menu.addAction(ui_we_want_to_set.tools_header_analyzer_dock_action)
364
+
327
365
  # Response Inspector Dock
328
366
  ui_we_want_to_set.tools_response_dock_action = QAction(language_wrapper.language_word_dict.get(
329
367
  "extend_tools_menu_response_dock_action"))
@@ -352,11 +390,14 @@ _DOCK_WIDGETS: dict[str, tuple[str, Callable[[PyBreezeMainWindow], object]]] = {
352
390
  "Timestamp": ("extend_tools_menu_timestamp_dock_title", lambda win: TimestampGUI(win)),
353
391
  "Hash": ("extend_tools_menu_hash_dock_title", lambda win: HashGUI(win)),
354
392
  "QueryJson": ("extend_tools_menu_query_json_dock_title", lambda win: QueryJsonGUI(win)),
393
+ "UrlBuilder": ("extend_tools_menu_url_builder_dock_title", lambda win: UrlBuilderGUI(win)),
355
394
  "Regex": ("extend_tools_menu_regex_dock_title", lambda win: RegexGUI(win)),
356
395
  "HttpStatus": (
357
396
  "extend_tools_menu_http_status_dock_title", lambda win: HttpStatusGUI(main_window=win)),
358
397
  "Diff": ("extend_tools_menu_diff_dock_title", lambda win: DiffGUI(win)),
359
398
  "JsonFormat": ("extend_tools_menu_json_format_dock_title", lambda win: JsonFormatGUI(win)),
399
+ "HeaderAnalyzer": (
400
+ "extend_tools_menu_header_analyzer_dock_title", lambda win: HeaderAnalyzerGUI(win)),
360
401
  "ResponseInspector": (
361
402
  "extend_tools_menu_response_dock_title", lambda win: ResponseInspectorGUI(win)),
362
403
  }
@@ -4,7 +4,8 @@ Automation engineers routinely copy a request as ``curl`` from browser dev tools
4
4
  This widget parses that command and generates a runnable script for a chosen
5
5
  target (Python ``requests``, APITestka, LoadDensity), which can then be copied,
6
6
  opened straight into a new editor tab, or saved to a ``.py`` / ``.json`` file
7
- via the shared output actions.
7
+ via the shared output actions. The parsed URL can also be handed straight to the
8
+ URL parser/builder tool for further editing.
8
9
  """
9
10
  from __future__ import annotations
10
11
 
@@ -14,7 +15,9 @@ from PySide6.QtWidgets import (
14
15
  from je_editor import language_wrapper
15
16
 
16
17
  from pybreeze.pybreeze_ui.tools_gui.output_actions import OutputActions
17
- from pybreeze.utils.curl_import.curl_parser import parse_curl
18
+ from pybreeze.pybreeze_ui.tools_gui.tool_tabs import open_tool_tab
19
+ from pybreeze.pybreeze_ui.tools_gui.url_builder_gui import UrlBuilderGUI
20
+ from pybreeze.utils.curl_import.curl_parser import CurlRequest, parse_curl
18
21
  from pybreeze.utils.curl_import.script_templates import TEMPLATE_TARGETS, generate_template
19
22
  from pybreeze.utils.exception.exceptions import CurlParseException
20
23
  from pybreeze.utils.logging.logger import pybreeze_logger
@@ -31,8 +34,11 @@ class CurlImportGUI(QWidget):
31
34
  :param main_window: the window whose ``tab_widget`` "open in editor" uses
32
35
  """
33
36
  super().__init__()
37
+ self._main_window = main_window
34
38
  # The last successfully generated code (not an error or hint message).
35
39
  self._generated_code: str | None = None
40
+ # The request behind that code, so other tools can be handed its parts.
41
+ self._request: CurlRequest | None = None
36
42
  word = language_wrapper.language_word_dict
37
43
 
38
44
  self.input_label = QLabel(word.get("curl_import_input_label"))
@@ -54,6 +60,11 @@ class CurlImportGUI(QWidget):
54
60
  self.output_edit = QTextEdit()
55
61
  self.output_edit.setReadOnly(True)
56
62
 
63
+ # Cross-tool action: send the parsed URL to the URL parser/builder.
64
+ self.open_url_button = QPushButton(word.get("curl_import_open_url_button"))
65
+ self.open_url_button.clicked.connect(self.open_url_in_builder)
66
+ self.open_url_button.setEnabled(False)
67
+
57
68
  # Shared copy / open-in-editor / save actions. The extension and basename
58
69
  # follow the selected target; open/save are no-ops until a valid template.
59
70
  self.actions = OutputActions(
@@ -66,7 +77,7 @@ class CurlImportGUI(QWidget):
66
77
  for widget in (
67
78
  self.input_label, self.input_edit,
68
79
  self.target_label, self.target_select, self.convert_button,
69
- self.output_label, self.output_edit,
80
+ self.output_label, self.output_edit, self.open_url_button,
70
81
  ):
71
82
  layout.addWidget(widget)
72
83
  layout.addLayout(self.actions.button_row())
@@ -81,21 +92,43 @@ class CurlImportGUI(QWidget):
81
92
  if self.input_edit.toPlainText().strip():
82
93
  self.convert()
83
94
 
95
+ def _clear_result(self) -> None:
96
+ """Forget the last result, so the output and cross-tool actions go inactive."""
97
+ self._generated_code = None
98
+ self._request = None
99
+ self.open_url_button.setEnabled(False)
100
+
84
101
  def convert(self) -> None:
85
102
  """Parse the input command and show the template for the chosen target."""
86
103
  word = language_wrapper.language_word_dict
87
104
  command = self.input_edit.toPlainText().strip()
88
105
  if not command:
89
- self._generated_code = None
106
+ self._clear_result()
90
107
  self.output_edit.setPlainText(word.get("curl_import_empty_hint"))
91
108
  return
92
109
  try:
93
- code = generate_template(self.selected_target(), parse_curl(command))
110
+ request = parse_curl(command)
111
+ code = generate_template(self.selected_target(), request)
94
112
  except CurlParseException as error:
95
113
  pybreeze_logger.info("curl_import_gui.py convert failed: %r", error)
96
- self._generated_code = None
114
+ self._clear_result()
97
115
  self.output_edit.setPlainText(
98
116
  word.get("curl_import_error").format(error=str(error)))
99
117
  return
100
118
  self._generated_code = code
119
+ self._request = request
120
+ self.open_url_button.setEnabled(bool(request.url))
101
121
  self.output_edit.setPlainText(code)
122
+
123
+ def open_url_in_builder(self) -> QWidget | None:
124
+ """Open the parsed URL in the URL parser/builder tool, already parsed.
125
+
126
+ The full URL is handed over (query string included), so the builder shows
127
+ the address exactly as curl would send it.
128
+ """
129
+ if self._request is None or not self._request.url:
130
+ return None
131
+ return open_tool_tab(
132
+ self._main_window,
133
+ UrlBuilderGUI(main_window=self._main_window, initial_url=self._request.full_url),
134
+ "extend_tools_menu_url_builder_tab_label")
@@ -0,0 +1,108 @@
1
+ """A tool tab that analyses a pasted block of HTTP headers.
2
+
3
+ Paste request or response headers and read back every field, the names that were
4
+ sent more than once, and what is worth knowing about them — cookie flags, CORS
5
+ and HSTS policies, headers carrying credentials, and the response security
6
+ headers that are missing.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ from PySide6.QtWidgets import QLabel, QPushButton, QTextEdit, QVBoxLayout, QWidget
11
+ from je_editor import language_wrapper
12
+
13
+ from pybreeze.pybreeze_ui.tools_gui.output_actions import OutputActions
14
+ from pybreeze.utils.header_tools.header_analyzer import (
15
+ HeaderAnalysis, HeaderFinding, analyze_headers
16
+ )
17
+
18
+
19
+ def _finding_line(finding: HeaderFinding) -> str:
20
+ """Render one finding as a translated, level-prefixed line."""
21
+ word = language_wrapper.language_word_dict
22
+ level = word.get(f"header_analyzer_level_{finding.level}") or finding.level
23
+ message = word.get(f"header_finding_{finding.code}") or finding.code
24
+ return f"[{level}] {message.format(header=finding.header, detail=finding.detail)}"
25
+
26
+
27
+ def build_header_report(analysis: HeaderAnalysis) -> str:
28
+ """Render a header analysis into a readable, sectioned report.
29
+
30
+ :param analysis: the analysed header block
31
+ :return: display text, or the "no headers" message when nothing was found
32
+ """
33
+ word = language_wrapper.language_word_dict
34
+ if not analysis.fields:
35
+ return word.get("header_analyzer_no_headers")
36
+
37
+ lines = [word.get("header_analyzer_headers_label").format(count=len(analysis.fields))]
38
+ lines.extend(f"{header.name}: {header.value}" for header in analysis.fields)
39
+
40
+ if analysis.duplicates:
41
+ lines.extend(["", word.get("header_analyzer_duplicates_label")])
42
+ lines.extend(f"{name} × {count}" for name, count in analysis.duplicates.items())
43
+
44
+ lines.extend(["", word.get("header_analyzer_findings_label")])
45
+ if analysis.findings:
46
+ lines.extend(_finding_line(finding) for finding in analysis.findings)
47
+ else:
48
+ lines.append(word.get("header_analyzer_no_findings"))
49
+ return "\n".join(lines)
50
+
51
+
52
+ class HeaderAnalyzerGUI(QWidget):
53
+ """Paste HTTP headers and read what they say about the request or response."""
54
+
55
+ def __init__(self, main_window=None, initial_headers: str | None = None) -> None:
56
+ """
57
+ :param main_window: window whose ``tab_widget`` "open in editor" uses
58
+ :param initial_headers: a header block to pre-fill and analyse on open
59
+ """
60
+ super().__init__()
61
+ self._analysis: HeaderAnalysis | None = None
62
+ word = language_wrapper.language_word_dict
63
+
64
+ self.input_label = QLabel(word.get("header_analyzer_input_label"))
65
+ self.input_edit = QTextEdit()
66
+ self.input_edit.setPlaceholderText(word.get("header_analyzer_input_placeholder"))
67
+ self.input_edit.setAcceptRichText(False)
68
+
69
+ self.analyze_button = QPushButton(word.get("header_analyzer_analyze_button"))
70
+ self.analyze_button.clicked.connect(self.analyze)
71
+
72
+ self.output_label = QLabel(word.get("header_analyzer_output_label"))
73
+ self.output_edit = QTextEdit()
74
+ self.output_edit.setReadOnly(True)
75
+
76
+ self.actions = OutputActions(
77
+ self, self.output_edit, main_window=main_window,
78
+ basename="headers", extension="txt",
79
+ is_valid=lambda: self._analysis is not None)
80
+
81
+ layout = QVBoxLayout()
82
+ for widget in (
83
+ self.input_label, self.input_edit, self.analyze_button,
84
+ self.output_label, self.output_edit,
85
+ ):
86
+ layout.addWidget(widget)
87
+ layout.addLayout(self.actions.button_row())
88
+ self.setLayout(layout)
89
+
90
+ if initial_headers:
91
+ self.input_edit.setPlainText(initial_headers)
92
+ self.analyze()
93
+
94
+ def analyze(self) -> None:
95
+ """Analyse the pasted headers and show the report."""
96
+ word = language_wrapper.language_word_dict
97
+ text = self.input_edit.toPlainText().strip()
98
+ if not text:
99
+ self._analysis = None
100
+ self.output_edit.setPlainText(word.get("header_analyzer_empty_hint"))
101
+ return
102
+ analysis = analyze_headers(text)
103
+ if not analysis.fields:
104
+ self._analysis = None
105
+ self.output_edit.setPlainText(word.get("header_analyzer_no_headers"))
106
+ return
107
+ self._analysis = analysis
108
+ self.output_edit.setPlainText(build_header_report(analysis))