Skip to content

Commit e1d98c9

Browse files
committed
Update both version
* Fix JupyterLab widget and thread * Rename Logger and log file * Add multi language words
1 parent ce72017 commit e1d98c9

12 files changed

Lines changed: 145 additions & 71 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,5 @@ dmypy.json
149149
.jeditor
150150
**/.jeditor
151151
**/user_setting.*
152-
bing_cookies.*
152+
bing_cookies.*
153+
**/output

dev.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
66

77
[project]
88
name = "pybreeze_dev"
9-
version = "1.0.8"
9+
version = "1.0.10"
1010
authors = [
1111
{ name = "JE-Chen", email = "jechenmailman@gmail.com" },
1212
]
File renamed without changes.

pybreeze/pybreeze_ui/extend_multi_language/extend_english.py renamed to pybreeze/extend_multi_language/extend_english.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,5 +270,11 @@ def update_english_word_dict():
270270
"skills_response_label": "Response:",
271271
"skills_missing_input": "Please enter API URL and Prompt",
272272
"skills_generating": "Generating...",
273+
# JupyterLab GUI
274+
"jupyterlab_init": "Initializing...",
275+
"jupyterlab_downloading": "Downloading...",
276+
"jupyterlab_loading": "Loading...",
277+
"jupyterlab_timeout": "JupyterLab Timeout",
278+
"jupyterlab_init_failed": "JupyterLab init failed",
273279
}
274280
)

pybreeze/pybreeze_ui/extend_multi_language/extend_traditional_chinese.py renamed to pybreeze/extend_multi_language/extend_traditional_chinese.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,5 +270,11 @@ def update_traditional_chinese_word_dict():
270270
"skills_response_label": "回傳結果:",
271271
"skills_missing_input": "請輸入 API URL 和 Prompt",
272272
"skills_generating": "產生中...",
273+
# JupyterLab GUI
274+
"jupyterlab_init": "初始化中...",
275+
"jupyterlab_downloading": "下載中...",
276+
"jupyterlab_loading": "載入中...",
277+
"jupyterlab_timeout": "JupyterLab 啟動超時",
278+
"jupyterlab_init_failed": "JupyterLab 啟動失敗",
273279
}
274280
)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from pybreeze.extend_multi_language.extend_english import update_english_word_dict
2+
from pybreeze.extend_multi_language.extend_traditional_chinese import \
3+
update_traditional_chinese_word_dict
4+
5+
6+
def update_language_dict():
7+
update_traditional_chinese_word_dict()
8+
update_english_word_dict()

pybreeze/pybreeze_ui/editor_main/main_ui.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,15 @@
44
from pathlib import Path
55
from typing import List, Dict, Type
66

7-
from pybreeze.utils.logging.logger import pybreeze_logger
8-
97
environ["LOCUST_SKIP_MONKEY_PATCH"] = "1"
108

119
from PySide6.QtCore import QTimer, QCoreApplication
1210
from PySide6.QtGui import QIcon
13-
from PySide6.QtWidgets import QApplication, QWidget, QSystemTrayIcon
11+
from PySide6.QtWidgets import QApplication, QWidget
1412
from je_editor import EditorMain, language_wrapper
1513
from qt_material import apply_stylesheet
1614

17-
from pybreeze.pybreeze_ui.extend_multi_language.update_language_dict import update_language_dict
15+
from pybreeze.extend_multi_language.update_language_dict import update_language_dict
1816
from pybreeze.pybreeze_ui.menu.build_menubar import add_menu_to_menubar
1917
from pybreeze.pybreeze_ui.syntax.syntax_extend import \
2018
syntax_extend_package

pybreeze/pybreeze_ui/extend_multi_language/update_language_dict.py

Lines changed: 0 additions & 8 deletions
This file was deleted.

pybreeze/pybreeze_ui/jupyter_lab_gui/jupyer_lab_thread.py

Lines changed: 91 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
import os
12
import socket
23
import subprocess
34
import sys
4-
from PySide6.QtCore import QThread, Signal
55
import time
6+
import traceback
7+
8+
from PySide6.QtCore import QThread, Signal
9+
from je_editor import language_wrapper
10+
11+
from pybreeze.utils.logging.logger import pybreeze_logger
612

713

814
def find_free_port():
@@ -13,41 +19,93 @@ def find_free_port():
1319
return port
1420

1521

16-
class JupyterServerThread(QThread):
17-
server_ready = Signal(str)
22+
def get_venv_python():
23+
# 如果在 venv 中
24+
if hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix):
25+
return sys.executable
26+
27+
# 嘗試從常見位置找 venv
28+
possible_paths = [
29+
os.path.join(os.getcwd(), "venv", "Scripts", "python.exe"),
30+
os.path.join(os.getcwd(), ".venv", "Scripts", "python.exe"),
31+
]
1832

19-
def __init__(self):
20-
super().__init__()
21-
self.process = None
33+
for path in possible_paths:
34+
if os.path.exists(path):
35+
return path
36+
37+
raise RuntimeError("找不到 venv 的 python.exe")
38+
39+
40+
def is_jupyter_installed(python_exe):
41+
result = subprocess.run(
42+
[python_exe, "-m", "pip", "show", "jupyterlab"],
43+
stdout=subprocess.PIPE,
44+
stderr=subprocess.PIPE
45+
)
46+
return result.returncode == 0
47+
48+
49+
class JupyterLauncherThread(QThread):
50+
server_ready = Signal(str)
51+
status_update = Signal(str)
52+
error_occurred = Signal(str)
2253

