je-editor 0.0.222__py3-none-any.whl → 0.0.224__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.
Potentially problematic release.
This version of je-editor might be problematic. Click here for more details.
- je_editor/__init__.py +2 -2
- je_editor/git_client/commit_graph.py +7 -7
- je_editor/git_client/git_action.py +0 -7
- je_editor/pyside_ui/browser/browser_view.py +16 -4
- je_editor/pyside_ui/browser/browser_widget.py +43 -29
- je_editor/pyside_ui/browser/main_browser_widget.py +85 -0
- je_editor/pyside_ui/code/auto_save/auto_save_manager.py +34 -2
- je_editor/pyside_ui/code/auto_save/auto_save_thread.py +19 -6
- je_editor/pyside_ui/code/code_format/pep8_format.py +53 -9
- je_editor/pyside_ui/code/code_process/code_exec.py +88 -52
- je_editor/pyside_ui/code/plaintext_code_edit/code_edit_plaintext.py +116 -55
- je_editor/pyside_ui/code/running_process_manager.py +19 -1
- je_editor/pyside_ui/code/shell_process/shell_exec.py +71 -48
- je_editor/pyside_ui/code/syntax/python_syntax.py +45 -10
- je_editor/pyside_ui/code/syntax/syntax_setting.py +40 -12
- je_editor/pyside_ui/code/textedit_code_result/code_record.py +34 -12
- je_editor/pyside_ui/code/variable_inspector/inspector_gui.py +53 -6
- je_editor/pyside_ui/dialog/ai_dialog/set_ai_dialog.py +30 -3
- je_editor/pyside_ui/dialog/file_dialog/create_file_dialog.py +35 -2
- je_editor/pyside_ui/dialog/file_dialog/open_file_dialog.py +33 -5
- je_editor/pyside_ui/dialog/file_dialog/save_file_dialog.py +25 -3
- je_editor/pyside_ui/dialog/search_ui/search_error_box.py +26 -1
- je_editor/pyside_ui/dialog/search_ui/search_text_box.py +26 -1
- je_editor/pyside_ui/git_ui/code_diff_compare/code_diff_viewer_widget.py +11 -11
- je_editor/pyside_ui/git_ui/git_client/commit_table.py +46 -8
- je_editor/pyside_ui/git_ui/git_client/git_branch_tree_widget.py +49 -15
- je_editor/pyside_ui/git_ui/git_client/git_client_gui.py +81 -16
- je_editor/pyside_ui/git_ui/git_client/graph_view.py +64 -20
- je_editor/pyside_ui/main_ui/ai_widget/ai_config.py +20 -5
- je_editor/pyside_ui/main_ui/ai_widget/ask_thread.py +20 -1
- je_editor/pyside_ui/main_ui/ai_widget/chat_ui.py +56 -41
- je_editor/pyside_ui/main_ui/ai_widget/langchain_interface.py +45 -6
- je_editor/pyside_ui/main_ui/console_widget/console_gui.py +44 -12
- je_editor/pyside_ui/main_ui/console_widget/qprocess_adapter.py +34 -13
- je_editor/pyside_ui/main_ui/dock/destroy_dock.py +33 -2
- je_editor/pyside_ui/main_ui/editor/editor_widget.py +104 -20
- je_editor/pyside_ui/main_ui/editor/editor_widget_dock.py +34 -7
- je_editor/pyside_ui/main_ui/editor/process_input.py +38 -11
- je_editor/pyside_ui/main_ui/ipython_widget/rich_jupyter.py +46 -11
- je_editor/pyside_ui/main_ui/main_editor.py +180 -42
- je_editor/pyside_ui/main_ui/menu/check_style_menu/build_check_style_menu.py +51 -28
- je_editor/pyside_ui/main_ui/menu/dock_menu/build_dock_menu.py +83 -36
- je_editor/pyside_ui/main_ui/menu/file_menu/build_file_menu.py +70 -17
- je_editor/pyside_ui/main_ui/menu/help_menu/build_help_menu.py +35 -4
- je_editor/pyside_ui/main_ui/menu/language_menu/build_language_server.py +41 -1
- je_editor/pyside_ui/main_ui/menu/python_env_menu/build_venv_menu.py +100 -42
- je_editor/pyside_ui/main_ui/menu/run_menu/build_run_menu.py +57 -7
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_debug_menu.py +50 -4
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_program_menu.py +52 -6
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_shell_menu.py +44 -4
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/utils.py +23 -1
- je_editor/pyside_ui/main_ui/menu/set_menu_bar.py +37 -12
- je_editor/pyside_ui/main_ui/menu/style_menu/build_style_menu.py +44 -7
- je_editor/pyside_ui/main_ui/menu/tab_menu/build_tab_menu.py +127 -44
- je_editor/pyside_ui/main_ui/menu/text_menu/build_text_menu.py +65 -1
- je_editor/pyside_ui/main_ui/save_settings/setting_utils.py +18 -1
- je_editor/pyside_ui/main_ui/save_settings/user_color_setting_file.py +33 -3
- je_editor/pyside_ui/main_ui/save_settings/user_setting_file.py +38 -11
- je_editor/pyside_ui/main_ui/system_tray/extend_system_tray.py +39 -2
- je_editor/start_editor.py +26 -1
- je_editor/utils/encodings/python_encodings.py +101 -98
- je_editor/utils/file/open/open_file.py +36 -19
- je_editor/utils/file/save/save_file.py +35 -14
- je_editor/utils/json/json_file.py +29 -14
- je_editor/utils/json_format/json_process.py +33 -2
- je_editor/utils/logging/loggin_instance.py +38 -8
- je_editor/utils/multi_language/multi_language_wrapper.py +29 -4
- je_editor/utils/redirect_manager/redirect_manager_class.py +49 -11
- je_editor/utils/venv_check/check_venv.py +45 -15
- {je_editor-0.0.222.dist-info → je_editor-0.0.224.dist-info}/METADATA +1 -1
- {je_editor-0.0.222.dist-info → je_editor-0.0.224.dist-info}/RECORD +74 -74
- je_editor/git_client/github.py +0 -81
- {je_editor-0.0.222.dist-info → je_editor-0.0.224.dist-info}/WHEEL +0 -0
- {je_editor-0.0.222.dist-info → je_editor-0.0.224.dist-info}/licenses/LICENSE +0 -0
- {je_editor-0.0.222.dist-info → je_editor-0.0.224.dist-info}/top_level.txt +0 -0
|
@@ -2,34 +2,51 @@ import typing
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from threading import Lock
|
|
4
4
|
|
|
5
|
+
# 匯入自訂例外與日誌工具
|
|
6
|
+
# Import custom exception and logging utility
|
|
5
7
|
from je_editor.utils.exception.exceptions import JEditorOpenFileException
|
|
6
8
|
from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
7
9
|
|
|
8
10
|
|
|
9
|
-
def read_file(file_path: str) ->
|
|
11
|
+
def read_file(file_path: str) -> list[Path | str] | None:
|
|
10
12
|
"""
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
功能說明 (Function Description):
|
|
14
|
+
用來檢查檔案是否存在並嘗試開啟,讀取其內容。
|
|
15
|
+
Used to check if a file exists and open it to read its content.
|
|
16
|
+
|
|
17
|
+
:param file_path: 檔案完整路徑 / the full path of the file to read
|
|
18
|
+
:return: [檔案路徑, 檔案內容] / [file path, file content]
|
|
19
|
+
|
|
20
|
+
流程 (Logic):
|
|
21
|
+
1. 嘗試鎖定執行緒 (避免多執行緒同時存取)
|
|
22
|
+
Try to lock the thread (prevent concurrent access).
|
|
23
|
+
2. 檢查檔案路徑是否為空,並確認檔案存在且為檔案。
|
|
24
|
+
Check if file path is not empty, exists, and is a file.
|
|
25
|
+
3. 若條件成立,嘗試以 UTF-8 編碼開啟檔案並讀取內容。
|
|
26
|
+
If true, open the file with UTF-8 encoding and read content.
|
|
27
|
+
4. 最後釋放鎖。
|
|
28
|
+
Finally, release the lock.
|
|
22
29
|
"""
|
|
30
|
+
|
|
31
|
+
# 記錄日誌,方便除錯與追蹤
|
|
32
|
+
# Log the file path for debugging and tracking
|
|
23
33
|
jeditor_logger.info(f"open_file.py read_file file_path: {file_path}")
|
|
24
|
-
|
|
34
|
+
|
|
35
|
+
lock = Lock() # 建立一個執行緒鎖 / Create a thread lock
|
|
25
36
|
try:
|
|
26
|
-
lock.acquire()
|
|
27
|
-
if file_path != "" and file_path is not None:
|
|
28
|
-
file_path = Path(file_path)
|
|
29
|
-
if file_path.exists() and file_path.is_file():
|
|
37
|
+
lock.acquire() # 嘗試鎖定資源 / Acquire the lock
|
|
38
|
+
if file_path != "" and file_path is not None: # 確認路徑不為空 / Ensure path is not empty
|
|
39
|
+
file_path = Path(file_path) # 轉換為 Path 物件 / Convert to Path object
|
|
40
|
+
if file_path.exists() and file_path.is_file(): # 檢查檔案存在且為檔案 / Check file existence
|
|
41
|
+
# 以讀寫模式開啟檔案 (UTF-8 編碼)
|
|
42
|
+
# Open file in read+write mode with UTF-8 encoding
|
|
30
43
|
with open(file_path, "r+", encoding="utf-8") as open_read_file:
|
|
31
|
-
return [file_path, open_read_file.read()]
|
|
44
|
+
return [file_path, open_read_file.read()] # 回傳檔案路徑與內容 / Return file path and content
|
|
32
45
|
except JEditorOpenFileException:
|
|
46
|
+
# 捕捉自訂例外並重新拋出
|
|
47
|
+
# Catch custom exception and re-raise
|
|
33
48
|
raise JEditorOpenFileException
|
|
34
49
|
finally:
|
|
35
|
-
|
|
50
|
+
# 確保鎖一定會被釋放
|
|
51
|
+
# Ensure the lock is always released
|
|
52
|
+
lock.release()
|
|
@@ -1,31 +1,52 @@
|
|
|
1
1
|
from threading import Lock
|
|
2
2
|
|
|
3
|
+
# 匯入自訂例外與日誌工具
|
|
4
|
+
# Import custom exception and logging utility
|
|
3
5
|
from je_editor.utils.exception.exceptions import JEditorSaveFileException
|
|
4
6
|
from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
def write_file(file_path: str, content: str) -> None:
|
|
8
10
|
"""
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
功能說明 (Function Description):
|
|
12
|
+
將指定內容寫入檔案,並確保在多執行緒環境下安全操作。
|
|
13
|
+
Write the given content into a file, ensuring thread safety.
|
|
14
|
+
|
|
15
|
+
:param file_path: 要寫入的檔案路徑 / the file path to write
|
|
16
|
+
:param content: 要寫入的內容 / the content to write
|
|
17
|
+
|
|
18
|
+
流程 (Logic):
|
|
19
|
+
1. 嘗試鎖定執行緒 (避免多執行緒同時存取檔案)
|
|
20
|
+
Try to lock the thread (prevent concurrent file access).
|
|
21
|
+
2. 檢查檔案路徑是否為空字串或 None。
|
|
22
|
+
Check if file path is not empty or None.
|
|
23
|
+
3. 若條件成立,開啟檔案並以 UTF-8 編碼寫入內容。
|
|
24
|
+
If valid, open the file and write content with UTF-8 encoding.
|
|
25
|
+
4. 最後釋放鎖。
|
|
26
|
+
Finally, release the lock.
|
|
17
27
|
"""
|
|
28
|
+
|
|
29
|
+
# 記錄日誌,方便除錯與追蹤
|
|
30
|
+
# Log the file path and content for debugging and tracking
|
|
18
31
|
jeditor_logger.info("save_file.py write_file "
|
|
19
32
|
f"file_path: {file_path} "
|
|
20
33
|
f"content: {content}")
|
|
21
|
-
|
|
22
|
-
|
|
34
|
+
|
|
35
|
+
lock = Lock() # 建立一個執行緒鎖 / Create a thread lock
|
|
36
|
+
content = str(content) # 確保內容為字串 / Ensure content is a string
|
|
37
|
+
|
|
23
38
|
try:
|
|
24
|
-
lock.acquire()
|
|
25
|
-
if file_path != "" and file_path is not None:
|
|
39
|
+
lock.acquire() # 嘗試鎖定資源 / Acquire the lock
|
|
40
|
+
if file_path != "" and file_path is not None: # 確認路徑有效 / Ensure path is valid
|
|
41
|
+
# 以寫入模式開啟檔案 (UTF-8 編碼)
|
|
42
|
+
# Open file in write+read mode with UTF-8 encoding
|
|
26
43
|
with open(file_path, "w+", encoding="utf-8") as file_to_write:
|
|
27
|
-
file_to_write.write(content)
|
|
44
|
+
file_to_write.write(content) # 寫入內容 / Write content
|
|
28
45
|
except JEditorSaveFileException:
|
|
46
|
+
# 捕捉自訂例外並重新拋出
|
|
47
|
+
# Catch custom exception and re-raise
|
|
29
48
|
raise JEditorSaveFileException
|
|
30
49
|
finally:
|
|
31
|
-
|
|
50
|
+
# 確保鎖一定會被釋放
|
|
51
|
+
# Ensure the lock is always released
|
|
52
|
+
lock.release()
|
|
@@ -1,48 +1,63 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from threading import Lock
|
|
4
|
-
from typing import Union
|
|
4
|
+
from typing import Union, Any
|
|
5
5
|
|
|
6
|
+
# 匯入自訂錯誤訊息與例外類別
|
|
7
|
+
# Import custom error messages and exception class
|
|
6
8
|
from je_editor.utils.exception.exception_tags import cant_find_json_error
|
|
7
9
|
from je_editor.utils.exception.exception_tags import cant_save_json_error
|
|
8
10
|
from je_editor.utils.exception.exceptions import JEditorJsonException
|
|
9
11
|
from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
10
12
|
|
|
13
|
+
# 全域鎖,確保多執行緒存取 JSON 檔案時的安全性
|
|
14
|
+
# Global lock to ensure thread safety when accessing JSON files
|
|
11
15
|
_lock = Lock()
|
|
12
16
|
|
|
13
17
|
|
|
14
|
-
def read_json(json_file_path: str) ->
|
|
18
|
+
def read_json(json_file_path: str) -> Any | None:
|
|
15
19
|
"""
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
功能說明 (Function Description):
|
|
21
|
+
讀取 JSON 檔案並回傳其內容。
|
|
22
|
+
Read a JSON file and return its content.
|
|
23
|
+
|
|
24
|
+
:param json_file_path: JSON 檔案路徑 / path to the JSON file
|
|
25
|
+
:return: list 或 dict,取決於 JSON 結構 / list or dict depending on JSON structure
|
|
18
26
|
"""
|
|
19
27
|
jeditor_logger.info(f"json_file.py read_json json_file_path: {json_file_path}")
|
|
20
|
-
_lock.acquire()
|
|
28
|
+
_lock.acquire() # 嘗試鎖定資源 / Acquire the lock
|
|
21
29
|
try:
|
|
22
30
|
file_path = Path(json_file_path)
|
|
23
|
-
if file_path.exists() and file_path.is_file():
|
|
24
|
-
with open(json_file_path) as read_file:
|
|
25
|
-
return json.loads(read_file.read())
|
|
31
|
+
if file_path.exists() and file_path.is_file(): # 確認檔案存在且為檔案 / Ensure file exists
|
|
32
|
+
with open(json_file_path) as read_file: # 開啟檔案 (預設 UTF-8)
|
|
33
|
+
return json.loads(read_file.read()) # 載入 JSON 並回傳 / Load JSON and return
|
|
26
34
|
except JEditorJsonException:
|
|
35
|
+
# 捕捉自訂例外並重新拋出
|
|
36
|
+
# Catch custom exception and re-raise
|
|
27
37
|
raise JEditorJsonException(cant_find_json_error)
|
|
28
38
|
finally:
|
|
29
|
-
_lock.release()
|
|
39
|
+
_lock.release() # 確保鎖一定會被釋放 / Ensure the lock is always released
|
|
30
40
|
|
|
31
41
|
|
|
32
42
|
def write_json(json_save_path: str, data_to_output: Union[list, dict]) -> None:
|
|
33
43
|
"""
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
功能說明 (Function Description):
|
|
45
|
+
將資料寫入 JSON 檔案。
|
|
46
|
+
Write data into a JSON file.
|
|
47
|
+
|
|
48
|
+
:param json_save_path: JSON 檔案儲存路徑 / path to save the JSON file
|
|
49
|
+
:param data_to_output: 要輸出的資料 (list 或 dict) / data to output (list or dict)
|
|
37
50
|
"""
|
|
38
51
|
jeditor_logger.info("json_file.py write_json "
|
|
39
52
|
f"json_save_path: {json_save_path} "
|
|
40
53
|
f"data_to_output: {data_to_output}")
|
|
41
|
-
_lock.acquire()
|
|
54
|
+
_lock.acquire() # 嘗試鎖定資源 / Acquire the lock
|
|
42
55
|
try:
|
|
56
|
+
# 以寫入模式開啟檔案,並將資料轉換為 JSON 格式 (縮排 4 格)
|
|
57
|
+
# Open file in write mode and dump data as JSON (indent=4)
|
|
43
58
|
with open(json_save_path, "w+") as file_to_write:
|
|
44
59
|
file_to_write.write(json.dumps(data_to_output, indent=4))
|
|
45
60
|
except JEditorJsonException:
|
|
46
61
|
raise JEditorJsonException(cant_save_json_error)
|
|
47
62
|
finally:
|
|
48
|
-
_lock.release()
|
|
63
|
+
_lock.release() # 確保鎖一定會被釋放 / Ensure the lock is always released
|
|
@@ -3,6 +3,8 @@ import sys
|
|
|
3
3
|
from json import dumps
|
|
4
4
|
from json import loads
|
|
5
5
|
|
|
6
|
+
# 匯入自訂錯誤訊息與例外類別
|
|
7
|
+
# Import custom error messages and exception class
|
|
6
8
|
from je_editor.utils.exception.exception_tags import cant_reformat_json_error
|
|
7
9
|
from je_editor.utils.exception.exception_tags import wrong_json_data_error
|
|
8
10
|
from je_editor.utils.exception.exceptions import JEditorJsonException
|
|
@@ -10,24 +12,53 @@ from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
def __process_json(json_string: str, **kwargs) -> str:
|
|
15
|
+
"""
|
|
16
|
+
功能說明 (Function Description):
|
|
17
|
+
嘗試將輸入的 JSON 字串重新格式化 (pretty print)。
|
|
18
|
+
Try to reformat the input JSON string (pretty print).
|
|
19
|
+
|
|
20
|
+
:param json_string: JSON 格式字串 / JSON formatted string
|
|
21
|
+
:param kwargs: 額外參數傳給 json.dumps / extra arguments for json.dumps
|
|
22
|
+
:return: 格式化後的 JSON 字串 / formatted JSON string
|
|
23
|
+
"""
|
|
13
24
|
try:
|
|
25
|
+
# 嘗試先將字串解析為 JSON,再重新輸出為縮排格式
|
|
26
|
+
# Try to parse string into JSON, then dump with indentation
|
|
14
27
|
return dumps(loads(json_string), indent=4, sort_keys=True, **kwargs)
|
|
15
28
|
except json.JSONDecodeError as error:
|
|
29
|
+
# 如果 JSON 格式錯誤,輸出錯誤訊息到 stderr 並拋出例外
|
|
30
|
+
# If JSON format is invalid, print error to stderr and raise exception
|
|
16
31
|
print(wrong_json_data_error, file=sys.stderr)
|
|
17
32
|
raise error
|
|
18
33
|
except TypeError:
|
|
34
|
+
# 如果輸入不是合法 JSON 字串,嘗試直接將物件轉為 JSON
|
|
35
|
+
# If input is not a valid JSON string, try dumping the object directly
|
|
19
36
|
try:
|
|
20
37
|
return dumps(json_string, indent=4, sort_keys=True, **kwargs)
|
|
21
38
|
except TypeError:
|
|
39
|
+
# 若仍失敗,拋出自訂例外
|
|
40
|
+
# If still fails, raise custom exception
|
|
22
41
|
raise JEditorJsonException(wrong_json_data_error)
|
|
23
42
|
|
|
24
43
|
|
|
25
44
|
def reformat_json(json_string: str, **kwargs) -> str:
|
|
26
|
-
|
|
45
|
+
"""
|
|
46
|
+
功能說明 (Function Description):
|
|
47
|
+
對外提供的 JSON 格式化函式,會呼叫內部的 __process_json。
|
|
48
|
+
Public function to reformat JSON string, calls __process_json internally.
|
|
49
|
+
|
|
50
|
+
:param json_string: JSON 格式字串 / JSON formatted string
|
|
51
|
+
:param kwargs: 額外參數傳給 json.dumps / extra arguments for json.dumps
|
|
52
|
+
:return: 格式化後的 JSON 字串 / formatted JSON string
|
|
53
|
+
"""
|
|
54
|
+
# 記錄日誌,方便除錯與追蹤
|
|
55
|
+
# Log the input string and kwargs for debugging and tracking
|
|
27
56
|
jeditor_logger.info(f"json_process.py reformat_json "
|
|
28
57
|
f"json_string: {json_string} "
|
|
29
58
|
f"kwargs: {kwargs}")
|
|
30
59
|
try:
|
|
31
60
|
return __process_json(json_string, **kwargs)
|
|
32
61
|
except JEditorJsonException:
|
|
33
|
-
|
|
62
|
+
# 捕捉自訂例外並重新拋出
|
|
63
|
+
# Catch custom exception and re-raise
|
|
64
|
+
raise JEditorJsonException(cant_reformat_json_error)
|
|
@@ -1,27 +1,57 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from logging.handlers import RotatingFileHandler
|
|
3
3
|
|
|
4
|
+
# 設定 root logger 的最低層級為 DEBUG
|
|
5
|
+
# Set the root logger level to DEBUG
|
|
4
6
|
logging.root.setLevel(logging.DEBUG)
|
|
7
|
+
|
|
8
|
+
# 建立一個名為 "JEditor" 的 logger
|
|
9
|
+
# Create a logger named "JEditor"
|
|
5
10
|
jeditor_logger = logging.getLogger("JEditor")
|
|
11
|
+
|
|
12
|
+
# 設定 JEditor logger 的層級為 WARNING (只會輸出 WARNING 以上的訊息)
|
|
13
|
+
# Set the JEditor logger level to WARNING (only WARNING and above will be logged)
|
|
6
14
|
jeditor_logger.setLevel(logging.WARNING)
|
|
15
|
+
|
|
16
|
+
# 定義日誌格式:時間 | logger 名稱 | 等級 | 訊息
|
|
17
|
+
# Define log format: time | logger name | level | message
|
|
7
18
|
formatter = logging.Formatter('%(asctime)s | %(name)s | %(levelname)s | %(message)s')
|
|
8
19
|
|
|
20
|
+
|
|
9
21
|
class JEditorLoggingHandler(RotatingFileHandler):
|
|
22
|
+
"""
|
|
23
|
+
自訂的 Logging Handler,繼承自 RotatingFileHandler
|
|
24
|
+
Custom Logging Handler, inherits from RotatingFileHandler
|
|
10
25
|
|
|
11
|
-
|
|
26
|
+
功能:
|
|
27
|
+
- 將日誌輸出到檔案 (支援檔案大小輪替)
|
|
28
|
+
- 預設檔名為 JEditor.log
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
# redirect logging stderr output to queue (註解說明,但目前未實作)
|
|
32
|
+
# 註解提到要將 stderr 輸出導向 queue,但目前程式碼僅繼承 RotatingFileHandler
|
|
12
33
|
|
|
13
34
|
def __init__(self, filename: str = "JEditor.log", mode="w",
|
|
14
|
-
maxBytes:int=1073741824, backupCount:int=0):
|
|
35
|
+
maxBytes: int = 1073741824, backupCount: int = 0):
|
|
36
|
+
"""
|
|
37
|
+
:param filename: 日誌檔案名稱 / log file name
|
|
38
|
+
:param mode: 檔案開啟模式 (預設 w 覆寫) / file open mode (default "w" overwrite)
|
|
39
|
+
:param maxBytes: 單一檔案最大大小 (預設 1GB) / max file size (default 1GB)
|
|
40
|
+
:param backupCount: 保留的備份檔案數量 / number of backup files to keep
|
|
41
|
+
"""
|
|
15
42
|
super().__init__(filename=filename, mode=mode, maxBytes=maxBytes, backupCount=backupCount)
|
|
16
|
-
self.formatter = formatter
|
|
17
|
-
self.setLevel(logging.DEBUG)
|
|
43
|
+
self.formatter = formatter # 設定日誌格式 / set log formatter
|
|
44
|
+
self.setLevel(logging.DEBUG) # 設定 handler 層級為 DEBUG / set handler level to DEBUG
|
|
18
45
|
|
|
19
46
|
def emit(self, record: logging.LogRecord) -> None:
|
|
47
|
+
"""
|
|
48
|
+
實際輸出日誌的方法,這裡直接呼叫父類別的 emit
|
|
49
|
+
Method to emit log records, here just call parent emit
|
|
50
|
+
"""
|
|
20
51
|
super().emit(record)
|
|
21
52
|
|
|
22
53
|
|
|
23
|
-
#
|
|
54
|
+
# 建立檔案處理器並加入到 JEditor logger
|
|
55
|
+
# Create file handler and add it to JEditor logger
|
|
24
56
|
file_handler = JEditorLoggingHandler()
|
|
25
|
-
jeditor_logger.addHandler(file_handler)
|
|
26
|
-
|
|
27
|
-
|
|
57
|
+
jeditor_logger.addHandler(file_handler)
|
|
@@ -4,26 +4,51 @@ from je_editor.utils.multi_language.traditional_chinese import traditional_chine
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class LanguageWrapper(object):
|
|
7
|
+
"""
|
|
8
|
+
功能說明 (Function Description):
|
|
9
|
+
- 提供一個語言包裝器,用來管理目前使用的語言與對應的字典。
|
|
10
|
+
- A language wrapper to manage the current language and its corresponding dictionary.
|
|
11
|
+
"""
|
|
7
12
|
|
|
8
|
-
def __init__(
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
def __init__(self):
|
|
14
|
+
# 初始化時記錄日誌
|
|
15
|
+
# Log initialization
|
|
11
16
|
jeditor_logger.info("Init LanguageWrapper")
|
|
17
|
+
|
|
18
|
+
# 預設語言為 English
|
|
19
|
+
# Default language is English
|
|
12
20
|
self.language: str = "English"
|
|
21
|
+
|
|
22
|
+
# 可選語言字典對照表
|
|
23
|
+
# Mapping of available languages to their word dictionaries
|
|
13
24
|
self.choose_language_dict = {
|
|
14
25
|
"English": english_word_dict,
|
|
15
26
|
"Traditional_Chinese": traditional_chinese_word_dict
|
|
16
27
|
}
|
|
28
|
+
|
|
29
|
+
# 根據目前語言選擇對應字典
|
|
30
|
+
# Select the dictionary based on current language
|
|
17
31
|
self.language_word_dict: dict = self.choose_language_dict.get(self.language)
|
|
18
32
|
|
|
19
33
|
def reset_language(self, language) -> None:
|
|
34
|
+
"""
|
|
35
|
+
重設語言 (Reset the language)
|
|
36
|
+
:param language: "English" 或 "Traditional_Chinese"
|
|
37
|
+
"""
|
|
20
38
|
jeditor_logger.info(f"LanguageWrapper reset_language language: {language}")
|
|
39
|
+
|
|
40
|
+
# 檢查輸入是否為支援的語言
|
|
41
|
+
# Check if the input language is supported
|
|
21
42
|
if language in [
|
|
22
43
|
"English",
|
|
23
44
|
"Traditional_Chinese"
|
|
24
45
|
]:
|
|
46
|
+
# 更新語言與對應字典
|
|
47
|
+
# Update language and corresponding dictionary
|
|
25
48
|
self.language = language
|
|
26
49
|
self.language_word_dict = self.choose_language_dict.get(self.language)
|
|
27
50
|
|
|
28
51
|
|
|
29
|
-
|
|
52
|
+
# 建立一個全域的 LanguageWrapper 實例
|
|
53
|
+
# Create a global instance of LanguageWrapper
|
|
54
|
+
language_wrapper = LanguageWrapper()
|
|
@@ -6,54 +6,90 @@ from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class RedirectStdOut(logging.Handler):
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
"""
|
|
10
|
+
功能說明 (Function Description):
|
|
11
|
+
- 將標準輸出 (stdout) 重導向到 queue
|
|
12
|
+
- Redirect standard output (stdout) to a queue
|
|
13
|
+
"""
|
|
11
14
|
|
|
12
15
|
def __init__(self):
|
|
13
16
|
super().__init__()
|
|
14
17
|
|
|
15
18
|
def write(self, content_to_write) -> None:
|
|
19
|
+
# 將輸出內容放入 RedirectManager 的 stdout queue
|
|
20
|
+
# Put output content into RedirectManager's stdout queue
|
|
16
21
|
redirect_manager_instance.std_out_queue.put(content_to_write)
|
|
17
22
|
|
|
18
23
|
def emit(self, record: logging.LogRecord) -> None:
|
|
24
|
+
# 將 logging 訊息格式化後放入 stdout queue
|
|
25
|
+
# Put formatted logging record into stdout queue
|
|
19
26
|
redirect_manager_instance.std_out_queue.put(self.format(record))
|
|
20
27
|
|
|
21
28
|
|
|
22
29
|
class RedirectStdErr(logging.Handler):
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
"""
|
|
31
|
+
功能說明 (Function Description):
|
|
32
|
+
- 將標準錯誤輸出 (stderr) 重導向到 queue
|
|
33
|
+
- Redirect standard error (stderr) to a queue
|
|
34
|
+
"""
|
|
25
35
|
|
|
26
36
|
def __init__(self):
|
|
27
37
|
super().__init__()
|
|
28
38
|
|
|
29
39
|
def write(self, content_to_write) -> None:
|
|
40
|
+
# 將錯誤輸出內容放入 RedirectManager 的 stderr queue
|
|
41
|
+
# Put error output content into RedirectManager's stderr queue
|
|
30
42
|
redirect_manager_instance.std_err_queue.put(content_to_write)
|
|
31
43
|
|
|
32
44
|
def emit(self, record: logging.LogRecord) -> None:
|
|
45
|
+
# 將 logging 訊息格式化後放入 stderr queue
|
|
46
|
+
# Put formatted logging record into stderr queue
|
|
33
47
|
redirect_manager_instance.std_err_queue.put(self.format(record))
|
|
34
48
|
|
|
35
49
|
|
|
36
50
|
class RedirectManager(object):
|
|
37
|
-
|
|
51
|
+
"""
|
|
52
|
+
功能說明 (Function Description):
|
|
53
|
+
- 管理 stdout 與 stderr 的重導向
|
|
54
|
+
- 提供 set_redirect 與 restore_std 方法
|
|
55
|
+
- Manage redirection of stdout and stderr
|
|
56
|
+
- Provides set_redirect and restore_std methods
|
|
57
|
+
"""
|
|
58
|
+
|
|
38
59
|
def __init__(self):
|
|
39
60
|
jeditor_logger.info("Init RedirectManager")
|
|
61
|
+
# 建立 stdout 與 stderr 的 queue
|
|
62
|
+
# Create queues for stdout and stderr
|
|
40
63
|
self.std_err_queue = queue.Queue()
|
|
41
64
|
self.std_out_queue = queue.Queue()
|
|
42
65
|
|
|
43
66
|
@staticmethod
|
|
44
67
|
def set_redirect() -> None:
|
|
45
68
|
"""
|
|
46
|
-
|
|
69
|
+
啟用重導向
|
|
70
|
+
Redirect stdout and stderr to queues
|
|
47
71
|
"""
|
|
48
72
|
jeditor_logger.info("RedirectManager set_redirect")
|
|
49
73
|
redirect_out = RedirectStdOut()
|
|
50
74
|
redirect_err = RedirectStdErr()
|
|
75
|
+
|
|
76
|
+
# 將 sys.stdout / sys.stderr 指向自訂 handler
|
|
77
|
+
# Redirect sys.stdout / sys.stderr to custom handlers
|
|
51
78
|
sys.stdout = redirect_out
|
|
52
79
|
sys.stderr = redirect_err
|
|
80
|
+
|
|
81
|
+
# 建立一個 logger 並綁定 stderr handler
|
|
82
|
+
# Create a logger and bind stderr handler
|
|
53
83
|
default_logger = logging.getLogger("JEditor_RedirectManager")
|
|
54
84
|
default_logger.addHandler(redirect_err)
|
|
55
|
-
|
|
56
|
-
|
|
85
|
+
|
|
86
|
+
# 過濾掉不需要重導向的 logger
|
|
87
|
+
# Skip specific loggers from being redirected
|
|
88
|
+
skip_logger_list = [
|
|
89
|
+
"JEditor", "FrontEngine",
|
|
90
|
+
"AutomationIDE", "TestPioneer",
|
|
91
|
+
"langchain", "langchain_core", "langchain_openai"
|
|
92
|
+
]
|
|
57
93
|
for name in logging.root.manager.loggerDict.keys():
|
|
58
94
|
if name in skip_logger_list:
|
|
59
95
|
continue
|
|
@@ -63,12 +99,14 @@ class RedirectManager(object):
|
|
|
63
99
|
@staticmethod
|
|
64
100
|
def restore_std() -> None:
|
|
65
101
|
"""
|
|
66
|
-
|
|
67
|
-
|
|
102
|
+
重設 stdout 與 stderr
|
|
103
|
+
Restore stdout and stderr to default
|
|
68
104
|
"""
|
|
69
105
|
jeditor_logger.info("RedirectManager restore_std")
|
|
70
106
|
sys.stdout = sys.__stdout__
|
|
71
107
|
sys.stderr = sys.__stderr__
|
|
72
108
|
|
|
73
109
|
|
|
74
|
-
|
|
110
|
+
# 建立全域 RedirectManager 實例
|
|
111
|
+
# Create a global instance of RedirectManager
|
|
112
|
+
redirect_manager_instance = RedirectManager()
|
|
@@ -1,28 +1,58 @@
|
|
|
1
1
|
import shutil
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
|
+
# 匯入自訂錯誤訊息與例外類別
|
|
5
|
+
# Import custom error messages and exception class
|
|
6
|
+
from je_editor.utils.exception.exception_tags import compiler_not_found_error
|
|
7
|
+
from je_editor.utils.exception.exceptions import JEditorExecException
|
|
8
|
+
from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
import shutil
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
# 匯入自訂錯誤訊息與例外類別
|
|
15
|
+
# Import custom error messages and exception class
|
|
4
16
|
from je_editor.utils.exception.exception_tags import compiler_not_found_error
|
|
5
17
|
from je_editor.utils.exception.exceptions import JEditorExecException
|
|
6
18
|
from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
7
19
|
|
|
8
20
|
|
|
9
21
|
def check_and_choose_venv(venv_path: Path) -> str:
|
|
22
|
+
"""
|
|
23
|
+
功能說明 (Function Description):
|
|
24
|
+
檢查虛擬環境 (venv) 路徑,並嘗試尋找可用的 Python 編譯器。
|
|
25
|
+
Check the virtual environment (venv) path and try to find a usable Python interpreter.
|
|
26
|
+
|
|
27
|
+
:param venv_path: 虛擬環境的路徑 / path to the virtual environment
|
|
28
|
+
:return: Python 編譯器的完整路徑 / full path to the Python interpreter
|
|
29
|
+
:raise JEditorExecException: 若找不到 Python 編譯器 / if no Python interpreter is found
|
|
30
|
+
"""
|
|
31
|
+
|
|
10
32
|
jeditor_logger.info(f"check_venv.py check_and_choose_venv venv_path: {venv_path}")
|
|
11
|
-
|
|
33
|
+
|
|
34
|
+
# 如果 venv_path 是資料夾且存在
|
|
35
|
+
# If venv_path is a directory and exists
|
|
12
36
|
if venv_path.is_dir() and venv_path.exists():
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
37
|
+
# 先嘗試在該路徑下尋找 python3
|
|
38
|
+
# Try to find python3 in the given path
|
|
39
|
+
compiler_path = shutil.which("python3", path=str(venv_path))
|
|
40
|
+
if compiler_path:
|
|
41
|
+
return compiler_path
|
|
42
|
+
|
|
43
|
+
# 如果找不到 python3,再找 python
|
|
44
|
+
# If python3 not found, try python
|
|
45
|
+
compiler_path = shutil.which("python", path=str(venv_path))
|
|
46
|
+
if compiler_path:
|
|
47
|
+
return compiler_path
|
|
48
|
+
|
|
49
|
+
# 如果 venv_path 無效或都找不到,最後再嘗試系統預設的 python3 或 python
|
|
50
|
+
# If venv_path is invalid or no interpreter found, try system default python3 or python
|
|
51
|
+
compiler_path = shutil.which("python3") or shutil.which("python")
|
|
52
|
+
|
|
53
|
+
# 如果還是找不到,拋出例外
|
|
54
|
+
# If still not found, raise exception
|
|
26
55
|
if compiler_path is None:
|
|
27
56
|
raise JEditorExecException(compiler_not_found_error)
|
|
28
|
-
|
|
57
|
+
|
|
58
|
+
return compiler_path
|