pycforge-sdk 0.6.3__py3-none-any.whl
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.
- pycforge_sdk/__init__.py +6 -0
- pycforge_sdk/__main__.py +3 -0
- pycforge_sdk/catalogue.py +287 -0
- pycforge_sdk/cli.py +114 -0
- pycforge_sdk/connection.py +136 -0
- pycforge_sdk/discovery.py +227 -0
- pycforge_sdk/editing.py +84 -0
- pycforge_sdk/engine_launch.py +45 -0
- pycforge_sdk/engine_worker.py +53 -0
- pycforge_sdk/gui/__init__.py +1 -0
- pycforge_sdk/gui/__main__.py +3 -0
- pycforge_sdk/gui/app.py +36 -0
- pycforge_sdk/gui/dialogs.py +310 -0
- pycforge_sdk/gui/editor.py +412 -0
- pycforge_sdk/gui/help/index.html +9 -0
- pycforge_sdk/gui/identity.py +139 -0
- pycforge_sdk/gui/jobs.py +146 -0
- pycforge_sdk/gui/reference.py +39 -0
- pycforge_sdk/gui/resources/sdk-mark.png +0 -0
- pycforge_sdk/gui/scanner.py +134 -0
- pycforge_sdk/gui/startup.py +118 -0
- pycforge_sdk/gui/visual/__init__.py +1 -0
- pycforge_sdk/gui/visual/action_contract.py +550 -0
- pycforge_sdk/gui/visual/icons.py +117 -0
- pycforge_sdk/gui/visual/qt_actions.py +501 -0
- pycforge_sdk/gui/visual/qt_branding.py +47 -0
- pycforge_sdk/gui/visual/qt_dialog_chrome.py +337 -0
- pycforge_sdk/gui/visual/qt_file_icons.py +130 -0
- pycforge_sdk/gui/visual/qt_icons.py +80 -0
- pycforge_sdk/gui/visual/qt_screen_geometry.py +166 -0
- pycforge_sdk/gui/visual/qt_title_controls.py +333 -0
- pycforge_sdk/gui/visual/qt_window_chrome.py +314 -0
- pycforge_sdk/gui/visual/qt_window_resize.py +93 -0
- pycforge_sdk/gui/visual/qt_workspace_widgets.py +448 -0
- pycforge_sdk/gui/visual/resources/icons/128/add-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/brand-mark.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/bundle-search.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/cancel.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/check.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/chevron-right.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/close.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/collapse-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/command-palette.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/convert.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/copy.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/cut.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/decision-trace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/details.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/diagnostics.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/duplicate-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/exit.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/expand-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/export.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/find.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/go-to-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/go-to-output.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/go-to-source.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/help.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/history.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/indent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/link-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/mappings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/move-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/move-line-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/move-line-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/move-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/next.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/open.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/outdent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/outline.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/paste.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/previous.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/primary-module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/redo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/remove-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/replace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/save-as.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/save.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/select-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/settings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/show-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/split-view.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/summary.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/telemetry.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/toggle-comment.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/toggle-fold.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/tools.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/undo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/128/whitespace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/add-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/brand-mark.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/bundle-search.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/cancel.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/check.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/chevron-right.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/close.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/collapse-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/command-palette.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/convert.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/copy.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/cut.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/decision-trace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/details.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/diagnostics.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/duplicate-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/exit.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/expand-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/export.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/find.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/go-to-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/go-to-output.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/go-to-source.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/help.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/history.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/indent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/link-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/mappings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/move-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/move-line-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/move-line-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/move-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/next.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/open.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/outdent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/outline.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/paste.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/previous.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/primary-module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/redo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/remove-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/replace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/save-as.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/save.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/select-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/settings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/show-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/split-view.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/summary.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/telemetry.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/toggle-comment.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/toggle-fold.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/tools.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/undo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/16/whitespace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/add-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/brand-mark.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/bundle-search.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/cancel.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/check.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/chevron-right.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/close.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/collapse-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/command-palette.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/convert.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/copy.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/cut.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/decision-trace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/details.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/diagnostics.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/duplicate-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/exit.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/expand-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/export.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/find.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/go-to-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/go-to-output.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/go-to-source.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/help.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/history.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/indent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/link-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/mappings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/move-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/move-line-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/move-line-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/move-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/next.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/open.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/outdent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/outline.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/paste.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/previous.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/primary-module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/redo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/remove-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/replace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/save-as.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/save.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/select-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/settings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/show-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/split-view.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/summary.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/telemetry.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/toggle-comment.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/toggle-fold.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/tools.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/undo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/20/whitespace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/add-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/brand-mark.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/bundle-search.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/cancel.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/check.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/chevron-right.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/close.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/collapse-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/command-palette.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/convert.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/copy.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/cut.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/decision-trace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/details.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/diagnostics.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/duplicate-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/exit.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/expand-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/export.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/find.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/go-to-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/go-to-output.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/go-to-source.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/help.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/history.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/indent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/link-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/mappings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/move-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/move-line-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/move-line-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/move-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/next.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/open.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/outdent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/outline.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/paste.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/previous.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/primary-module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/redo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/remove-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/replace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/save-as.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/save.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/select-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/settings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/show-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/split-view.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/summary.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/telemetry.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/toggle-comment.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/toggle-fold.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/tools.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/undo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/24/whitespace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/add-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/brand-mark.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/bundle-search.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/cancel.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/check.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/chevron-right.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/close.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/collapse-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/command-palette.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/convert.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/copy.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/cut.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/decision-trace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/details.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/diagnostics.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/duplicate-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/exit.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/expand-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/export.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/find.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/go-to-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/go-to-output.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/go-to-source.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/help.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/history.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/indent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/link-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/mappings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/move-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/move-line-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/move-line-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/move-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/next.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/open.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/outdent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/outline.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/paste.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/previous.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/primary-module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/redo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/remove-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/replace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/save-as.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/save.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/select-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/settings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/show-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/split-view.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/summary.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/telemetry.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/toggle-comment.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/toggle-fold.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/tools.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/undo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/256/whitespace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/add-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/brand-mark.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/bundle-search.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/cancel.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/check.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/chevron-right.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/close.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/collapse-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/command-palette.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/convert.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/copy.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/cut.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/decision-trace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/details.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/diagnostics.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/duplicate-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/exit.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/expand-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/export.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/find.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/go-to-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/go-to-output.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/go-to-source.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/help.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/history.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/indent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/link-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/mappings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/move-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/move-line-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/move-line-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/move-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/next.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/open.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/outdent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/outline.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/paste.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/previous.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/primary-module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/redo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/remove-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/replace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/save-as.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/save.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/select-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/settings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/show-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/split-view.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/summary.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/telemetry.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/toggle-comment.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/toggle-fold.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/tools.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/undo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/32/whitespace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/add-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/brand-mark.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/bundle-search.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/cancel.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/check.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/chevron-right.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/close.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/collapse-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/command-palette.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/convert.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/copy.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/cut.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/decision-trace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/details.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/diagnostics.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/duplicate-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/exit.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/expand-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/export.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/find.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/go-to-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/go-to-output.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/go-to-source.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/help.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/history.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/indent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/link-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/mappings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/move-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/move-line-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/move-line-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/move-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/next.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/open.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/outdent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/outline.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/paste.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/previous.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/primary-module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/redo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/remove-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/replace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/save-as.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/save.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/select-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/settings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/show-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/split-view.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/summary.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/telemetry.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/toggle-comment.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/toggle-fold.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/tools.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/undo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/48/whitespace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/add-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/brand-mark.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/bundle-search.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/cancel.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/check.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/chevron-right.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/close.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/collapse-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/command-palette.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/convert.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/copy.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/cut.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/decision-trace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/details.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/diagnostics.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/duplicate-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/exit.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/expand-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/export.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/find.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/go-to-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/go-to-output.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/go-to-source.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/help.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/history.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/indent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/link-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/mappings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/move-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/move-line-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/move-line-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/move-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/next.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/open.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/outdent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/outline.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/paste.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/previous.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/primary-module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/redo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/remove-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/replace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/save-as.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/save.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/select-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/settings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/show-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/split-view.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/summary.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/telemetry.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/toggle-comment.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/toggle-fold.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/tools.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/undo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/64/whitespace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/add-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/brand-mark.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/bundle-search.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/cancel.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/check.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/chevron-right.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/close.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/collapse-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/command-palette.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/convert.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/copy.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/cut.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/decision-trace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/details.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/diagnostics.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/duplicate-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/exit.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/expand-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/export.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/find.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/go-to-line.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/go-to-output.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/go-to-source.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/help.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/history.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/indent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/link-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/mappings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/move-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/move-line-down.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/move-line-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/move-up.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/next.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/open.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/outdent.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/outline.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/paste.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/previous.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/primary-module.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/redo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/remove-document.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/replace.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/save-as.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/save.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/select-all.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/settings.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/show-c.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/split-view.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/summary.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/telemetry.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/toggle-comment.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/toggle-fold.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/tools.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/undo.png +0 -0
- pycforge_sdk/gui/visual/resources/icons/96/whitespace.png +0 -0
- pycforge_sdk/gui/visual/theme.py +204 -0
- pycforge_sdk/gui/visual/theme_steel_stylesheet.py +901 -0
- pycforge_sdk/gui/visual/theme_stylesheet.py +597 -0
- pycforge_sdk/gui/visual/theme_workspace_stylesheet.py +169 -0
- pycforge_sdk/gui/visual/visual_tokens.py +146 -0
- pycforge_sdk/gui/widgets.py +68 -0
- pycforge_sdk/gui/window.py +559 -0
- pycforge_sdk/native.py +42 -0
- pycforge_sdk/package_metadata.py +21 -0
- pycforge_sdk/process.py +58 -0
- pycforge_sdk/project.py +143 -0
- pycforge_sdk/readiness.py +106 -0
- pycforge_sdk/results.py +45 -0
- pycforge_sdk/service.py +454 -0
- pycforge_sdk/workbench.py +88 -0
- pycforge_sdk-0.6.3.dist-info/METADATA +221 -0
- pycforge_sdk-0.6.3.dist-info/RECORD +559 -0
- pycforge_sdk-0.6.3.dist-info/WHEEL +5 -0
- pycforge_sdk-0.6.3.dist-info/entry_points.txt +5 -0
- pycforge_sdk-0.6.3.dist-info/licenses/LICENSE +674 -0
- pycforge_sdk-0.6.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
"""Desktop workflow coordinator; conversion and readiness live in the SDK."""
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import copy
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
from PySide6.QtCore import Qt, QSize, QTimer, QFileSystemWatcher, QSettings
|
|
7
|
+
from PySide6.QtGui import QAction, QKeySequence
|
|
8
|
+
from PySide6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
|
9
|
+
QLineEdit, QSplitter, QStackedWidget, QListWidget, QToolBar, QPlainTextEdit,
|
|
10
|
+
QDialog, QFrame, QLabel, QComboBox, QScrollArea)
|
|
11
|
+
from .. import __version__
|
|
12
|
+
from .visual.qt_window_chrome import install_frameless_window_chrome
|
|
13
|
+
from .visual.qt_icons import load_pycforge_icon
|
|
14
|
+
from .identity import SDK_QSS, sdk_icon, brand_panel, PathLabel
|
|
15
|
+
from .startup import StartupDialog
|
|
16
|
+
from .widgets import label, button, SafeBrowser, MenuIconStyle
|
|
17
|
+
from .dialogs import Dialog, Prompt, PathDialog, NewProjectDialog, SourceDialog
|
|
18
|
+
from .editor import ProjectEditor
|
|
19
|
+
from .scanner import ScannerPanel
|
|
20
|
+
from .reference import ReferencePanel
|
|
21
|
+
from .jobs import JobRunner
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class MainWindow(QMainWindow):
|
|
25
|
+
def __init__(self, *, engine_python=None, cache=None, compiler=None, timeout=30,
|
|
26
|
+
settings=None, parent=None):
|
|
27
|
+
super().__init__(parent)
|
|
28
|
+
self.settings = settings if settings is not None else QSettings("PyCForge", "SDK")
|
|
29
|
+
self.cache = str(cache or Path.home()/".pycforge-sdk"/"cache")
|
|
30
|
+
self.timeout = timeout
|
|
31
|
+
self.snapshot = None
|
|
32
|
+
self.dirty = self.external_change = False
|
|
33
|
+
self.revision = 0
|
|
34
|
+
self.ready = False
|
|
35
|
+
self.connection = "unavailable"
|
|
36
|
+
self.execution_available = False
|
|
37
|
+
self.templates = []; self.methods = []; self.operations = []
|
|
38
|
+
self.workbench = None; self.help_documents = []; self.help_engine = ""
|
|
39
|
+
self.close_pending = self.close_after_save = False
|
|
40
|
+
self.after_connect = None
|
|
41
|
+
self.explicit_engine = str(engine_python) if engine_python else None
|
|
42
|
+
self.startup_dialog = None
|
|
43
|
+
self.offline_pending = False
|
|
44
|
+
self.catalogue_offline = False
|
|
45
|
+
self.setWindowTitle(f"PyCForge SDK {__version__}")
|
|
46
|
+
self.setWindowIcon(sdk_icon())
|
|
47
|
+
self.setStyleSheet(SDK_QSS)
|
|
48
|
+
self.setMinimumSize(920, 640); self.resize(1320, 860)
|
|
49
|
+
self.runner = JobRunner(self)
|
|
50
|
+
self.runner.busy_changed.connect(self.busy_changed)
|
|
51
|
+
self.runner.finished.connect(self.finished)
|
|
52
|
+
self.runner.progress.connect(self.progress)
|
|
53
|
+
self.watcher = QFileSystemWatcher(self)
|
|
54
|
+
self.watcher.fileChanged.connect(self.disk_changed)
|
|
55
|
+
self._make_actions()
|
|
56
|
+
self._make_menus()
|
|
57
|
+
central = QWidget(); layout = QVBoxLayout(central); layout.setContentsMargins(10, 7, 10, 8)
|
|
58
|
+
self.link_panel = QFrame(); self.link_panel.setObjectName("SDKEngineLink")
|
|
59
|
+
link_layout = QHBoxLayout(self.link_panel); link_layout.setContentsMargins(13, 10, 12, 10)
|
|
60
|
+
mark = QLabel(); mark.setFixedSize(40, 40)
|
|
61
|
+
mark.setPixmap(sdk_icon().pixmap(mark.size(), self.devicePixelRatioF())); link_layout.addWidget(mark)
|
|
62
|
+
link_text = QVBoxLayout(); link_text.setSpacing(3)
|
|
63
|
+
tag = label("ENGINE CONNECTION"); tag.setObjectName("SDKConnectionTag"); link_text.addWidget(tag)
|
|
64
|
+
self.connection_label = label("Find your PyCForge installation")
|
|
65
|
+
self.connection_label.setObjectName("SDKConnectionTitle"); link_text.addWidget(self.connection_label)
|
|
66
|
+
self.connection_path = PathLabel(); link_text.addWidget(self.connection_path)
|
|
67
|
+
self.connection_summary = label("Conversion capabilities and reference come from PyCForge.", muted=True)
|
|
68
|
+
link_text.addWidget(self.connection_summary); link_layout.addLayout(link_text, 1)
|
|
69
|
+
self.locate_button = button("Locate PyCForge…", "open", self.browse_engine)
|
|
70
|
+
link_layout.addWidget(self.locate_button)
|
|
71
|
+
self.connect_button = button("Refresh", "history", self.refresh_engine,
|
|
72
|
+
"Reconnect to PyCForge and refresh its conversion capabilities and reference.")
|
|
73
|
+
self.connect_button.setProperty("sdkAccent", True); link_layout.addWidget(self.connect_button)
|
|
74
|
+
self.settings_button = button("Engine and tools", "settings", self.toggle_connection_settings)
|
|
75
|
+
link_layout.addWidget(self.settings_button); layout.addWidget(self.link_panel)
|
|
76
|
+
self.connection_settings = QWidget(); self.connection_settings.setObjectName("SDKConnectionSettings")
|
|
77
|
+
settings_layout = QVBoxLayout(self.connection_settings); settings_layout.setContentsMargins(0, 0, 0, 0)
|
|
78
|
+
engine_row = QHBoxLayout()
|
|
79
|
+
self.engine = QLineEdit(str(engine_python or self.settings.value("last_engine", self.settings.value("engine", sys.executable))))
|
|
80
|
+
self.engine.setAccessibleName("PyCForge Python interpreter")
|
|
81
|
+
self.engine.setToolTip("Choose the Python interpreter containing your PyCForge installation. The SDK uses it in a separate process.")
|
|
82
|
+
engine_row.addWidget(label("PyCForge Python")); engine_row.addWidget(self.engine, 1)
|
|
83
|
+
self.engine_browse = button("Locate…", "open", self.browse_engine)
|
|
84
|
+
self.search_button = button("Find installed", "diagnostics", self.begin_startup)
|
|
85
|
+
engine_row.addWidget(self.engine_browse); engine_row.addWidget(self.search_button)
|
|
86
|
+
self.current_python = button("This Python", "module", lambda: self.engine.setText(sys.executable),
|
|
87
|
+
"Use the SDK's Python interpreter if PyCForge is installed in this same environment; then Refresh.")
|
|
88
|
+
engine_row.addWidget(self.current_python)
|
|
89
|
+
settings_layout.addLayout(engine_row)
|
|
90
|
+
compiler_row = QHBoxLayout()
|
|
91
|
+
self.compiler = QLineEdit(str(compiler or self.settings.value("compiler", "gcc")))
|
|
92
|
+
self.compiler.setAccessibleName("Native verification compiler")
|
|
93
|
+
self.compiler.setToolTip("External compiler used only when you request native verification. The engine supplies its supported test profile.")
|
|
94
|
+
compiler_row.addWidget(label("Verify with")); compiler_row.addWidget(self.compiler, 1)
|
|
95
|
+
self.compiler_browse = button("Browse", "open", self.browse_compiler)
|
|
96
|
+
compiler_row.addWidget(self.compiler_browse)
|
|
97
|
+
settings_layout.addLayout(compiler_row)
|
|
98
|
+
layout.addWidget(self.connection_settings); self.connection_settings.hide()
|
|
99
|
+
self.identity = label("No extension project open", muted=True); layout.addWidget(self.identity)
|
|
100
|
+
split = QSplitter(); layout.addWidget(split, 1)
|
|
101
|
+
self.navigation = QListWidget(); self.navigation.setObjectName("DocumentList")
|
|
102
|
+
self.navigation.setAccessibleName("SDK workspace")
|
|
103
|
+
self.navigation.addItems(["Scanner", "Edit extension", "Engine reference", "Activity"])
|
|
104
|
+
for index in range(self.navigation.count()):
|
|
105
|
+
self.navigation.item(index).setSizeHint(QSize(170, 44))
|
|
106
|
+
self.navigation.item(index).setIcon(load_pycforge_icon(("diagnostics", "module", "help", "history")[index]))
|
|
107
|
+
self.navigation.setIconSize(QSize(24, 24))
|
|
108
|
+
sidebar = QWidget()
|
|
109
|
+
sidebar.setMinimumWidth(220); sidebar.setMaximumWidth(250)
|
|
110
|
+
sidebar_layout = QVBoxLayout(sidebar)
|
|
111
|
+
sidebar_layout.setContentsMargins(0, 0, 0, 0)
|
|
112
|
+
sidebar_layout.addWidget(brand_panel(sidebar))
|
|
113
|
+
sidebar_layout.addWidget(self.navigation, 1)
|
|
114
|
+
self.pages = QStackedWidget()
|
|
115
|
+
self.scanner = ScannerPanel(); self.editor = ProjectEditor(); self.reference = ReferencePanel()
|
|
116
|
+
self.activity = QPlainTextEdit(); self.activity.setReadOnly(True)
|
|
117
|
+
self.activity.setMaximumBlockCount(4000); self.activity.setAccessibleName("SDK activity and diagnostics")
|
|
118
|
+
self.scanner_scroll = QScrollArea(); self.scanner_scroll.setWidgetResizable(True)
|
|
119
|
+
self.scanner_scroll.setFrameShape(QFrame.Shape.NoFrame)
|
|
120
|
+
self.scanner.setMinimumHeight(max(580, 48 * self.font().pointSize()))
|
|
121
|
+
self.scanner_scroll.setWidget(self.scanner)
|
|
122
|
+
for page in (self.scanner_scroll, self.editor, self.reference, self.activity): self.pages.addWidget(page)
|
|
123
|
+
split.addWidget(sidebar); split.addWidget(self.pages); split.setSizes([220, 1100])
|
|
124
|
+
self.navigation.currentRowChanged.connect(self.pages.setCurrentIndex); self.navigation.setCurrentRow(0)
|
|
125
|
+
self.editor.changed.connect(self.edited)
|
|
126
|
+
self.editor.source_requested.connect(self.edit_source)
|
|
127
|
+
self.scanner.field_requested.connect(self.open_finding)
|
|
128
|
+
self.engine.textChanged.connect(self.engine_changed)
|
|
129
|
+
self.compiler.textChanged.connect(self.compiler_changed)
|
|
130
|
+
self.setCentralWidget(central)
|
|
131
|
+
self.chrome = install_frameless_window_chrome(self, self.menuBar())
|
|
132
|
+
self.statusBar().showMessage("Find PyCForge, then choose or open an extension project.")
|
|
133
|
+
self.update_actions()
|
|
134
|
+
|
|
135
|
+
def _action(self, key, text, icon, callback, shortcut=None, tip=""):
|
|
136
|
+
action = QAction(load_pycforge_icon(icon), text, self)
|
|
137
|
+
action.setIconVisibleInMenu(True)
|
|
138
|
+
action.setObjectName("sdkAction_" + key); action.setToolTip(tip or text)
|
|
139
|
+
if shortcut: action.setShortcut(QKeySequence(shortcut))
|
|
140
|
+
action.triggered.connect(callback); self.actions[key] = action
|
|
141
|
+
return action
|
|
142
|
+
|
|
143
|
+
def _make_actions(self):
|
|
144
|
+
self.actions = {}
|
|
145
|
+
self._action("new", "New", "add-document", self.new_project, "Ctrl+N")
|
|
146
|
+
self._action("open", "Open", "open", self.open_project, "Ctrl+O")
|
|
147
|
+
self._action("save", "Save", "save-python", self.save_project, "Ctrl+S")
|
|
148
|
+
self._action("reload", "Reload from disk", "history", self.reload_project)
|
|
149
|
+
self._action("scan", "Scan", "diagnostics", self.scan, "F5", "Check current packaging readiness without running fixture programs.")
|
|
150
|
+
self._action("verify", "Verify fixtures", "check", self.verify, "F6", "Explicitly convert, compile and run the complete saved fixture suite.")
|
|
151
|
+
self._action("build", "Package", "save-c", self.build, "Ctrl+B", "Package only the exact project approved by current verification.")
|
|
152
|
+
self._action("cancel", "Cancel", "cancel", self.cancel)
|
|
153
|
+
self._action("document", "Add missing Help fields", "help", self.prepare_documentation)
|
|
154
|
+
self._action("register", "Register a package in PyCForge…", "module", self.register)
|
|
155
|
+
self._action("help", "SDK Help", "help", self.help, "F1")
|
|
156
|
+
self._action("exit", "Exit", "exit", self.close, "Ctrl+Q")
|
|
157
|
+
bar = QToolBar("Extension actions", self); bar.setMovable(False)
|
|
158
|
+
bar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon); bar.setIconSize(QSize(24, 24))
|
|
159
|
+
for key in ("new", "open", "save", "scan", "verify", "build", "cancel"):
|
|
160
|
+
if key == "scan": bar.addSeparator()
|
|
161
|
+
bar.addAction(self.actions[key])
|
|
162
|
+
if key in ("scan", "verify", "build"):
|
|
163
|
+
bar.widgetForAction(self.actions[key]).setProperty("sdkAccent", True)
|
|
164
|
+
self.addToolBar(bar)
|
|
165
|
+
|
|
166
|
+
def _make_menus(self):
|
|
167
|
+
for title, keys in (("&File", ("new", "open", "save", "reload", "exit")),
|
|
168
|
+
("&Extension", ("scan", "verify", "build", "cancel")),
|
|
169
|
+
("&Tools", ("document", "register")), ("&Help", ("help",))):
|
|
170
|
+
menu = self.menuBar().addMenu(title)
|
|
171
|
+
menu.setObjectName("PyCForgeMenu")
|
|
172
|
+
menu.setStyle(MenuIconStyle(menu))
|
|
173
|
+
menu.setStyleSheet("QMenu::icon { width: 24px; height: 24px; } QMenu::item { min-height: 30px; }")
|
|
174
|
+
for key in keys: menu.addAction(self.actions[key])
|
|
175
|
+
self.menuBar().setNativeMenuBar(False)
|
|
176
|
+
|
|
177
|
+
def configuration(self):
|
|
178
|
+
return {"engine_python": self.engine.text().strip(), "cache": self.cache, "timeout": self.timeout}
|
|
179
|
+
|
|
180
|
+
def update_actions(self):
|
|
181
|
+
busy = self.runner.busy
|
|
182
|
+
project = self.snapshot is not None
|
|
183
|
+
saved = project and not self.dirty and not self.external_change
|
|
184
|
+
connected = self.connection == "connected" and self.execution_available
|
|
185
|
+
for key in ("open", "reload", "new", "register", "document", "save", "scan", "verify", "build"):
|
|
186
|
+
allowed = {"open": True, "reload": project, "new": bool(self.templates),
|
|
187
|
+
"register": connected, "document": saved and connected,
|
|
188
|
+
"save": project and self.dirty and not self.external_change,
|
|
189
|
+
"scan": saved, "verify": saved and connected,
|
|
190
|
+
"build": saved and connected and self.ready}[key]
|
|
191
|
+
self.actions[key].setEnabled(bool(allowed and not busy))
|
|
192
|
+
self.actions["cancel"].setEnabled(busy)
|
|
193
|
+
for widget in (self.engine, self.compiler, self.engine_browse, self.compiler_browse, self.connect_button,
|
|
194
|
+
self.current_python, self.locate_button, self.search_button):
|
|
195
|
+
widget.setEnabled(not busy)
|
|
196
|
+
self.editor.setEnabled(project and (not busy or self.runner.method in ("readiness", "verify")))
|
|
197
|
+
self.setWindowTitle((self.snapshot["document"]["declaration"].get("namespace", "Extension") +
|
|
198
|
+
(" •" if self.dirty else "") + " — " if project else "") + f"PyCForge SDK {__version__}")
|
|
199
|
+
|
|
200
|
+
def invalidate(self, message):
|
|
201
|
+
self.ready = False; self.revision += 1
|
|
202
|
+
self.scanner.invalidate(message); self.update_actions()
|
|
203
|
+
|
|
204
|
+
def edited(self):
|
|
205
|
+
self.dirty = True
|
|
206
|
+
self.invalidate("Unsaved edits. Save the project, then scan and verify its new contents.")
|
|
207
|
+
|
|
208
|
+
def engine_changed(self):
|
|
209
|
+
self.connection = "unavailable"
|
|
210
|
+
self.execution_available = False
|
|
211
|
+
self.templates = []; self.methods = []; self.operations = []
|
|
212
|
+
self.connection_label.setText("Engine selection changed. Connect to refresh the reference.")
|
|
213
|
+
self.connection_path.setText(self.engine.text())
|
|
214
|
+
self.connection_summary.setText("Refresh to check this installation and load its capabilities.")
|
|
215
|
+
self.locate_button.show()
|
|
216
|
+
self.reference.state.setText("Previous engine reference — connect to refresh. Execution approval cleared.")
|
|
217
|
+
self.invalidate("Engine selection changed. Connect, then scan the saved project.")
|
|
218
|
+
|
|
219
|
+
def compiler_changed(self):
|
|
220
|
+
self.invalidate("Compiler selection changed. Scan to check whether its identity matches verification.")
|
|
221
|
+
|
|
222
|
+
def browse_engine(self):
|
|
223
|
+
path = PathDialog.choose(self.startup_dialog or self, "Locate PyCForge", initial=self.engine.text(), mode="engine")
|
|
224
|
+
if path:
|
|
225
|
+
self.begin_startup(locations=[path])
|
|
226
|
+
|
|
227
|
+
def toggle_connection_settings(self):
|
|
228
|
+
self.connection_settings.setVisible(not self.connection_settings.isVisible())
|
|
229
|
+
|
|
230
|
+
def refresh_engine(self):
|
|
231
|
+
if self.connection == "connected" or self.engine.text().strip():
|
|
232
|
+
self.connect_engine()
|
|
233
|
+
else:
|
|
234
|
+
self.begin_startup()
|
|
235
|
+
|
|
236
|
+
def begin_startup(self, _checked=False, *, locations=None):
|
|
237
|
+
if self.runner.busy:
|
|
238
|
+
return
|
|
239
|
+
self.offline_pending = False
|
|
240
|
+
if self.startup_dialog is None:
|
|
241
|
+
self.startup_dialog = StartupDialog(self)
|
|
242
|
+
self.startup_dialog.offline_requested.connect(self.continue_offline)
|
|
243
|
+
self.startup_dialog.locate_requested.connect(self.browse_engine)
|
|
244
|
+
self.startup_dialog.retry_requested.connect(self.begin_startup)
|
|
245
|
+
self.startup_dialog.engine_selected.connect(self.select_discovered_engine)
|
|
246
|
+
self.startup_dialog.search_started(); self.startup_dialog.show()
|
|
247
|
+
self.ready = False
|
|
248
|
+
preferred = None
|
|
249
|
+
if locations is None:
|
|
250
|
+
if self.explicit_engine:
|
|
251
|
+
locations = [self.explicit_engine]
|
|
252
|
+
self.explicit_engine = None
|
|
253
|
+
else:
|
|
254
|
+
preferred = self.settings.value("last_engine", self.settings.value("engine", None))
|
|
255
|
+
self.start("discover", kwargs={"preferred": preferred, "locations": locations,
|
|
256
|
+
"timeout": min(self.timeout, 3), "search_timeout": min(self.timeout, 20)})
|
|
257
|
+
|
|
258
|
+
def select_discovered_engine(self, path):
|
|
259
|
+
if self.close_pending or self.offline_pending:
|
|
260
|
+
return
|
|
261
|
+
self.engine.setText(path)
|
|
262
|
+
if self.startup_dialog:
|
|
263
|
+
self.startup_dialog.connecting(path)
|
|
264
|
+
self.connect_engine()
|
|
265
|
+
|
|
266
|
+
def continue_offline(self):
|
|
267
|
+
self.offline_pending = True
|
|
268
|
+
if self.runner.busy:
|
|
269
|
+
self.runner.cancel()
|
|
270
|
+
if self.startup_dialog:
|
|
271
|
+
self.startup_dialog.status.setText("Stopping the connection search…")
|
|
272
|
+
self.startup_dialog.offline.setEnabled(False)
|
|
273
|
+
else:
|
|
274
|
+
self._load_offline()
|
|
275
|
+
|
|
276
|
+
def _load_offline(self):
|
|
277
|
+
self.offline_pending = False
|
|
278
|
+
self.catalogue_offline = True
|
|
279
|
+
self.start("catalogue", kwargs={"offline": True})
|
|
280
|
+
|
|
281
|
+
def _reveal_workspace(self):
|
|
282
|
+
self.show()
|
|
283
|
+
if self.startup_dialog:
|
|
284
|
+
dialog, self.startup_dialog = self.startup_dialog, None
|
|
285
|
+
dialog.accept(); dialog.deleteLater()
|
|
286
|
+
|
|
287
|
+
def browse_compiler(self):
|
|
288
|
+
path = PathDialog.choose(self, "Choose a native verification compiler", initial=self.compiler.text())
|
|
289
|
+
if path: self.compiler.setText(path)
|
|
290
|
+
|
|
291
|
+
def connect_engine(self):
|
|
292
|
+
self.ready = False
|
|
293
|
+
self.catalogue_offline = False
|
|
294
|
+
self.start("catalogue")
|
|
295
|
+
|
|
296
|
+
def start(self, method, args=(), kwargs=None):
|
|
297
|
+
if self.runner.busy: return False
|
|
298
|
+
if method in ("save_project", "prepare_documentation") and self.watcher.files():
|
|
299
|
+
self.watcher.removePaths(self.watcher.files())
|
|
300
|
+
if method in ("readiness", "verify", "build"):
|
|
301
|
+
self.ready = False; self.navigation.setCurrentRow(0)
|
|
302
|
+
self.scanner.running({"readiness": "Scanning extension…", "verify": "Verifying fixtures…", "build": "Checking and packaging…"}[method])
|
|
303
|
+
self.statusBar().showMessage("Working: " + method.replace("_", " "))
|
|
304
|
+
return self.runner.start(self.configuration(), method, args, kwargs, revision=self.revision)
|
|
305
|
+
|
|
306
|
+
def allow_discard(self):
|
|
307
|
+
if not self.dirty: return True
|
|
308
|
+
return Prompt.ask(self, "Unsaved project", "Discard your unsaved project edits and continue?",
|
|
309
|
+
[("discard", "Discard edits"), ("cancel", "Keep editing")]) == "discard"
|
|
310
|
+
|
|
311
|
+
def new_project(self):
|
|
312
|
+
if not self.allow_discard(): return
|
|
313
|
+
dlg = NewProjectDialog(self.templates, self)
|
|
314
|
+
if dlg.exec() == QDialog.DialogCode.Accepted:
|
|
315
|
+
self.start("create_project", (dlg.directory.text(),), {"author": dlg.author.text(), "template": dlg.template.currentData()})
|
|
316
|
+
|
|
317
|
+
def open_project(self, path=None):
|
|
318
|
+
if not self.allow_discard(): return
|
|
319
|
+
path = path if isinstance(path, str) else PathDialog.choose(self, "Open extension project", mode="directory",
|
|
320
|
+
description="Select the SDK extension folder containing project.json.")
|
|
321
|
+
if path: self.start("open_project", (path,))
|
|
322
|
+
|
|
323
|
+
def reload_project(self):
|
|
324
|
+
if self.snapshot and self.allow_discard(): self.start("open_project", (self.snapshot["directory"],))
|
|
325
|
+
|
|
326
|
+
def load_snapshot(self, data):
|
|
327
|
+
self.snapshot = data; self.dirty = self.external_change = False
|
|
328
|
+
self.editor.directory = data["directory"]
|
|
329
|
+
self.editor.expected_sha256 = data["project_sha256"]
|
|
330
|
+
self.editor.configuration = self.configuration()
|
|
331
|
+
self.editor.load(data["document"], methods=self.methods, operations=self.operations, workbench=self.workbench)
|
|
332
|
+
self.identity.setText(data["directory"])
|
|
333
|
+
self.rewatch()
|
|
334
|
+
self.invalidate("Saved project loaded. Run Scan to check what is ready for verification or packaging.")
|
|
335
|
+
|
|
336
|
+
def rewatch(self):
|
|
337
|
+
if self.watcher.files(): self.watcher.removePaths(self.watcher.files())
|
|
338
|
+
if self.snapshot:
|
|
339
|
+
root = Path(self.snapshot["directory"])
|
|
340
|
+
paths = [str(root/"project.json"), *[str(root/name) for name in self.snapshot["sources"]]]
|
|
341
|
+
paths.append(str(root/".pycforge-sdk/verification.json"))
|
|
342
|
+
self.watcher.addPaths([p for p in paths if Path(p).is_file()])
|
|
343
|
+
|
|
344
|
+
def disk_changed(self, path):
|
|
345
|
+
if path.endswith("/.pycforge-sdk/verification.json") or path.endswith("\\.pycforge-sdk\\verification.json"):
|
|
346
|
+
if not (self.runner.busy and self.runner.method == "verify"):
|
|
347
|
+
self.invalidate("Verification evidence changed. Run Scan to check it again.")
|
|
348
|
+
QTimer.singleShot(0, self.rewatch)
|
|
349
|
+
return
|
|
350
|
+
if self.runner.busy and self.runner.method in ("save_project", "save_source", "prepare_documentation"):
|
|
351
|
+
return
|
|
352
|
+
self.external_change = True
|
|
353
|
+
self.invalidate("A project file changed outside this editor. Reload from disk before scanning or saving.")
|
|
354
|
+
QTimer.singleShot(0, self.rewatch)
|
|
355
|
+
|
|
356
|
+
def save_project(self):
|
|
357
|
+
if self.snapshot:
|
|
358
|
+
self.start("save_project", (self.snapshot["directory"], copy.deepcopy(self.editor.draft)),
|
|
359
|
+
{"expected_sha256": self.snapshot["project_sha256"]})
|
|
360
|
+
|
|
361
|
+
def scan(self):
|
|
362
|
+
if self.snapshot and not self.dirty and not self.external_change:
|
|
363
|
+
self.start("readiness", (self.snapshot["directory"],), {"compiler": self.compiler.text().strip()})
|
|
364
|
+
|
|
365
|
+
def verify(self):
|
|
366
|
+
if self.snapshot and not self.dirty and not self.external_change:
|
|
367
|
+
self.start("verify", (self.snapshot["directory"],), {"compiler": self.compiler.text().strip()})
|
|
368
|
+
|
|
369
|
+
def build(self):
|
|
370
|
+
if not self.ready or not self.snapshot or self.dirty or self.external_change: return
|
|
371
|
+
namespace = self.snapshot["document"]["declaration"].get("namespace", "extension")
|
|
372
|
+
path = PathDialog.choose(self, "Save verified conversion package", mode="save",
|
|
373
|
+
suffix=".pcfplugin",
|
|
374
|
+
initial=str(Path(self.snapshot["directory"]).parent/(namespace+".pcfplugin")))
|
|
375
|
+
if not path: return
|
|
376
|
+
if Path(path).exists() and Prompt.ask(self, "Replace package", "Replace the existing package after the evidence checks pass?",
|
|
377
|
+
[("replace", "Replace"), ("cancel", "Cancel")]) != "replace": return
|
|
378
|
+
self.start("build", (self.snapshot["directory"], path), {"compiler": self.compiler.text().strip()})
|
|
379
|
+
|
|
380
|
+
def prepare_documentation(self):
|
|
381
|
+
if self.snapshot:
|
|
382
|
+
self.start("prepare_documentation", (self.snapshot["directory"],))
|
|
383
|
+
|
|
384
|
+
def edit_source(self, filename):
|
|
385
|
+
if self.dirty or self.external_change:
|
|
386
|
+
self.statusBar().showMessage("Save or reload the project before editing a fixture source."); return
|
|
387
|
+
if self.runner.busy: return
|
|
388
|
+
dlg = SourceDialog(self.snapshot, filename, self.configuration(), self)
|
|
389
|
+
# Its explicit one-file save owns the only mutation while the modal
|
|
390
|
+
# dialog is open; re-arm watchers after loading the resulting snapshot.
|
|
391
|
+
self.watcher.blockSignals(True)
|
|
392
|
+
try: dlg.exec()
|
|
393
|
+
finally: self.watcher.blockSignals(False)
|
|
394
|
+
if dlg.saved_snapshot: self.load_snapshot(dlg.saved_snapshot)
|
|
395
|
+
else:
|
|
396
|
+
# Re-read to detect external changes while the dialog was open.
|
|
397
|
+
self.start("open_project", (self.snapshot["directory"],))
|
|
398
|
+
|
|
399
|
+
def register(self):
|
|
400
|
+
path = PathDialog.choose(self, "Register a conversion package", suffix=".pcfplugin")
|
|
401
|
+
if not path: return
|
|
402
|
+
if Prompt.ask(self, "Register in PyCForge", "Add this package to the selected PyCForge installation's import registry? This is separate from packaging and does not publish a release.\n\n" + path,
|
|
403
|
+
[("register", "Register package"), ("cancel", "Cancel")]) == "register":
|
|
404
|
+
self.start("register", (path,))
|
|
405
|
+
|
|
406
|
+
def open_finding(self, path):
|
|
407
|
+
if self.editor.focus_path(path): self.navigation.setCurrentRow(1)
|
|
408
|
+
else: self.statusBar().showMessage("Field " + path + ": review the project data or add missing Help fields.")
|
|
409
|
+
|
|
410
|
+
def busy_changed(self, busy):
|
|
411
|
+
self.update_actions()
|
|
412
|
+
|
|
413
|
+
def progress(self, event):
|
|
414
|
+
if self.startup_dialog and event.get("phase") == "discovery":
|
|
415
|
+
self.startup_dialog.update_progress(event)
|
|
416
|
+
self.scanner.update_progress(event)
|
|
417
|
+
self.statusBar().showMessage(event.get("name", event.get("phase", "Working")))
|
|
418
|
+
|
|
419
|
+
def cancel(self):
|
|
420
|
+
self.runner.cancel(); self.ready = False
|
|
421
|
+
self.statusBar().showMessage("Canceling; waiting for the supervised operation to finish.")
|
|
422
|
+
|
|
423
|
+
def finished(self, method, result, revision):
|
|
424
|
+
self.activity.appendPlainText(method + " — " + result["status"])
|
|
425
|
+
if result["diagnostics"]: self.activity.appendPlainText(json.dumps(result["diagnostics"], indent=2))
|
|
426
|
+
data = result["data"]; success = result["status"] == "succeeded"
|
|
427
|
+
self.statusBar().showMessage(method.replace("_", " ").title() + ": " + result["status"])
|
|
428
|
+
if method in ("discover", "catalogue") and self.offline_pending and not self.close_pending:
|
|
429
|
+
self._load_offline()
|
|
430
|
+
return
|
|
431
|
+
if method == "discover":
|
|
432
|
+
self.activity.appendPlainText(json.dumps(data, indent=2))
|
|
433
|
+
if not self.close_pending:
|
|
434
|
+
engines = data.get("engines", [])
|
|
435
|
+
if len(engines) == 1:
|
|
436
|
+
self.select_discovered_engine(engines[0]["engine_python"])
|
|
437
|
+
elif engines and self.startup_dialog:
|
|
438
|
+
self.startup_dialog.show_choices(engines, limited=data.get("limited", False))
|
|
439
|
+
elif self.startup_dialog:
|
|
440
|
+
message = (result["diagnostics"][0]["message"] if result["diagnostics"] else
|
|
441
|
+
"No working installation was found in the checked locations.")
|
|
442
|
+
if data.get("limited"):
|
|
443
|
+
message += " The search reached its limit."
|
|
444
|
+
self.startup_dialog.failed(message)
|
|
445
|
+
elif method == "catalogue":
|
|
446
|
+
connection = data.get("connection", {})
|
|
447
|
+
self.connection = connection.get("state", "unavailable")
|
|
448
|
+
self.execution_available = connection.get("execution_available") is True
|
|
449
|
+
identity = connection.get("engine") or {}
|
|
450
|
+
self.connection_label.setText("PyCForge " + identity.get("engine_version", "") + " · " + self.connection)
|
|
451
|
+
self.connection_path.setText(self.engine.text() if self.connection == "connected" else "Cached reference only" if self.connection == "offline" else "No live engine connection")
|
|
452
|
+
if self.connection == "connected" and not self.execution_available:
|
|
453
|
+
self.connection_label.setText(self.connection_label.text() + " · authoring unavailable")
|
|
454
|
+
self.templates, self.methods, self.operations = data.get("templates", []), data.get("methods", []), data.get("array_operations", [])
|
|
455
|
+
self.workbench, self.help_documents = data.get("workbench"), data.get("documents", [])
|
|
456
|
+
self.help_engine = identity.get("engine_version", "")
|
|
457
|
+
imports = f"{len(self.workbench['imports'])} imports · " if self.workbench else ""
|
|
458
|
+
self.connection_summary.setText((imports + f"{len(self.templates)} starters · {len(self.methods)} API entries"
|
|
459
|
+
if self.connection == "connected" else "Local projects and cached reference remain available. Connect to use engine operations."))
|
|
460
|
+
self.locate_button.setVisible(self.connection != "connected")
|
|
461
|
+
if self.connection == "connected":
|
|
462
|
+
# Store only a validated live selection, immediately after success.
|
|
463
|
+
self.settings.setValue("last_engine", self.engine.text())
|
|
464
|
+
self.settings.setValue("engine", self.engine.text()); self.settings.sync()
|
|
465
|
+
self.reference.load(self.methods, self.connection, data.get("limits", []))
|
|
466
|
+
if self.snapshot:
|
|
467
|
+
self.editor.load(self.editor.draft, methods=self.methods, operations=self.operations, workbench=self.workbench)
|
|
468
|
+
self.editor.configuration = self.configuration()
|
|
469
|
+
self.ready = False; self.revision += 1
|
|
470
|
+
reveal = self.connection == "connected" or self.catalogue_offline
|
|
471
|
+
if self.startup_dialog and not self.close_pending:
|
|
472
|
+
if reveal:
|
|
473
|
+
self._reveal_workspace()
|
|
474
|
+
else:
|
|
475
|
+
self.startup_dialog.failed(connection.get("problem") or "The installation could not be connected.")
|
|
476
|
+
if self.after_connect and (reveal or self.startup_dialog is None) and not self.close_pending:
|
|
477
|
+
path = self.after_connect; self.after_connect = None
|
|
478
|
+
self.start("open_project", (path,))
|
|
479
|
+
elif method in ("open_project", "save_project") and success:
|
|
480
|
+
self.load_snapshot(data)
|
|
481
|
+
if method == "save_project" and self.close_after_save:
|
|
482
|
+
self.close_after_save = False; QTimer.singleShot(0, self.close)
|
|
483
|
+
elif method == "create_project" and success:
|
|
484
|
+
self.start("open_project", (data["directory"],))
|
|
485
|
+
elif method == "prepare_documentation" and success:
|
|
486
|
+
self.start("open_project", (self.snapshot["directory"],))
|
|
487
|
+
elif method in ("readiness", "verify", "build"):
|
|
488
|
+
returned_hash = data.get("readiness", data.get("report", data)).get("project_sha256")
|
|
489
|
+
if returned_hash and self.snapshot and returned_hash != self.snapshot["project_sha256"]:
|
|
490
|
+
self.external_change = True
|
|
491
|
+
if revision != self.revision or self.dirty or self.external_change:
|
|
492
|
+
self.ready = False
|
|
493
|
+
self.scanner.invalidate("Project or selection changed during work. This result cannot approve the current editor contents.")
|
|
494
|
+
elif method == "readiness" and "readiness" in data:
|
|
495
|
+
self.scanner.show_readiness(data["readiness"])
|
|
496
|
+
self.ready = success and data["readiness"].get("ready") is True
|
|
497
|
+
elif method == "verify":
|
|
498
|
+
if "report" in data: self.scanner.show_report(data["report"])
|
|
499
|
+
if success and not self.close_pending: self.scan()
|
|
500
|
+
else:
|
|
501
|
+
self.scanner.verdict.setText("Verification did not pass")
|
|
502
|
+
self.scanner.explanation.setText("Review the fixture results and Activity. Correct the problem, then verify again.")
|
|
503
|
+
self.scanner.progress.setRange(0, 1); self.scanner.progress.setValue(0)
|
|
504
|
+
elif method == "build" and success:
|
|
505
|
+
self.scanner.verdict.setText("Package created")
|
|
506
|
+
self.scanner.explanation.setText(data["package"] + "\nRegistration is a separate action in Tools.")
|
|
507
|
+
self.scanner.progress.setRange(0, 1); self.scanner.progress.setValue(1)
|
|
508
|
+
self.activity.appendPlainText(json.dumps(data, indent=2))
|
|
509
|
+
self.scanner.evidence.setPlainText(json.dumps(data, indent=2))
|
|
510
|
+
self.ready = True
|
|
511
|
+
else:
|
|
512
|
+
self.scanner.invalidate("Operation did not complete. Review Activity for the reason.")
|
|
513
|
+
elif method == "register":
|
|
514
|
+
self.activity.appendPlainText(json.dumps(data, indent=2)); self.navigation.setCurrentRow(3)
|
|
515
|
+
if not success and method == "save_project": self.close_after_save = False
|
|
516
|
+
if method in ("save_project", "prepare_documentation", "verify"): self.rewatch()
|
|
517
|
+
if not success and result["diagnostics"]:
|
|
518
|
+
self.statusBar().showMessage(result["diagnostics"][0]["message"])
|
|
519
|
+
self.update_actions()
|
|
520
|
+
if self.close_pending and not self.runner.busy:
|
|
521
|
+
self.close_pending = False; QTimer.singleShot(0, self.close)
|
|
522
|
+
|
|
523
|
+
def help(self):
|
|
524
|
+
dlg = Dialog("PyCForge SDK Help", self)
|
|
525
|
+
search = QLineEdit(); search.setPlaceholderText("Find in this guide…"); search.setAccessibleName("Find in SDK Help")
|
|
526
|
+
browser = SafeBrowser(); browser.setStyleSheet("QScrollBar:vertical { width: 28px; }")
|
|
527
|
+
documents = [{"title":"Getting started", "html":(Path(__file__).parent/"help/index.html").read_text(encoding="utf-8")}]
|
|
528
|
+
documents.extend(self.help_documents)
|
|
529
|
+
choice = QComboBox(); choice.setAccessibleName("SDK and import Help topics")
|
|
530
|
+
for document in documents:
|
|
531
|
+
choice.addItem(load_pycforge_icon("module" if document.get("id", "").startswith("import:") else "help"), document["title"])
|
|
532
|
+
choice.currentIndexChanged.connect(lambda index: browser.setHtml(documents[index]["html"]))
|
|
533
|
+
browser.setHtml(documents[0]["html"])
|
|
534
|
+
if self.help_documents: choice.setCurrentIndex(1)
|
|
535
|
+
dlg.body.addWidget(label("Help from PyCForge " + self.help_engine + " · " + self.connection if self.help_documents else
|
|
536
|
+
"Getting started — connect to PyCForge for its SDK guide and conversion-import Help.", muted=True))
|
|
537
|
+
dlg.body.addWidget(choice)
|
|
538
|
+
def find():
|
|
539
|
+
if not browser.find(search.text()):
|
|
540
|
+
cursor = browser.textCursor(); cursor.movePosition(cursor.MoveOperation.Start)
|
|
541
|
+
browser.setTextCursor(cursor); browser.find(search.text())
|
|
542
|
+
search.returnPressed.connect(find)
|
|
543
|
+
dlg.body.addWidget(search); dlg.body.addWidget(browser, 1)
|
|
544
|
+
dlg.body.addWidget(button("Close", "close", dlg.accept)); dlg.resize(900, 690); dlg.exec()
|
|
545
|
+
|
|
546
|
+
def closeEvent(self, event):
|
|
547
|
+
if self.runner.busy:
|
|
548
|
+
self.close_pending = True; self.cancel(); event.ignore(); return
|
|
549
|
+
if self.dirty:
|
|
550
|
+
choice = Prompt.ask(self, "Unsaved project", "Save your project edits before closing?",
|
|
551
|
+
[("save", "Save"), ("discard", "Discard edits"), ("cancel", "Keep editing")])
|
|
552
|
+
if choice == "cancel": event.ignore(); return
|
|
553
|
+
if choice == "save":
|
|
554
|
+
self.close_after_save = True; self.save_project(); event.ignore(); return
|
|
555
|
+
if self.startup_dialog:
|
|
556
|
+
dialog, self.startup_dialog = self.startup_dialog, None
|
|
557
|
+
dialog.accept(); dialog.deleteLater()
|
|
558
|
+
self.settings.setValue("compiler", self.compiler.text())
|
|
559
|
+
event.accept()
|
pycforge_sdk/native.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Generic fixture orchestration using the selected engine's build profile."""
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import platform
|
|
4
|
+
import shutil
|
|
5
|
+
from .process import run
|
|
6
|
+
from .project import digest, read
|
|
7
|
+
from .results import SDKError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def compiler_identity(compiler, profile, *, timeout, cancel):
|
|
11
|
+
if type(profile) is not dict or platform.system() not in profile.get("hosts", []):
|
|
12
|
+
raise SDKError("SDK_TARGET", "Native verification is not qualified for this host by the selected engine profile.")
|
|
13
|
+
for key in ("compile_args", "link_args", "compiler_version_args"):
|
|
14
|
+
if type(profile.get(key)) is not list or any(type(a) is not str or len(a) > 4096 for a in profile[key]):
|
|
15
|
+
raise SDKError("SDK_CAPABILITY", "Malformed native toolchain profile.")
|
|
16
|
+
executable = shutil.which(str(compiler))
|
|
17
|
+
if not executable:
|
|
18
|
+
raise SDKError("SDK_COMPILER", "C compiler not found: " + str(compiler), status="incomplete")
|
|
19
|
+
executable = str(Path(executable).resolve())
|
|
20
|
+
binary = read(executable, 128*1024*1024)
|
|
21
|
+
result = run([executable, *profile["compiler_version_args"]], timeout=timeout, cancel=cancel)
|
|
22
|
+
if result.returncode:
|
|
23
|
+
raise SDKError("SDK_COMPILER", "Cannot identify the selected C compiler.", status="incomplete")
|
|
24
|
+
return {"executable": executable, "sha256": digest(binary), "version": result.stdout.decode("utf-8", "replace"),
|
|
25
|
+
"system": platform.system(), "machine": platform.machine(), "profile": profile}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def execute_fixture(c_text, expected, compiler, work, *, timeout, cancel):
|
|
29
|
+
source, executable = Path(work)/"program.c", Path(work)/"program"
|
|
30
|
+
source.write_text(c_text, encoding="utf-8", newline="\n")
|
|
31
|
+
profile = compiler["profile"]
|
|
32
|
+
build = run([compiler["executable"], *profile["compile_args"], str(source), *profile["link_args"], "-o", str(executable)],
|
|
33
|
+
cwd=work, timeout=timeout, cancel=cancel)
|
|
34
|
+
result = {"compiler_exit_code": build.returncode, "compiler_stderr": build.stderr.decode("utf-8", "replace")}
|
|
35
|
+
if build.returncode or not executable.is_file():
|
|
36
|
+
return {**result, "passed": False, "reason": "Native compilation did not produce an executable."}
|
|
37
|
+
native = run([executable], cwd=work, timeout=timeout, cancel=cancel)
|
|
38
|
+
actual = {"stdout": native.stdout.decode("utf-8", "replace"), "stderr": native.stderr.decode("utf-8", "replace"), "exit_code": native.returncode}
|
|
39
|
+
passed = (native.stdout == expected["stdout"].encode("utf-8") and native.stderr == expected["stderr"].encode("utf-8")
|
|
40
|
+
and native.returncode == expected["exit_code"])
|
|
41
|
+
return {**result, "actual": actual, "passed": passed,
|
|
42
|
+
"reason": "Fixture matched." if passed else "Native result differs from the fixture expectation."}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Report the engine-produced archive's identity without guessing its family."""
|
|
2
|
+
import io
|
|
3
|
+
import json
|
|
4
|
+
import zipfile
|
|
5
|
+
from .results import SDKError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def archive_format(content):
|
|
9
|
+
"""Read inert metadata after engine admission; this is not package admission."""
|
|
10
|
+
try:
|
|
11
|
+
with zipfile.ZipFile(io.BytesIO(content)) as archive:
|
|
12
|
+
member=archive.getinfo('manifest.json')
|
|
13
|
+
if member.file_size > 65536:
|
|
14
|
+
raise ValueError('Manifest exceeds the reporting budget')
|
|
15
|
+
data=json.loads(archive.read(member))
|
|
16
|
+
value=data['format']
|
|
17
|
+
if type(value) is not str or not value.strip() or len(value)>200:
|
|
18
|
+
raise ValueError('Missing package format')
|
|
19
|
+
return value
|
|
20
|
+
except (ValueError,TypeError,KeyError,zipfile.BadZipFile,RuntimeError) as error:
|
|
21
|
+
raise SDKError('SDK_ENGINE_ERROR','Cannot read the engine-produced package identity: '+str(error)) from error
|