pyqt-code-editor 0.0.55__tar.gz → 0.0.56__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.
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/PKG-INFO +16 -3
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/__init__.py +1 -1
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/app.py +20 -0
- pyqt_code_editor-0.0.56/pyqt_code_editor/components/jupyter_console/__init__.py +1 -0
- pyqt_code_editor-0.0.56/pyqt_code_editor/components/jupyter_console/jupyter_console.py +198 -0
- pyqt_code_editor-0.0.55/pyqt_code_editor/components/jupyter_console.py → pyqt_code_editor-0.0.56/pyqt_code_editor/components/jupyter_console/jupyter_console_tab.py +84 -261
- pyqt_code_editor-0.0.56/pyqt_code_editor/components/jupyter_console/kernel_spec_manager.py +21 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/components/sigmund/sigmund_analyst_widget.py +36 -9
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/readme.md +15 -2
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/COPYING +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyproject.toml +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/_settings.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/code_editors/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/code_editors/code_editors.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/code_editors/languages/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/code_editors/languages/generic.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/code_editors/languages/javascript.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/code_editors/languages/markdown.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/code_editors/languages/python.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/code_editors/languages/text.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/components/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/components/editor_panel.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/components/find_in_files.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/components/project_explorer.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/components/settings_panel.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/components/sigmund/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/components/sigmund/confirm_run_code_dialog.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/components/sigmund/editor_workspace.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/components/sigmund/sigmund.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/components/sigmund/sigmund_analyst_chat_widget.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/components/workspace_explorer.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/environment_manager.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/auto_indent.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/auto_pair.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/base.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/check.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/comment.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/complete.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/execute.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/file_link.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/highlight_matching_brackets.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/line_number.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/merge_undo_actions.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/python_auto_indent.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/search_replace.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/shortcuts.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/smart_backspace_delete.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/symbols.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/theme.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/widgets/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/mixins/zoom.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/sigmund-analyst.png +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/signal_router.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/syntax_highlighters/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/syntax_highlighters/languages/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/syntax_highlighters/languages/generic.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/syntax_highlighters/languages/python.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/syntax_highlighters/syntax_highlighter.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/themes.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/utils/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/utils/languages/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/utils/languages/python/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/utils/languages/python/_auto_indent.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/utils/languages/python/_extract_cells.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/utils/languages/python/_mask_str_in_code.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/watchdog.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/widgets/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/widgets/calltip_widget.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/widgets/completion_popup.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/widgets/dock.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/widgets/quick_open_dialog.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/widgets/quick_open_file_dialog.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/widgets/quick_symbol_dialog.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/widgets/search_replace_frame.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/widgets/tab_splitter.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/widgets/tabbed_editor.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/languages/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/languages/generic.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/languages/python.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/manager.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/process.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/providers/__init__.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/providers/codestral.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/providers/jedi.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/providers/ruff.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/providers/sigmund.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/providers/symbol.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/providers/tree_sitter.py +0 -0
- {pyqt_code_editor-0.0.55 → pyqt_code_editor-0.0.56}/pyqt_code_editor/worker/settings.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyqt_code_editor
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.56
|
|
4
4
|
Summary: Fully featured code-editor widgets for PyQt
|
|
5
5
|
Keywords: code editor,pyqt,ide
|
|
6
6
|
Author-email: Sebastiaan Mathôt <s.mathot@cogsci.nl>
|
|
@@ -30,10 +30,15 @@ Requires-Dist: tree-sitter-yaml
|
|
|
30
30
|
Requires-Dist: ruff
|
|
31
31
|
Project-URL: Source, https://github.com/open-cogsci/sigmund-analyst
|
|
32
32
|
|
|
33
|
-
# PyQt Code Editor
|
|
33
|
+
# Sigmund Analyst (PyQt Code Editor)
|
|
34
34
|
|
|
35
35
|
Copyright 2025-2026 Sebastiaan Mathôt
|
|
36
36
|
|
|
37
|
+
- [About](#about)
|
|
38
|
+
- [AI integration](#ai-integration)
|
|
39
|
+
- [Installation](#installation)
|
|
40
|
+
- [License](#license)
|
|
41
|
+
|
|
37
42
|
|
|
38
43
|
## About
|
|
39
44
|
|
|
@@ -68,7 +73,15 @@ As-you-type code suggestions are provided by Mistral Codestral. To activate Mist
|
|
|
68
73
|
|
|
69
74
|
## Installation
|
|
70
75
|
|
|
71
|
-
|
|
76
|
+
|
|
77
|
+
### Windows
|
|
78
|
+
|
|
79
|
+
The easiest way to install Sigmund Analys on Windows is to install OpenSesame, which include Sigmund Analyst:
|
|
80
|
+
|
|
81
|
+
- <https://osdoc.cogsci.nl/download/>
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
### Linux/ Ubuntu
|
|
72
85
|
|
|
73
86
|
The easiest way to install Sigmund Analyst on Linux is to download and run the installer script. This will create a Virtual Environment, pip install Sigmund Analyst and all dependencies into this environment, and add a Desktop file to your system to easily start Sigmund Analyst. To upgrade, simply run the script again.
|
|
74
87
|
|
|
@@ -456,10 +456,30 @@ class SigmundAnalyst(QMainWindow):
|
|
|
456
456
|
)
|
|
457
457
|
dlg.exec_()
|
|
458
458
|
|
|
459
|
+
|
|
460
|
+
def handle_output(text, content):
|
|
461
|
+
print('***')
|
|
462
|
+
print(text)
|
|
463
|
+
# print('---')
|
|
464
|
+
# for part in content['parts']:
|
|
465
|
+
# print(part)
|
|
466
|
+
# print(content)
|
|
467
|
+
print('***')
|
|
468
|
+
|
|
459
469
|
|
|
460
470
|
def launch_app():
|
|
461
471
|
app = QApplication(sys.argv)
|
|
462
472
|
settings.set_font_family()
|
|
463
473
|
window = SigmundAnalyst()
|
|
464
474
|
window.show()
|
|
475
|
+
window._jupyter_console.execution_complete.connect(handle_output)
|
|
476
|
+
window._toggle_dock_widget(window._jupyter_console)
|
|
477
|
+
# window._jupyter_console.execute_code('''
|
|
478
|
+
# from matplotlib import pyplot as plt
|
|
479
|
+
# plt.plot([1,2,3,4])
|
|
480
|
+
# plt.show()
|
|
481
|
+
# print(10)
|
|
482
|
+
# # int('x')
|
|
483
|
+
# 11
|
|
484
|
+
# ''')
|
|
465
485
|
sys.exit(app.exec_())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .jupyter_console import JupyterConsole
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
from qtpy.QtWidgets import (QTabWidget, QWidget, QToolButton, QMenu,
|
|
2
|
+
QAction, QHBoxLayout)
|
|
3
|
+
from qtpy.QtCore import Signal
|
|
4
|
+
import qtawesome as qta
|
|
5
|
+
import sys
|
|
6
|
+
import logging
|
|
7
|
+
from ...environment_manager import environment_manager
|
|
8
|
+
from ...themes import HORIZONTAL_SPACING
|
|
9
|
+
from ...widgets import Dock
|
|
10
|
+
from .jupyter_console_tab import JupyterConsoleTab
|
|
11
|
+
from .kernel_spec_manager import HomeAwareKernelSpecManager
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class JupyterConsole(Dock):
|
|
16
|
+
"""Dockable widget containing tabbed Jupyter consoles"""
|
|
17
|
+
|
|
18
|
+
execution_complete = Signal(str, object)
|
|
19
|
+
workspace_updated = Signal(dict)
|
|
20
|
+
|
|
21
|
+
def __init__(self, parent=None, default_kernel='python3'):
|
|
22
|
+
super().__init__("Jupyter Console", parent)
|
|
23
|
+
self.setObjectName('jupyter_console')
|
|
24
|
+
self.default_kernel = default_kernel
|
|
25
|
+
|
|
26
|
+
# ---------------------------------------------------------------------
|
|
27
|
+
# Kernel cache
|
|
28
|
+
# ---------------------------------------------------------------------
|
|
29
|
+
self.available_kernels = {} # will be filled by refresh_kernel_menu()
|
|
30
|
+
|
|
31
|
+
# ---------------------------------------------------------------------
|
|
32
|
+
# UI setup
|
|
33
|
+
# ---------------------------------------------------------------------
|
|
34
|
+
self.tab_widget = QTabWidget()
|
|
35
|
+
self.tab_widget.setTabsClosable(True)
|
|
36
|
+
self.tab_widget.tabCloseRequested.connect(self.close_tab)
|
|
37
|
+
self.tab_widget.currentChanged.connect(self._on_tab_changed)
|
|
38
|
+
self.setWidget(self.tab_widget)
|
|
39
|
+
|
|
40
|
+
# Corner widget with buttons
|
|
41
|
+
corner_widget = QWidget()
|
|
42
|
+
corner_layout = QHBoxLayout(corner_widget)
|
|
43
|
+
corner_layout.setContentsMargins(0, 0, 0, 0)
|
|
44
|
+
corner_layout.setSpacing(HORIZONTAL_SPACING)
|
|
45
|
+
|
|
46
|
+
self.kernel_button = QToolButton()
|
|
47
|
+
self.kernel_button.setIcon(qta.icon('mdi6.plus'))
|
|
48
|
+
self.kernel_button.setToolTip("Add new kernel")
|
|
49
|
+
self.kernel_button.setPopupMode(QToolButton.InstantPopup)
|
|
50
|
+
self.kernel_button.setAutoRaise(True)
|
|
51
|
+
corner_layout.addWidget(self.kernel_button)
|
|
52
|
+
|
|
53
|
+
self.restart_button = QToolButton()
|
|
54
|
+
self.restart_button.setIcon(qta.icon('mdi6.restart'))
|
|
55
|
+
self.restart_button.setToolTip("Restart current kernel")
|
|
56
|
+
self.restart_button.clicked.connect(self.restart_current_kernel)
|
|
57
|
+
self.restart_button.setAutoRaise(True)
|
|
58
|
+
corner_layout.addWidget(self.restart_button)
|
|
59
|
+
|
|
60
|
+
self.interrupt_button = QToolButton()
|
|
61
|
+
self.interrupt_button.setIcon(qta.icon('mdi6.stop'))
|
|
62
|
+
self.interrupt_button.setToolTip("Interrupt current kernel (Ctrl+C)")
|
|
63
|
+
self.interrupt_button.clicked.connect(self.interrupt_current_kernel)
|
|
64
|
+
self.interrupt_button.setAutoRaise(True)
|
|
65
|
+
corner_layout.addWidget(self.interrupt_button)
|
|
66
|
+
|
|
67
|
+
self.tab_widget.setCornerWidget(corner_widget)
|
|
68
|
+
|
|
69
|
+
# ---------------------------------------------------------------------
|
|
70
|
+
# Kernel menu
|
|
71
|
+
# ---------------------------------------------------------------------
|
|
72
|
+
self.kernel_menu = QMenu(self.kernel_button)
|
|
73
|
+
self.kernel_button.setMenu(self.kernel_menu)
|
|
74
|
+
self.refresh_kernel_menu()
|
|
75
|
+
|
|
76
|
+
# ---------------------------------------------------------------------
|
|
77
|
+
# Start with a default kernel
|
|
78
|
+
# ---------------------------------------------------------------------
|
|
79
|
+
self.add_console_tab(self.default_kernel)
|
|
80
|
+
|
|
81
|
+
# -------------------------------------------------------------------------
|
|
82
|
+
# Helper methods
|
|
83
|
+
# -------------------------------------------------------------------------
|
|
84
|
+
def _on_tab_changed(self, index):
|
|
85
|
+
console_tab = self.tab_widget.widget(index)
|
|
86
|
+
if console_tab:
|
|
87
|
+
console_tab.update_workspace()
|
|
88
|
+
spec = self.available_kernels.get(console_tab.kernel_name, None)
|
|
89
|
+
if spec:
|
|
90
|
+
python_executable = spec['spec']['argv'][0]
|
|
91
|
+
else:
|
|
92
|
+
python_executable = sys.executable
|
|
93
|
+
environment_manager.set_environment(console_tab.kernel_name,
|
|
94
|
+
python_executable,
|
|
95
|
+
'python')
|
|
96
|
+
|
|
97
|
+
# -------------------------------------------------------------------------
|
|
98
|
+
# Kernel handling
|
|
99
|
+
# -------------------------------------------------------------------------
|
|
100
|
+
def refresh_kernel_menu(self):
|
|
101
|
+
"""Refresh the list of available kernels and rebuild the kernel menu."""
|
|
102
|
+
self.kernel_menu.clear()
|
|
103
|
+
|
|
104
|
+
# Get available kernelspecs
|
|
105
|
+
kernel_spec_manager = HomeAwareKernelSpecManager()
|
|
106
|
+
self.available_kernels = kernel_spec_manager.get_all_specs()
|
|
107
|
+
self.fallback_kernel = list(self.available_kernels.keys())[0]
|
|
108
|
+
for spec_name, spec in self.available_kernels.items():
|
|
109
|
+
display_name = spec['spec']['display_name']
|
|
110
|
+
action = QAction(display_name, self)
|
|
111
|
+
action.setData(spec_name)
|
|
112
|
+
action.triggered.connect(self.kernel_menu_triggered)
|
|
113
|
+
self.kernel_menu.addAction(action)
|
|
114
|
+
|
|
115
|
+
def kernel_menu_triggered(self):
|
|
116
|
+
action = self.sender()
|
|
117
|
+
if action:
|
|
118
|
+
self.add_console_tab(action.data())
|
|
119
|
+
|
|
120
|
+
def add_console_tab(self, kernel_name):
|
|
121
|
+
"""Add a new console tab with the specified kernel.
|
|
122
|
+
Falls back to the first available kernel if the requested one is invalid.
|
|
123
|
+
"""
|
|
124
|
+
if kernel_name not in self.available_kernels:
|
|
125
|
+
if self.available_kernels:
|
|
126
|
+
logger.warning(
|
|
127
|
+
"Requested kernel '%s' not found. "
|
|
128
|
+
"Falling back to '%s'.", kernel_name, self.fallback_kernel
|
|
129
|
+
)
|
|
130
|
+
kernel_name = self.fallback_kernel
|
|
131
|
+
else:
|
|
132
|
+
logger.error("No available kernels found. Cannot create console tab.")
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
console_tab = JupyterConsoleTab(kernel_name=kernel_name, parent=self)
|
|
136
|
+
console_tab.execution_complete.connect(self.handle_execution_complete)
|
|
137
|
+
console_tab.workspace_updated.connect(self.handle_workspace_updated)
|
|
138
|
+
index = self.tab_widget.addTab(console_tab, kernel_name)
|
|
139
|
+
self.tab_widget.setCurrentIndex(index)
|
|
140
|
+
return console_tab
|
|
141
|
+
|
|
142
|
+
# -------------------------------------------------------------------------
|
|
143
|
+
# Tab / kernel management
|
|
144
|
+
# -------------------------------------------------------------------------
|
|
145
|
+
def close_tab(self, index):
|
|
146
|
+
widget = self.tab_widget.widget(index)
|
|
147
|
+
if widget:
|
|
148
|
+
widget.shutdown_kernel()
|
|
149
|
+
self.tab_widget.removeTab(index)
|
|
150
|
+
if self.tab_widget.count() == 0:
|
|
151
|
+
self.add_console_tab(self.default_kernel)
|
|
152
|
+
|
|
153
|
+
def get_current_console(self):
|
|
154
|
+
return self.tab_widget.currentWidget()
|
|
155
|
+
|
|
156
|
+
def restart_current_kernel(self):
|
|
157
|
+
console = self.get_current_console()
|
|
158
|
+
if console:
|
|
159
|
+
logger.info("Restarting current kernel")
|
|
160
|
+
if console.restart_kernel():
|
|
161
|
+
logger.info("Kernel restart initiated")
|
|
162
|
+
else:
|
|
163
|
+
logger.warning("Failed to restart kernel")
|
|
164
|
+
|
|
165
|
+
def interrupt_current_kernel(self):
|
|
166
|
+
console = self.get_current_console()
|
|
167
|
+
if console:
|
|
168
|
+
logger.info("Interrupting current kernel")
|
|
169
|
+
if console.interrupt_kernel():
|
|
170
|
+
logger.info("Interrupt signal sent to kernel")
|
|
171
|
+
else:
|
|
172
|
+
logger.warning("Failed to interrupt kernel")
|
|
173
|
+
|
|
174
|
+
# -------------------------------------------------------------------------
|
|
175
|
+
# Execution helpers
|
|
176
|
+
# -------------------------------------------------------------------------
|
|
177
|
+
def execute_code(self, code, silent=False):
|
|
178
|
+
console = self.get_current_console()
|
|
179
|
+
if console:
|
|
180
|
+
(console.execute_silently if silent else console.execute_code)(code)
|
|
181
|
+
|
|
182
|
+
def execute_file(self, filepath):
|
|
183
|
+
console = self.get_current_console()
|
|
184
|
+
if console:
|
|
185
|
+
console.execute_file(filepath)
|
|
186
|
+
|
|
187
|
+
def change_directory(self, directory):
|
|
188
|
+
console = self.get_current_console()
|
|
189
|
+
return console.change_directory(directory) if console else False
|
|
190
|
+
|
|
191
|
+
# -------------------------------------------------------------------------
|
|
192
|
+
# Signals
|
|
193
|
+
# -------------------------------------------------------------------------
|
|
194
|
+
def handle_execution_complete(self, output, result):
|
|
195
|
+
self.execution_complete.emit(output, result)
|
|
196
|
+
|
|
197
|
+
def handle_workspace_updated(self, data):
|
|
198
|
+
self.workspace_updated.emit(data)
|