2354
def run(self):
24-
port = find_free_port()
25-
26-
cmd = [
27-
sys.executable,
28-
"-m",
29-
"jupyterlab",
30-
"--no-browser",
31-
f"--ServerApp.port={port}",
32-
"--ServerApp.token=",
33-
"--ServerApp.password=",
34-
"--ServerApp.allow_origin=*",
35-
"--ServerApp.disable_check_xsrf=True",
36-
]
37-
38-
self.process = subprocess.Popen(cmd)
39-
40-
# 輪詢 port,直到可連
41-
while True:
42-
try:
43-
s = socket.create_connection(("localhost", port), timeout=0.5)
44-
s.close()
45-
break
46-
except OSError:
47-
time.sleep(0.1)
48-
49-
# Server ready,發射 signal
50-
self.server_ready.emit(f"http://localhost:{port}/lab")
55+
try:
56+
python_exe = get_venv_python()
57+
58+
if not is_jupyter_installed(python_exe):
59+
self.status_update.emit(language_wrapper.language_word_dict.get("jupyterlab_downloading"))
60+
61+
result = subprocess.run([
62+
python_exe,
63+
"-m",
64+
"pip",
65+
"install",
66+
"jupyterlab",
67+
"-U"
68+
], capture_output=True, text=True)
69+
70+
if result.returncode != 0:
71+
raise RuntimeError(result.stderr)
72+
73+
self.status_update.emit(language_wrapper.language_word_dict.get("jupyterlab_loading"))
74+
75+
port = find_free_port()
76+
77+
self.process = subprocess.Popen([
78+
python_exe,
79+
"-m",
80+
"jupyterlab",
81+
"--no-browser",
82+
f"--ServerApp.port={port}",
83+
"--ServerApp.token=",
84+
"--ServerApp.password=",
85+
"--ServerApp.allow_origin=*",
86+
"--ServerApp.disable_check_xsrf=True",
87+
], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
88+
89+
start_time = time.time()
90+
91+
while True:
92+
if time.time() - start_time > 30:
93+
raise TimeoutError("JupyterLab 啟動超時")
94+
95+
try:
96+
s = socket.create_connection(("localhost", port), timeout=0.5)
97+
s.close()
98+
break
99+
except OSError:
100+
time.sleep(0.2)
101+
102+
self.server_ready.emit(f"http://localhost:{port}/lab")
103+
104+
except Exception:
105+
err = traceback.format_exc()
106+
print(err)
107+
self.error_occurred.emit(err)
108+
pybreeze_logger.info(err)
51109

52110
def stop(self):
53111
if self.process:

pybreeze/pybreeze_ui/jupyter_lab_gui/jupyter_lab_widget.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
from PySide6.QtCore import QUrl
44
from PySide6.QtWebEngineWidgets import QWebEngineView
5-
from PySide6.QtWidgets import QApplication, QVBoxLayout, QWidget
5+
from PySide6.QtWidgets import QApplication, QVBoxLayout, QWidget, QLabel
6+
from je_editor import language_wrapper
67

7-
from pybreeze.pybreeze_ui.jupyter_lab_gui.jupyer_lab_thread import JupyterServerThread
8+
from pybreeze.pybreeze_ui.jupyter_lab_gui.jupyer_lab_thread import JupyterLauncherThread
9+
from pybreeze.utils.logging.logger import pybreeze_logger
810

911

1012
class JupyterLabWidget(QWidget):
@@ -14,45 +16,48 @@ def __init__(self):
1416

1517
layout = QVBoxLayout(self)
1618

19+
self.status_label = QLabel(language_wrapper.language_word_dict.get("jupyterlab_init"))
20+
layout.addWidget(self.status_label)
21+
1722
self.browser = QWebEngineView()
23+
self.browser.hide()
1824
layout.addWidget(self.browser)
1925

20-
# 啟動 Jupyter server thread
21-
self.thread = JupyterServerThread()
26+
self.thread = JupyterLauncherThread()
27+
self.thread.status_update.connect(self.update_status)
2228
self.thread.server_ready.connect(self.load_lab)
29+
self.thread.error_occurred.connect(self.show_error)
2330
self.thread.start()
2431

25-
def load_lab(self, url: str):
26-
"""Load JupyterLab URL into WebEngine"""
27-
28-
if not url:
29-
print("Invalid JupyterLab URL")
30-
return
31-
32-
print("JupyterLab running at:", url)
32+
def update_status(self, text):
33+
self.status_label.setText(text)
3334

34-
qurl = QUrl(url)
35+
def load_lab(self, url):
36+
if self.status_label:
37+
self.status_label.setParent(None)
38+
self.status_label.deleteLater()
39+
self.status_label = None
3540

36-
if not qurl.isValid():
37-
print("Invalid QUrl:", url)
38-
return
41+
self.browser.setUrl(QUrl(url))
42+
self.browser.show()
3943

40-
self.browser.setUrl(qurl)
44+
def show_error(self, msg):
45+
self.status_label.setText(language_wrapper.language_word_dict.get("jupyterlab_init_failed"))
46+
print(msg)
47+
pybreeze_logger.info(msg)
4148

4249
def closeEvent(self, event):
43-
44-
if hasattr(self, "thread") and self.thread.isRunning():
50+
if self.thread.isRunning():
4551
self.thread.stop()
4652
self.thread.quit()
4753
self.thread.wait()
48-
4954
event.accept()
5055

5156

5257
if __name__ == "__main__":
5358
app = QApplication(sys.argv)
5459

5560
win = JupyterLabWidget()
56-
win.show()
61+
win.showMaximized()
5762

5863
sys.exit(app.exec())

0 commit comments

Comments
 (0)