diff --git a/app2.py b/app2.py
index 3299b8653d48f48631cb2c7d7d4bf1d3cde2a156..902f4197cc8d59ceaca0321bd648f6a4a6427314 100644
--- a/app2.py
+++ b/app2.py
@@ -39,10 +39,6 @@ def exception_handler(i: 'Tuple[ClassVar[BaseException], BaseException]'):
reinstall_requirements_with_gui()
- # dlg = ExceptionHandlerDialog(i[1])
- #
- # dlg.exec_()
-
def on_exception(e):
from check_dependency import ExceptionHandlerDialog
@@ -66,7 +62,7 @@ os.environ['FORCE_QT_API'] = "1"
from typing import List, Callable, Tuple, ClassVar
from PySide2.QtCore import Signal, QTimer, Qt, QCoreApplication
from PySide2.QtGui import QCloseEvent, QTextCursor, QResizeEvent, QMoveEvent, QFont, QIcon, QPixmap
-from PySide2.QtWidgets import QApplication, QMessageBox, QSplashScreen, QStatusBar
+from PySide2.QtWidgets import QApplication, QMessageBox, QSplashScreen, QStatusBar, QDialog, QVBoxLayout, QProgressBar
import pmgwidgets
pmgwidgets.in_unit_test = lambda: False
@@ -74,10 +70,9 @@ from pmgwidgets import PMGToolBar
from features.extensions.extensions_manager.manager import extensions_manager
from features.main_window import base
-from features.io.settings import Settings
from features.io.settings import load_theme
from features.interpretermanager.interpretermanager import InterpreterManagerWidget
-from features.util.update import perform_update, UpdateTipClient
+from features.util.update import UpdateTipClient
from features.feedback import FeedbackClient
from features.ui.widgets.controlpanel import PMPageExt
from features.ui.pmwidgets import BaseMainWindow
@@ -141,9 +136,8 @@ class MainWindow(BaseMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
-
+ # settings = Settings()
t00 = time.time()
- settings = Settings()
self.main_option_form = base.OptionForm()
self.project_wizard: base.ProjectWizardForm = None
self.settings_changed_signal.connect(self.on_settings_changed)
@@ -155,7 +149,7 @@ class MainWindow(BaseMainWindow):
self.resize(1920, 1080)
# 设置主窗体标题
- self.setWindowTitle('PyMiner ' + utils.version)
+ self.setWindowTitle('PyMiner ' + utils.get_settings_item_from_file("config.ini", "INFO/VERSION", "default"))
# 设置状态栏
self.statusBar = QStatusBar()
@@ -192,7 +186,8 @@ class MainWindow(BaseMainWindow):
dw.setMaximumWidth(400)
# 设置主题 ,组件都加载后再设置主题,否则可能有些组件不生效
- load_theme(settings['theme'])
+ settings = utils.get_settings_from_file("config.ini")
+ load_theme(settings.value("MAIN/THEME"))
self.show()
self.load_layout()
@@ -201,7 +196,7 @@ class MainWindow(BaseMainWindow):
self.on_main_window_shown()
self.start_pmlocalserver() # 只要在插件加载完成之后启动就行,目前放在最后
- self.update_tip_client = UpdateTipClient() # 启动程序,检查更新,弹窗提醒
+ self.update_tip_client = UpdateTipClient(True) # 启动程序,检查更新,弹窗提醒
t01 = time.time()
logging.debug('Time Elapsed for loading main window contents: %f' % (t01 - t00))
@@ -220,7 +215,6 @@ class MainWindow(BaseMainWindow):
a0.accept()
self.delete_temporary_dock_windows()
self.save_layout() # TODO:PySide2上存储布局有问题。
- Settings.get_instance().save()
self.close_signal.emit()
self.extensions_manager.stop()
for k in self.dock_widgets.keys():
@@ -283,7 +277,12 @@ class MainWindow(BaseMainWindow):
self.window_geometry_changed_signal.emit()
def on_settings_changed(self):
- load_theme(Settings.get_instance()['theme'])
+ """
+ 当设置项发生改变时,加载这些设置项。
+ Returns:
+
+ """
+ load_theme(utils.get_settings_from_file("config.ini").value("MAIN/THEME"))
def delayed_call(self, time_ms: int, callback: Callable) -> None:
"""
@@ -329,7 +328,7 @@ class MainWindow(BaseMainWindow):
self.widgets_ready_signal.emit()
t1 = time.time()
logging.info('Layout ready time elapsed:%f' % (t1 - t0))
- self.set_dock_titlebar_visible(Settings.get_instance()['dock_titlebar_visible'])
+ self.set_dock_titlebar_visible(utils.get_settings_item_from_file("config.ini", "MAIN/DOCK_TITLEBAR_VISIBLE"))
self.bind_events()
self.events_ready_signal.emit()
t2 = time.time()
@@ -384,7 +383,25 @@ class MainWindow(BaseMainWindow):
"""
打开'检查更新'页面
"""
- perform_update()
+ dlg = QDialog()
+ dlg.setLayout(QVBoxLayout())
+ proc = QProgressBar()
+ dlg.layout().addWidget(proc)
+ dlg.setWindowTitle("请稍等,正在进行更新检查")
+ dlg.setFixedWidth(500)
+ proc.setRange(0, 0) # 设置进度条忙
+
+ def close(b):
+ if b:
+ dlg.close()
+ else:
+ dlg.close()
+ QMessageBox.information(self, "更新提示", "已经是最新版,无需更新!")
+
+ self.update_tip_client = UpdateTipClient(False)
+ self.update_tip_client.thread.exist_update.connect(close)
+
+ dlg.exec_()
def main_install_update(self):
closed = self.close()
@@ -495,8 +512,9 @@ def main(test_function: Callable[[MainWindow], None] = None):
splash.finish(window)
if test_function is None:
- # 展示快速启动窗口
- window.first_form_display()
+ # 展示快速启动窗口。只有在设置为True的情况下才显示起始页。
+ if utils.get_settings_item_from_file("config.ini", "MAIN/SHOW_START_PAGE"):
+ window.first_form_display()
else:
test_function(window)
logging.info('boot time elapsed:%f s' % (t1 - t0))
diff --git a/configuration/config.ini b/configuration/config.ini
new file mode 100644
index 0000000000000000000000000000000000000000..22e5135ee9c8366c695574694911bb0d2fa4906f
--- /dev/null
+++ b/configuration/config.ini
@@ -0,0 +1,19 @@
+[MAIN]
+THEME = Fusion
+LANGUAGE = zh_CN
+PATH_OUTPUT =
+PATH_WORKDIR =
+INTERPRETER = d:/pyminer/python.exe
+SHOW_START_PAGE = True
+CHECK_UPDATE = True
+DOCK_TITLEBAR_VISIBLE = False
+
+[RUN]
+EXTERNAL_INTERPRETERS = "[]"
+CURRENT_INTERPRETER =
+
+[INFO]
+VERSION = v2.1.4 Beta
+WEBSITE = http://www.pyminer.com
+AUTHOR = PyMiner Development Team
+MAIL = team@py2cn.com
diff --git a/features/extensions/extensionlib/extension_lib.py b/features/extensions/extensionlib/extension_lib.py
index ef22b7f646433b36d4794e7ec3a62e22d6585569..90126d73bbf9236929e8d36101e8b8fcbb14d5ec 100644
--- a/features/extensions/extensionlib/extension_lib.py
+++ b/features/extensions/extensionlib/extension_lib.py
@@ -1,10 +1,12 @@
import inspect
import os
-from typing import TYPE_CHECKING, Callable, Dict, List, Tuple, Union, Optional, Any
-from PySide2.QtCore import QRect, Signal, QTranslator, QLocale
-from PySide2.QtWidgets import QWidget, QApplication, QDialog
-from features.workspace.data_adapter import UniversalAdapter
+from typing import TYPE_CHECKING, Callable, Dict, List, Tuple, Optional, Any
+
+from PySide2.QtCore import QRect, Signal
+from PySide2.QtWidgets import QWidget, QDialog
+
import utils
+from features.workspace.data_adapter import UniversalAdapter
if TYPE_CHECKING:
from pmgwidgets import PMGToolBar
@@ -18,8 +20,6 @@ def wrapper():
from utils import get_main_window
from features.ui import pmwidgets
from features.extensions.extensionlib import baseext
- from features.ui.common.pmlocale import pmlocale
- from features.io.settings import Settings
from features.io.exceptions import PMExceptions
from pyminer_comm.base import DataDesc
@@ -260,42 +260,32 @@ def wrapper():
return utils.get_root_dir()
@staticmethod
- def _(text):
+ def get_settings_item_from_file(file: str, item: str, mode: str = "user"):
"""
-
+ 从设置文件中获取设置项
Args:
- text:
+ file:
+ item:
+ mode:
Returns:
"""
- return pmlocale.translate(text)
+ return utils.get_settings_item_from_file(file, item, mode)
@staticmethod
- def get_settings() -> Dict[str, str]:
- """
-
- Returns:
-
+ def write_settings_item_to_file(file: str, item: str, value: Any):
"""
- return Settings.get_instance()
-
- @staticmethod
- def update_settings(settings_to_modify: Dict[str, str]) -> None:
- """
- 修改设置
+ 将配置项写入设置文件中
Args:
- settings_to_modify:
+ file:
+ item:
+ value:
Returns:
"""
- settings = Settings.get_instance()
- for k, v in settings_to_modify.items():
- if k in settings.keys():
- Settings.get_instance()[k] = v
- else:
- raise ValueError('Key {0} not in Settings!' % k)
+ utils.write_settings_item_to_file(file, item, value)
get_main_window().settings_changed_signal.emit()
@staticmethod
@@ -309,7 +299,7 @@ def wrapper():
Returns:
"""
- Settings.get_instance()['work_dir'] = work_dir
+ utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", work_dir)
get_main_window().settings_changed_signal.emit()
@staticmethod
@@ -321,7 +311,20 @@ def wrapper():
"""
- return Settings.get_instance()['work_dir']
+ dir = utils.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR")
+ if (not isinstance(dir, str)) or (not os.path.exists(dir)):
+ dir = os.path.join(os.path.expanduser("~"), "Desktop")
+ utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", dir)
+ return dir
+
+ @staticmethod
+ def get_theme() -> str:
+ """
+ 获取主题
+ Returns:
+
+ """
+ return utils.get_settings_item_from_file("config.ini", "MAIN/THEME")
@staticmethod
def run_python_file(file_path: str, interpreter_path: str):
diff --git a/features/extensions/extensionlib/extensionlib.md b/features/extensions/extensionlib/extensionlib.md
index 093cc62aba8a6c4523b6b978ca26c830a0b5d1c3..5e5bf1e8a0d90ba36bb5fe22acb43a4cb74fabfa 100644
--- a/features/extensions/extensionlib/extensionlib.md
+++ b/features/extensions/extensionlib/extensionlib.md
@@ -210,7 +210,6 @@ def get_settings() -> Dict[str, str]:
Returns:
"""
-return Settings.get_instance()
### 设置当前工作路径
@staticmethod
diff --git a/features/feedback.py b/features/feedback.py
index 1fe390dc36b6122cb49df3031fc1da494a2b100a..f4a8a03522fab1d6e77b9cdc7b2f43108f26e082 100644
--- a/features/feedback.py
+++ b/features/feedback.py
@@ -4,41 +4,45 @@
# @Email : 2195932461@qq.com
# @File : feedback.py
# @Software: PyCharm
-from PySide2.QtWidgets import QDialog,QTextEdit,QLabel,QVBoxLayout,QApplication,QPushButton,QMessageBox
+import requests
+from PySide2.QtWidgets import QDialog, QTextEdit, QLabel, QVBoxLayout, QApplication, QPushButton, QMessageBox
+
from features.settings import Setting
-import requests,json
+
class FeedbackClient(QDialog):
def __init__(self):
super().__init__()
- self.vbox=QVBoxLayout()
+ self.vbox = QVBoxLayout()
self.setLayout(self.vbox)
- self.text_edit=QTextEdit()
+ self.text_edit = QTextEdit()
self.setWindowTitle(self.tr('Feedback'))
- self.label=QLabel(self.tr('You can give feedback through issue on suggestions or problems encountered in use! (<200 words)'))
- self.confirm_button=QPushButton(self.tr('confirm'))
+ self.label = QLabel(
+ self.tr('You can give feedback through issue on suggestions or problems encountered in use! (<200 words)'))
+ self.confirm_button = QPushButton(self.tr('confirm'))
self.confirm_button.setFixedWidth(75)
self.confirm_button.clicked.connect(self.post)
self.vbox.addWidget(self.label)
self.vbox.addWidget(self.text_edit)
self.vbox.addWidget(self.confirm_button)
setting = Setting()
- self.version=setting.get_system_version()
+ self.version = setting.get_system_version()
self.exec_()
def post(self):
- text=self.text_edit.toPlainText()
- version=self.version
+ text = self.text_edit.toPlainText()
+ version = self.version
url = 'http://www.pyminer.com/api/v1/feedback/'
data = {'core': version, 'feedback': text}
r = requests.post(url, data)
- if r.status_code==201:
- QMessageBox.about(self,self.tr('result'),self.tr('Submitted successfully!'))
+ if r.status_code == 201:
+ QMessageBox.about(self, self.tr('result'), self.tr('Submitted successfully!'))
else:
QMessageBox.warning(self, self.tr('result'), r.text, QMessageBox.Yes)
if __name__ == '__main__':
import sys
- app=QApplication(sys.argv)
- FeedbackClient()
\ No newline at end of file
+
+ app = QApplication(sys.argv)
+ FeedbackClient()
diff --git a/features/interpretermanager/interpretermanager.py b/features/interpretermanager/interpretermanager.py
index 73d1d4f66376c3d6af00c7e462b37cd96aed73a2..3861306dbfb988a15f4a90d4b6b8eaedacc7819b 100644
--- a/features/interpretermanager/interpretermanager.py
+++ b/features/interpretermanager/interpretermanager.py
@@ -7,13 +7,14 @@ settings['interpreters'] =
"""
import os
import sys
-from typing import Dict
+from typing import Dict, List
-from PySide2.QtWidgets import QTableWidget, QPushButton, QHBoxLayout, QVBoxLayout, QApplication, QWidget, QDialog, \
+from PySide2.QtWidgets import QPushButton, QHBoxLayout, QVBoxLayout, QWidget, QDialog, \
QListWidget, QMessageBox, QSpacerItem, QSizePolicy
-from features.io.settings import Settings
+import utils
from pmgwidgets import PMGPanelDialog
+from utils import get_settings_item_from_file
class Interpreter():
@@ -35,6 +36,38 @@ def get_interpreter_version(interpreter_path: str) -> str:
return version
+def get_all_external_interpreters() -> List[Dict]:
+ """
+ 获取所有的外部解释器
+ Returns:
+
+ """
+ return utils.get_settings_item_from_file("config.ini", "RUN/EXTERNAL_INTERPRETERS")
+
+
+def modify_interpreter_config(mode, info: Dict = None, index: int = -1):
+ """
+
+ Args:
+ info: 一个存储解释器信息的字典
+ mode: "add","delete","modify"
+
+ Returns:
+
+ """
+
+ external_interpreters = utils.get_settings_item_from_file("config.ini", "RUN/EXTERNAL_INTERPRETERS")
+ if mode == "add":
+ external_interpreters.append(info)
+ elif mode == "modify":
+ external_interpreters[index] = info
+ elif mode == "delete":
+ external_interpreters.pop(index)
+ else:
+ raise NotImplementedError(mode)
+ utils.write_settings_item_to_file("config.ini", "RUN/EXTERNAL_INTERPRETERS", external_interpreters)
+
+
class InterpreterManagerWidget(QWidget):
def __init__(self, parent=None):
super(InterpreterManagerWidget, self).__init__(parent)
@@ -83,13 +116,15 @@ class InterpreterManagerWidget(QWidget):
if ret == QDialog.Accepted:
res = dlg.get_value()
d = {'name': res['name'], 'path': res['path'], 'version': get_interpreter_version(res['path'])}
- Settings.get_instance()['external_interpreters'].append(d)
+ modify_interpreter_config("add", d)
self.show_interpreters()
def edit(self):
current_index = self.interpreters_list_show.currentRow()
list_index = current_index - 1 # 第一个是默认解释器,所以要减去1
- current_interpreter = Settings.get_instance()['external_interpreters'][list_index]
+
+ external_interpreters = get_all_external_interpreters()
+ current_interpreter = external_interpreters[list_index]
views = [
('line_ctrl', 'name', self.tr('Name'), current_interpreter['name']),
@@ -103,7 +138,7 @@ class InterpreterManagerWidget(QWidget):
if ret == QDialog.Accepted:
res = dlg.get_value()
d = {'name': res['name'], 'path': res['path'], 'version': get_interpreter_version(res['path'])}
- Settings.get_instance()['external_interpreters'][list_index] = d
+ modify_interpreter_config("modify", d, list_index)
self.show_interpreters()
def manage_packages(self):
@@ -126,19 +161,18 @@ class InterpreterManagerWidget(QWidget):
return True
def remove(self):
- Settings.get_instance()['external_interpreters'].pop(
- self.interpreters_list_show.currentRow() - 1) # 第一个是默认解释器,所以要减去1
+ modify_interpreter_config("delete", index=self.interpreters_list_show.currentRow() - 1)
self.show_interpreters()
def show_interpreters(self):
self.interpreters_list_show.clear()
self.interpreters_list_show.addItem(self.tr('BuiltIn (3.8.5)'))
- for interpreter in Settings.get_instance()['external_interpreters']:
+ ext_interpreters = get_all_external_interpreters()
+ for interpreter in ext_interpreters:
name = interpreter['name']
version = interpreter['version']
text = name + ' (%s)' % version
self.interpreters_list_show.addItem(text)
- pass
def on_list_current_item_changed(self):
"""
@@ -158,11 +192,10 @@ class InterpreterManagerWidget(QWidget):
return
else:
list_index = current_index - 1
- return Settings.get_instance()['external_interpreters'][list_index]
+ return get_all_external_interpreters()[list_index]
if __name__ == '__main__':
- s = Settings()
from PySide2.QtWidgets import QApplication
app = QApplication([])
diff --git a/features/io/encoding.py b/features/io/encoding.py
index f36c01dcb7ffed8a860017ef0a22759956ac4a88..caac3288c5d609ed51f90e89b70860d0ddd6073b 100644
--- a/features/io/encoding.py
+++ b/features/io/encoding.py
@@ -1,16 +1,20 @@
import os
+
from PySide2.QtWidgets import QDialog, QPushButton, QVBoxLayout, QHBoxLayout, QTextBrowser, QMessageBox
+
from pmgwidgets import PMGPanel
+import utils
from utils import file_encoding_convert
-from features.io.settings import Settings
class EncodingConversionWidget(QDialog):
def __init__(self, parent=None):
super(EncodingConversionWidget, self).__init__(parent=parent)
views = [
- ('file_ctrl', 'input_file', '读取文件名', '', '', Settings.get_instance()['work_dir']),
- ('file_ctrl', 'output_file', '输出为文件', '', '', Settings.get_instance()['work_dir'],'save'),
+ ('file_ctrl', 'input_file', '读取文件名', '', '',
+ utils.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR")),
+ ('file_ctrl', 'output_file', '输出为文件', '', '',
+ utils.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR"), 'save'),
[
('combo_ctrl', 'input_encoding', '读取编码方式', 'UTF8', ['UTF8', 'GBK', 'ASCII']),
('combo_ctrl', 'output_encoding', '输出编码方式', 'UTF8', ['UTF8', 'GBK', 'ASCII'])
@@ -32,7 +36,6 @@ class EncodingConversionWidget(QDialog):
self.button_preview.clicked.connect(self.preview)
self.button_convert.clicked.connect(self.convert)
- # self.button_preview.clicked.connect(self.preview)
def preview(self):
info = self.panel.get_value()
@@ -55,7 +58,6 @@ class EncodingConversionWidget(QDialog):
if __name__ == '__main__':
- s = Settings()
from PySide2.QtWidgets import QApplication
app = QApplication([])
diff --git a/features/io/settings.py b/features/io/settings.py
index 30b6c6d379dd292fe97bd8794c0ff947abe00a59..6055621639a97eceef2414e2309a2c8d8a81f06e 100644
--- a/features/io/settings.py
+++ b/features/io/settings.py
@@ -1,4 +1,5 @@
"""
+TODO:DEPRECATED。这个文件将被废弃!
settings.py负责设置文件的输入输出。
Settings继承字典类,另外写了存储函数。
还有其他设置的函数
@@ -40,6 +41,7 @@ import platform
from typing import Dict
from PySide2.QtWidgets import QApplication
+
import qdarkstyle
import utils
@@ -49,7 +51,7 @@ logger = logging.getLogger(__name__)
def get_pyminer_data_path() -> str:
path = os.path.join(os.path.expanduser('~'), '.pyminer')
if not os.path.exists(path):
- os.mkdir(path)
+ os.makedirs(path)
return path
@@ -96,73 +98,73 @@ def load_theme(style: str):
# app.setStyle("Windows")
-class Settings(dict):
- """
- 单例!
- """
-
- @classmethod
- def __new__(cls, *args):
- if not hasattr(cls, 'instance'):
- instance = super().__new__(cls)
- cls.instance = instance
- return cls.instance
-
- def __init__(self):
- super(Settings, self).__init__()
- self.check_pyminer_settings_dir()
- self.update(self.load())
-
- def check_pyminer_settings_dir(self):
- self.data_path = get_pyminer_data_path()
- path = os.path.join(self.data_path, 'pyminer_config')
- self.settings_path = path
- if not os.path.exists(path):
- os.mkdir(path)
-
- @staticmethod
- def get_instance() -> 'Settings':
- return Settings.instance
-
- def load(self) -> Dict[str, str]:
- """
- 加载设置项。
- default_settings是默认设置项
- :return:
- """
- with open(os.path.join(utils.get_root_dir(), 'configuration', 'default_settings.json'), 'r') as f:
- default_settings = json.load(f)
- if platform.system().lower() == 'windows':
- default_settings['work_dir'] = os.path.expanduser('~')
- else:
- default_settings['work_dir'] = os.environ['HOME']
- if not os.path.exists(default_settings['work_dir']):
- os.mkdir(default_settings['work_dir'])
-
- try:
- with open(os.path.join(self.settings_path, 'pyminer_settings.json'), 'r') as f:
- settings = json.load(f)
- except BaseException:
- settings = {}
-
- pmsettings = default_settings
- pmsettings.update(settings)
- if not os.path.exists(pmsettings['work_dir']):
- pmsettings['work_dir'] = os.path.expanduser('~')
- return pmsettings
-
- def save(self):
- """
- 保存
- :return:
- """
- import json
- try:
- config_file = os.path.join(self.settings_path, 'pyminer_settings.json')
- with open(config_file, 'w') as f:
- json.dump(self, f, indent=4)
- except FileNotFoundError as e:
- logging.warning(e)
+# class Settings(dict):
+# """
+# 单例!
+# """
+#
+# @classmethod
+# def __new__(cls, *args):
+# if not hasattr(cls, 'instance'):
+# instance = super().__new__(cls)
+# cls.instance = instance
+# return cls.instance
+#
+# def __init__(self):
+# super(Settings, self).__init__()
+# self.check_pyminer_settings_dir()
+# self.update(self.load())
+#
+# def check_pyminer_settings_dir(self):
+# self.data_path = get_pyminer_data_path()
+# path = os.path.join(self.data_path, 'pyminer_config')
+# self.settings_path = path
+# if not os.path.exists(path):
+# os.mkdir(path)
+#
+# @staticmethod
+# def get_instance() -> 'Settings':
+# return Settings.instance
+#
+# def load(self) -> Dict[str, str]:
+# """
+# 加载设置项。
+# default_settings是默认设置项
+# :return:
+# """
+# with open(os.path.join(utils.get_root_dir(), 'configuration', 'default_settings.json'), 'r') as f:
+# default_settings = json.load(f)
+# if platform.system().lower() == 'windows':
+# default_settings['work_dir'] = os.path.expanduser('~')
+# else:
+# default_settings['work_dir'] = os.environ['HOME']
+# if not os.path.exists(default_settings['work_dir']):
+# os.mkdir(default_settings['work_dir'])
+#
+# try:
+# with open(os.path.join(self.settings_path, 'pyminer_settings.json'), 'r') as f:
+# settings = json.load(f)
+# except BaseException:
+# settings = {}
+#
+# pmsettings = default_settings
+# pmsettings.update(settings)
+# if not os.path.exists(pmsettings['work_dir']):
+# pmsettings['work_dir'] = os.path.expanduser('~')
+# return pmsettings
+#
+# def save(self):
+# """
+# 保存
+# :return:
+# """
+# import json
+# try:
+# config_file = os.path.join(self.settings_path, 'pyminer_settings.json')
+# with open(config_file, 'w') as f:
+# json.dump(self, f, indent=4)
+# except FileNotFoundError as e:
+# logging.warning(e)
if __name__ == '__main__':
diff --git a/features/main_window/base.py b/features/main_window/base.py
index b3555ecabc3717f56f31c84b176bb9baaafea449..32b23dbf411cecdbc88508424c52f5ae90133811 100644
--- a/features/main_window/base.py
+++ b/features/main_window/base.py
@@ -1,36 +1,37 @@
+import base64
+import json
+import logging
import os
import sys
import time
-import subprocess
import webbrowser
-import base64
-import json
-from typing import Tuple, List
+from multiprocessing import shared_memory
+from typing import List
import qdarkstyle
from PySide2.QtCore import QPoint, QRectF
from PySide2.QtGui import QMouseEvent, QPainter, QLinearGradient, QCursor
from PySide2.QtGui import QCloseEvent
from PySide2.QtCore import Signal, Qt, QUrl, QPropertyAnimation
-from PySide2.QtWidgets import QApplication, QListWidgetItem, QWizard, QHeaderView, QMessageBox
+from PySide2.QtGui import QCloseEvent
+from PySide2.QtGui import QMouseEvent
from PySide2.QtWebEngineWidgets import *
+from PySide2.QtWidgets import QListWidgetItem, QWizard, QMessageBox
from PySide2.QtWidgets import QWidget, QDesktopWidget, QFileDialog, QApplication, QDialog
-from pmgwidgets import PMGPanel
-
-from features.ui.ui_option import Ui_Form as Option_Ui_Form
-from features.ui.ui_appstore import Ui_Form as appStore_Ui_Form
+import utils
+from features.extensions.extensionlib.extension_lib import extension_lib
from features.ui.ui_aboutme import Ui_Form as About_Ui_Form
-from features.ui.ui_project_wizard import Ui_Wizard as Project_Ui_Form
+from features.ui.ui_appstore import Ui_Form as appStore_Ui_Form
from features.ui.ui_first_form import Ui_Form as first_Ui_Form
from features.ui.ui_login import Ui_Form as login_Ui_Form
from features.ui.ui_logined import Ui_Form as logined_Ui_Form
-import utils
+from features.ui.ui_option import Ui_Form as Option_Ui_Form
+from features.ui.ui_project_wizard import Ui_Wizard as Project_Ui_Form
+from pmgwidgets import PMGPanel
from utils import get_main_window, http_client
-from features.io.settings import Settings
-from features.extensions.extensionlib.extension_lib import extension_lib
-from multiprocessing import shared_memory
+logger = logging.getLogger(__name__)
class OptionForm(QDialog, Option_Ui_Form):
@@ -59,21 +60,12 @@ class OptionForm(QDialog, Option_Ui_Form):
self.pushButton_cancel.clicked.connect(self.close)
self.pushButton_ok.clicked.connect(self.close)
self.pushButton_help.clicked.connect(self.get_help)
- self.get_check_update()
-
- def get_check_update(self):
- """是否启动检查更新"""
- check_update = Settings.get_instance().get('check_update')
- if check_update is None:
- self.checkBox.setChecked(True) # 默认检查更新
- else:
- self.checkBox.setChecked(check_update)
def setup_ui(self):
self.comboBox_9.setEnabled(False)
self.comboBox_8.setEnabled(False)
- self.checkBox_2.setEnabled(False)
- self.checkBox_minitray.setEnabled(False)
+ # self.checkbox_show_startpage.setEnabled(False)
+ # self.checkBox_minitray.setEnabled(False)
def add_settings_panel(self, text: str, settings_content: List):
settings_widget = PMGPanel(views=settings_content)
@@ -116,15 +108,17 @@ class OptionForm(QDialog, Option_Ui_Form):
"""
from features.io.settings import load_theme
load_theme(style)
-
- Settings.get_instance()['theme'] = self.comboBox_theme.currentText()
- # print(Settings.get_instance()['theme'])
+ utils.write_settings_item_to_file("config.ini", "MAIN/THEME", self.comboBox_theme.currentText())
get_main_window().settings_changed_signal.emit()
- # get_main_window().on_settings_changed()
- # self.signal_settings_changed.emit()
def slot_change_workspace(self):
- directory = QFileDialog.getExistingDirectory(self, "选择工作路径位置", directory=Settings.get_instance()['work_dir'])
+ """
+ 改变工作路径时的回调
+ Returns:
+
+ """
+ work_dir = utils.get_settings_item_from_file("config.ini", "MAIN/THEME", self.comboBox_theme.currentText())
+ directory = QFileDialog.getExistingDirectory(self, "选择工作路径位置", directory=work_dir)
if not directory == '':
self.lineEdit_worksapce.setText(directory)
@@ -138,22 +132,32 @@ class OptionForm(QDialog, Option_Ui_Form):
从而每次重新显示的时候都可以刷新数据。
:return:
"""
- settings = Settings.get_instance()
- if settings.get('theme') is not None:
+ settings = utils.get_settings_from_file("config.ini")
+ logger.debug("PATH/WORKDIR", settings.value('MAIN/PATH_WORKDIR'))
+ if settings.value('MAIN/THEME') is not None:
for i in range(self.comboBox_theme.count()):
- if self.comboBox_theme.itemText(i) == settings['theme']:
+ if self.comboBox_theme.itemText(i) == settings.value('MAIN/THEME'):
self.comboBox_theme.setCurrentIndex(i)
- self.lineEdit_worksapce.setText(settings['work_dir'])
+ self.lineEdit_worksapce.setText(settings.value("MAIN/PATH_WORKDIR"))
+ self.lineEdit_output.setText(settings.value("MAIN/PATH_OUTPUT"))
+
+ check_update = utils.get_settings_item_from_file("config.ini", "MAIN/CHECK_UPDATE")
+ show_start_page = utils.get_settings_item_from_file("config.ini", "MAIN/SHOW_START_PAGE")
+ self.check_box_check_upd_on_startup.setChecked(check_update)
+ self.checkbox_show_startpage.setChecked(show_start_page)
def refresh_settings(self):
"""
窗口关闭时,调用此方法,刷新主界面设置项。
:return:
"""
- settings = Settings.get_instance()
- settings['work_dir'] = self.lineEdit_worksapce.text()
- settings['theme'] = self.comboBox_theme.currentText()
- settings['check_update'] = self.checkBox.isChecked() # 设置是否检查更新
+ utils.write_settings_item_to_file("config.ini", "MAIN/THEME", self.comboBox_theme.currentText())
+ utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", self.lineEdit_worksapce.text())
+ utils.write_settings_item_to_file("config.ini", "MAIN/PATH_OUTPUT", self.lineEdit_output.text())
+ utils.write_settings_item_to_file("config.ini", "MAIN/CHECK_UPDATE",
+ self.check_box_check_upd_on_startup.isChecked())
+ utils.write_settings_item_to_file("config.ini", "MAIN/SHOW_START_PAGE",
+ self.checkbox_show_startpage.isChecked())
get_main_window().on_settings_changed()
self.signal_settings_changed.emit()
@@ -216,10 +220,28 @@ class AppstoreForm(QWidget, appStore_Ui_Form):
class AboutForm(QWidget, About_Ui_Form):
+ """
+ 关于 弹出框
+
+ """
+
def __init__(self):
super(AboutForm, self).__init__()
self.setupUi(self)
self.center()
+ AUTHOR = utils.get_settings_item_from_file("config.ini", "INFO/AUTHOR", "default")
+ MAIL = utils.get_settings_item_from_file("config.ini", "INFO/MAIL", "default")
+ self.textedit_about.setMarkdown("""# PyMiner
+PyMiner 是一款基于Python的开源、跨平台数据分析环境。它以方便Python初学者为己任,在Python的知识理论和工作实践之间搭建桥梁,竭诚为初学者服务。
+- PyMiner开箱即用,大大减少配置解释器环境的繁琐性。不仅提供了编程运行的功能,还能够以交互式的形式进行常见的数据分析操作,减少代码编写和文档查阅的时间。
+- PyMiner通过加载各种插件实现不同的需求,开发者可以通过编写插件,将PyMiner扩展的更强大、更趁手,甚至创建一番自己的商用程序。
+- PyMiner提供面向新手的快速入门教程,教程正由开发团队编写中。
+- 我们诚挚希望与Python培训或教育机构/个人合作,让我们的产品帮助到更多学习Python的人。
+
+作者:{AUTHOR}
+
+邮箱:{MAIL}
+""".format(AUTHOR=AUTHOR, MAIL=MAIL))
self.main_about_display()
@@ -246,6 +268,7 @@ class AboutForm(QWidget, About_Ui_Form):
system_info = '系统信息: ' + platform.platform() + ' ' + platform.architecture()[0]
cpu_info = 'CPU信息: ' + platform.processor()
self.feedback.setPlainText(python_info + '\n' + system_info + '\n' + cpu_info)
+ self.label_version_show.setText(utils.get_settings_item_from_file("config.ini", "INFO/VERSION", "default"))
class ProjectWizardForm(QWizard, Project_Ui_Form):
@@ -603,6 +626,7 @@ class LoginForm(QDialog, login_Ui_Form):
"""
登录窗口
"""
+
def __init__(self, parent=None):
super(LoginForm, self).__init__(parent)
self.setupUi(self)
@@ -694,7 +718,7 @@ class LoginedForm(QDialog, logined_Ui_Form):
shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token
buff = shared_memo.buf
for i in range(0, len(buff)):
- buff[i:i+1] = "\x00".encode()
+ buff[i:i + 1] = "\x00".encode()
time.sleep(0.5)
self.close()
diff --git a/features/ui/pmwidgets/pmmainwindow.py b/features/ui/pmwidgets/pmmainwindow.py
index 0c2060b101f690193c0ad2c502ecfe5e11d09273..f74385011a4f01ee39ee5adf2e8e15e1e2fe2b15 100644
--- a/features/ui/pmwidgets/pmmainwindow.py
+++ b/features/ui/pmwidgets/pmmainwindow.py
@@ -20,15 +20,15 @@ import chardet
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QMainWindow, QToolBar, QPushButton, QWidget, QMenu, QDialog
-from pmgwidgets import TopToolBarRight
-from features.io.settings import Settings
-from features.ui.common.pmlocale import pmlocale
import utils
+from features.ui.common.pmlocale import pmlocale
+from pmgwidgets import TopToolBarRight
if TYPE_CHECKING:
from app2 import PMToolBarHome
from features.ui.pmwidgets.dockwidget import PMDockWidget
from pmgwidgets import ActionWithMessage
+logger = logging.getLogger(__name__)
class BaseMainWindow(QMainWindow):
@@ -63,7 +63,7 @@ class BaseMainWindow(QMainWindow):
else:
for k, w in self.dock_widgets.items():
w.setTitleBarWidget(QWidget())
- Settings.get_instance()['dock_titlebar_visible'] = show
+ utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", show)
@staticmethod
def get_stylesheet(style_sheet_name: str = 'standard'):
@@ -82,9 +82,9 @@ class BaseMainWindow(QMainWindow):
enc = chardet.detect(b)
if enc.get('encoding') is not None:
s = b.decode(enc['encoding'])
- style_sheet = s.replace(
- 'MAIN_THEME', Settings.get_instance()['main_theme']).replace(
- 'MARGIN_THEME', Settings.get_instance()['margin_theme'])
+ style_sheet = s
+ else:
+ logger.fatal("加载样式表%s失败!" % style_sheet_name)
return style_sheet
def init_toolbar_tab(self):
@@ -175,7 +175,13 @@ class BaseMainWindow(QMainWindow):
self.refresh_toolbar_hide_button_status()
def save_layout(self):
- layout_path = os.path.join(Settings.get_instance().settings_path, 'layout.ini')
+ """
+ 当关闭程序时保存布局
+ Returns:
+
+ """
+ cfg_dir = utils.get_user_config_dir()
+ layout_path = os.path.join(cfg_dir, 'layout.ini')
try:
with open(layout_path, 'wb') as f:
s = b'' # self.saveState()
@@ -184,7 +190,7 @@ class BaseMainWindow(QMainWindow):
logging.warning("file not found:" + layout_path)
def load_layout(self):
- p = os.path.join(Settings.get_instance().settings_path, 'layout.ini')
+ # p = os.path.join(Settings.get_instance().settings_path, 'layout.ini')
# if os.path.exists(p):
# with open(p, 'rb') as f:
@@ -310,7 +316,8 @@ class BaseMainWindow(QMainWindow):
parent=home_toolbar,
message='lock_layout')
a.setCheckable(True)
- a.setChecked(not Settings.get_instance()['dock_titlebar_visible'])
+ dock_title_visible = utils.get_settings_item_from_file("config.ini", "MAIN/DOCK_TITLEBAR_VISIBLE")
+ a.setChecked(not dock_title_visible)
menu.addAction(a)
home_toolbar.get_control_widget('view_config').setMenu(menu)
self._view_config_menu = menu
diff --git a/features/ui/ui_aboutme.py b/features/ui/ui_aboutme.py
index df648fe94b20549aee51d91c55513e7fc45f3336..878455db4b2d2ee3b865a69d79e17fb0b31031b1 100644
--- a/features/ui/ui_aboutme.py
+++ b/features/ui/ui_aboutme.py
@@ -47,6 +47,7 @@ class Ui_Form(object):
font1.setFamily(u"Microsoft YaHei UI")
font1.setPointSize(24)
font1.setBold(True)
+ font1.setWeight(75)
self.label.setFont(font1)
self.label.setScaledContents(True)
self.label.setAlignment(Qt.AlignCenter)
@@ -62,12 +63,12 @@ class Ui_Form(object):
self.horizontalLayout.addWidget(self.label_2)
- self.label_6 = QLabel(Form)
- self.label_6.setObjectName(u"label_6")
- self.label_6.setFont(font2)
- self.label_6.setAlignment(Qt.AlignBottom|Qt.AlignHCenter)
+ self.label_version_show = QLabel(Form)
+ self.label_version_show.setObjectName(u"label_version_show")
+ self.label_version_show.setFont(font2)
+ self.label_version_show.setAlignment(Qt.AlignBottom|Qt.AlignHCenter)
- self.horizontalLayout.addWidget(self.label_6)
+ self.horizontalLayout.addWidget(self.label_version_show)
self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
@@ -88,12 +89,12 @@ class Ui_Form(object):
self.verticalLayout_2.setSpacing(0)
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
- self.plainTextEdit = QPlainTextEdit(self.tab)
- self.plainTextEdit.setObjectName(u"plainTextEdit")
- self.plainTextEdit.setFont(font3)
- self.plainTextEdit.setFrameShape(QFrame.NoFrame)
+ self.textedit_about = QTextEdit(self.tab)
+ self.textedit_about.setObjectName(u"textedit_about")
+ self.textedit_about.setFont(font3)
+ self.textedit_about.setFrameShape(QFrame.NoFrame)
- self.verticalLayout_2.addWidget(self.plainTextEdit)
+ self.verticalLayout_2.addWidget(self.textedit_about)
self.tabWidget.addTab(self.tab, "")
self.tab_2 = QWidget()
@@ -163,11 +164,7 @@ class Ui_Form(object):
self.label_3.setText("")
self.label.setText(QCoreApplication.translate("Form", u"PyMiner", None))
self.label_2.setText(QCoreApplication.translate("Form", u"Version:", None))
- self.label_6.setText(QCoreApplication.translate("Form", u"v2.0 Beta", None))
- self.plainTextEdit.setPlainText(QCoreApplication.translate("Form", u"PyMiner is a mathematical tool based on Python. It provides solutions to various of problems by loading different plugins. \n"
-"\n"
-"Author\uff1aPyMiner Development Team\n"
-"E-Mail\uff1ateam@py2cn.com", None))
+ self.label_version_show.setText(QCoreApplication.translate("Form", u"v2.0 Beta", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), QCoreApplication.translate("Form", u"About", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QCoreApplication.translate("Form", u"System", None))
self.plainTextEdit_2.setPlainText(QCoreApplication.translate("Form", u"\u4faf\u5c55\u610f\n"
diff --git a/features/ui/ui_aboutme.ui b/features/ui/ui_aboutme.ui
index d5ff050725e927202a1525656abe080e4e642896..747bd4a4577215361299eb1614f077c6b0daef82 100644
--- a/features/ui/ui_aboutme.ui
+++ b/features/ui/ui_aboutme.ui
@@ -64,7 +64,7 @@
- :/logo/icons/logo.png
+ :/logo/icons/logo.png
true
@@ -77,6 +77,7 @@
Microsoft YaHei UI
24
+ 75
true
@@ -107,7 +108,7 @@
-
-
+
黑体
@@ -168,7 +169,7 @@
0
-
-
+
黑体
@@ -178,12 +179,6 @@
QFrame::NoFrame
-
- PyMiner is a mathematical tool based on Python. It provides solutions to various of problems by loading different plugins.
-
-Author:PyMiner Development Team
-E-Mail:team@py2cn.com
-
@@ -282,7 +277,7 @@ houxinluo
- :/images/images/weixin.png
+ :/images/images/weixin.png
true
@@ -295,7 +290,7 @@ houxinluo
- :/images/images/zhifubao.png
+ :/images/images/zhifubao.png
true
diff --git a/features/ui/ui_option.py b/features/ui/ui_option.py
index 38cf32e715464be3eb4c9ffb9499a9f86c85e63f..7340b2170d05daae177441a84b475dbf2e3b1520 100644
--- a/features/ui/ui_option.py
+++ b/features/ui/ui_option.py
@@ -46,50 +46,24 @@ class Ui_Form(object):
self.verticalLayout_8.setObjectName(u"verticalLayout_8")
self.formLayout_2 = QFormLayout()
self.formLayout_2.setObjectName(u"formLayout_2")
- self.label = QLabel(self.tabBase)
- self.label.setObjectName(u"label")
-
- self.formLayout_2.setWidget(1, QFormLayout.LabelRole, self.label)
-
- self.label_15 = QLabel(self.tabBase)
- self.label_15.setObjectName(u"label_15")
-
- self.formLayout_2.setWidget(2, QFormLayout.LabelRole, self.label_15)
-
- self.checkBox = QCheckBox(self.tabBase)
- self.checkBox.setObjectName(u"checkBox")
- self.checkBox.setChecked(True)
-
- self.formLayout_2.setWidget(5, QFormLayout.LabelRole, self.checkBox)
-
- self.checkBox_2 = QCheckBox(self.tabBase)
- self.checkBox_2.setObjectName(u"checkBox_2")
-
- self.formLayout_2.setWidget(7, QFormLayout.LabelRole, self.checkBox_2)
-
- self.label_16 = QLabel(self.tabBase)
- self.label_16.setObjectName(u"label_16")
-
- self.formLayout_2.setWidget(3, QFormLayout.LabelRole, self.label_16)
-
- self.comboBox_9 = QComboBox(self.tabBase)
- self.comboBox_9.addItem("")
- self.comboBox_9.addItem("")
- self.comboBox_9.setObjectName(u"comboBox_9")
+ self.label_theme = QLabel(self.tabBase)
+ self.label_theme.setObjectName(u"label_theme")
- self.formLayout_2.setWidget(3, QFormLayout.FieldRole, self.comboBox_9)
+ self.formLayout_2.setWidget(0, QFormLayout.LabelRole, self.label_theme)
- self.label_11 = QLabel(self.tabBase)
- self.label_11.setObjectName(u"label_11")
+ self.comboBox_theme = QComboBox(self.tabBase)
+ self.comboBox_theme.addItem("")
+ self.comboBox_theme.addItem("")
+ self.comboBox_theme.addItem("")
+ self.comboBox_theme.addItem("")
+ self.comboBox_theme.setObjectName(u"comboBox_theme")
- self.formLayout_2.setWidget(4, QFormLayout.LabelRole, self.label_11)
+ self.formLayout_2.setWidget(0, QFormLayout.FieldRole, self.comboBox_theme)
- self.comboBox_8 = QComboBox(self.tabBase)
- self.comboBox_8.addItem("")
- self.comboBox_8.addItem("")
- self.comboBox_8.setObjectName(u"comboBox_8")
+ self.label = QLabel(self.tabBase)
+ self.label.setObjectName(u"label")
- self.formLayout_2.setWidget(4, QFormLayout.FieldRole, self.comboBox_8)
+ self.formLayout_2.setWidget(1, QFormLayout.LabelRole, self.label)
self.horizontalLayout_14 = QHBoxLayout()
self.horizontalLayout_14.setObjectName(u"horizontalLayout_14")
@@ -106,6 +80,11 @@ class Ui_Form(object):
self.formLayout_2.setLayout(1, QFormLayout.FieldRole, self.horizontalLayout_14)
+ self.label_15 = QLabel(self.tabBase)
+ self.label_15.setObjectName(u"label_15")
+
+ self.formLayout_2.setWidget(2, QFormLayout.LabelRole, self.label_15)
+
self.horizontalLayout_15 = QHBoxLayout()
self.horizontalLayout_15.setObjectName(u"horizontalLayout_15")
self.lineEdit_output = QLineEdit(self.tabBase)
@@ -121,25 +100,41 @@ class Ui_Form(object):
self.formLayout_2.setLayout(2, QFormLayout.FieldRole, self.horizontalLayout_15)
- self.label_theme = QLabel(self.tabBase)
- self.label_theme.setObjectName(u"label_theme")
+ self.label_16 = QLabel(self.tabBase)
+ self.label_16.setObjectName(u"label_16")
- self.formLayout_2.setWidget(0, QFormLayout.LabelRole, self.label_theme)
+ self.formLayout_2.setWidget(3, QFormLayout.LabelRole, self.label_16)
- self.comboBox_theme = QComboBox(self.tabBase)
- self.comboBox_theme.addItem("")
- self.comboBox_theme.addItem("")
- self.comboBox_theme.addItem("")
- self.comboBox_theme.addItem("")
- self.comboBox_theme.setObjectName(u"comboBox_theme")
+ self.comboBox_9 = QComboBox(self.tabBase)
+ self.comboBox_9.addItem("")
+ self.comboBox_9.addItem("")
+ self.comboBox_9.setObjectName(u"comboBox_9")
- self.formLayout_2.setWidget(0, QFormLayout.FieldRole, self.comboBox_theme)
+ self.formLayout_2.setWidget(3, QFormLayout.FieldRole, self.comboBox_9)
- self.checkBox_minitray = QCheckBox(self.tabBase)
- self.checkBox_minitray.setObjectName(u"checkBox_minitray")
- self.checkBox_minitray.setChecked(True)
+ self.label_11 = QLabel(self.tabBase)
+ self.label_11.setObjectName(u"label_11")
- self.formLayout_2.setWidget(6, QFormLayout.LabelRole, self.checkBox_minitray)
+ self.formLayout_2.setWidget(4, QFormLayout.LabelRole, self.label_11)
+
+ self.comboBox_8 = QComboBox(self.tabBase)
+ self.comboBox_8.addItem("")
+ self.comboBox_8.addItem("")
+ self.comboBox_8.setObjectName(u"comboBox_8")
+
+ self.formLayout_2.setWidget(4, QFormLayout.FieldRole, self.comboBox_8)
+
+ self.check_box_check_upd_on_startup = QCheckBox(self.tabBase)
+ self.check_box_check_upd_on_startup.setObjectName(u"check_box_check_upd_on_startup")
+ self.check_box_check_upd_on_startup.setChecked(True)
+
+ self.formLayout_2.setWidget(5, QFormLayout.LabelRole, self.check_box_check_upd_on_startup)
+
+ self.checkbox_show_startpage = QCheckBox(self.tabBase)
+ self.checkbox_show_startpage.setObjectName(u"checkbox_show_startpage")
+ self.checkbox_show_startpage.setChecked(True)
+
+ self.formLayout_2.setWidget(6, QFormLayout.LabelRole, self.checkbox_show_startpage)
self.verticalLayout_8.addLayout(self.formLayout_2)
@@ -354,7 +349,7 @@ class Ui_Form(object):
self.retranslateUi(Form)
- self.stackedWidget.setCurrentIndex(2)
+ self.stackedWidget.setCurrentIndex(0)
self.tabWidget.setCurrentIndex(0)
@@ -374,10 +369,16 @@ class Ui_Form(object):
___qlistwidgetitem2.setText(QCoreApplication.translate("Form", u"\u683c\u5f0f\u5316", None));
self.listWidget.setSortingEnabled(__sortingEnabled)
+ self.label_theme.setText(QCoreApplication.translate("Form", u"UI Theme", None))
+ self.comboBox_theme.setItemText(0, QCoreApplication.translate("Form", u"Fusion", None))
+ self.comboBox_theme.setItemText(1, QCoreApplication.translate("Form", u"Qdarkstyle", None))
+ self.comboBox_theme.setItemText(2, QCoreApplication.translate("Form", u"windowsvista", None))
+ self.comboBox_theme.setItemText(3, QCoreApplication.translate("Form", u"Windows", None))
+
self.label.setText(QCoreApplication.translate("Form", u"Work Directory", None))
+ self.toolButton_workspace.setText(QCoreApplication.translate("Form", u"...", None))
self.label_15.setText(QCoreApplication.translate("Form", u"Output Directory", None))
- self.checkBox.setText(QCoreApplication.translate("Form", u"Check upd on startup", None))
- self.checkBox_2.setText(QCoreApplication.translate("Form", u"Start with system", None))
+ self.toolButton_output.setText(QCoreApplication.translate("Form", u"...", None))
self.label_16.setText(QCoreApplication.translate("Form", u"UI Language", None))
self.comboBox_9.setItemText(0, QCoreApplication.translate("Form", u"\u7b80\u4f53\u4e2d\u6587", None))
self.comboBox_9.setItemText(1, QCoreApplication.translate("Form", u"English", None))
@@ -386,15 +387,8 @@ class Ui_Form(object):
self.comboBox_8.setItemText(0, QCoreApplication.translate("Form", u"utf-8", None))
self.comboBox_8.setItemText(1, QCoreApplication.translate("Form", u"gb2312", None))
- self.toolButton_workspace.setText(QCoreApplication.translate("Form", u"...", None))
- self.toolButton_output.setText(QCoreApplication.translate("Form", u"...", None))
- self.label_theme.setText(QCoreApplication.translate("Form", u"UI Theme", None))
- self.comboBox_theme.setItemText(0, QCoreApplication.translate("Form", u"Fusion", None))
- self.comboBox_theme.setItemText(1, QCoreApplication.translate("Form", u"Qdarkstyle", None))
- self.comboBox_theme.setItemText(2, QCoreApplication.translate("Form", u"windowsvista", None))
- self.comboBox_theme.setItemText(3, QCoreApplication.translate("Form", u"Windows", None))
-
- self.checkBox_minitray.setText(QCoreApplication.translate("Form", u"Minimize to tray", None))
+ self.check_box_check_upd_on_startup.setText(QCoreApplication.translate("Form", u"Check upd on startup", None))
+ self.checkbox_show_startpage.setText(QCoreApplication.translate("Form", u"\u663e\u793a\u8d77\u59cb\u9875\u9762", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabBase), QCoreApplication.translate("Form", u"Basic", None))
self.checkBox_3.setText(QCoreApplication.translate("Form", u"Interlaced coloring", None))
self.label_10.setText(QCoreApplication.translate("Form", u"Table Header Background:", None))
@@ -441,7 +435,7 @@ class Ui_Form(object):
self.label_8.setText(QCoreApplication.translate("Form", u"\u8d27\u5e01\u7b26\u53f7\u4f4d\u4e8e:", None))
self.pushButton_help.setText(QCoreApplication.translate("Form", u"Help", None))
- self.pushButton_ok.setText(QCoreApplication.translate("Form", u"Ok", None))
+ self.pushButton_ok.setText(QCoreApplication.translate("Form", u"OK", None))
self.pushButton_cancel.setText(QCoreApplication.translate("Form", u"Cancel", None))
# retranslateUi
diff --git a/features/ui/ui_option.ui b/features/ui/ui_option.ui
index addaebe83857f069a47dc9bf2f462b207033d59b..f9394124cfd07d880f577bf506eea314a30dcdd7 100644
--- a/features/ui/ui_option.ui
+++ b/features/ui/ui_option.ui
@@ -44,7 +44,7 @@
- 2
+ 0
@@ -75,79 +75,44 @@
-
-
-
-
-
- Work Directory
-
-
-
- -
-
-
- Output Directory
-
-
-
- -
-
-
- Check upd on startup
-
-
- true
-
-
-
- -
-
-
- Start with system
-
-
-
- -
-
+
-
+
- UI Language
+ UI Theme
- -
-
+
-
+
-
- 简体中文
+ Fusion
-
- English
+ Qdarkstyle
-
-
- -
-
-
- Encoding
-
-
-
- -
-
-
- utf-8
+ windowsvista
-
- gb2312
+ Windows
+ -
+
+
+ Work Directory
+
+
+
-
-
@@ -162,6 +127,13 @@
+ -
+
+
+ Output Directory
+
+
+
-
-
@@ -176,41 +148,62 @@
- -
-
+
-
+
- UI Theme
+ UI Language
- -
-
+
-
+
-
- Fusion
+ 简体中文
-
- Qdarkstyle
+ English
+
+
+ -
+
+
+ Encoding
+
+
+
+ -
+
-
- windowsvista
+ utf-8
-
- Windows
+ gb2312
+ -
+
+
+ Check upd on startup
+
+
+ true
+
+
+
-
-
+
- Minimize to tray
+ 显示起始页面
true
@@ -569,7 +562,7 @@ p, li { white-space: pre-wrap; }
-
- Ok
+ OK
diff --git a/features/util/update.py b/features/util/update.py
index 9c30689db40fbd0349e8d12a9f73bc19e2f34e58..22aad5c8cbadec6ec8b28cecb05ad3826fc09737 100644
--- a/features/util/update.py
+++ b/features/util/update.py
@@ -11,7 +11,7 @@ from PySide2.QtCore import Qt, QThread, Signal
from PySide2.QtWidgets import QProgressBar, QVBoxLayout, QLabel, QApplication, QDesktopWidget, QDialog, QHBoxLayout, \
QPushButton, QTableWidgetItem, QHeaderView, QTableView
-from features.io.settings import Settings
+import utils
from features.util.check_update_ui import Ui_Dialog
from features.util.make_update import should_be_recorded
@@ -184,7 +184,6 @@ class UpdateClientThread(BaseUpdateThread):
return
if response.status_code == 200:
local_path = self.root.joinpath(item)
- # local_path = Path('D:/temp/temp').joinpath(item)
if not local_path.parent.is_dir():
os.makedirs(local_path.parent)
with open(local_path, 'wb') as f:
@@ -208,23 +207,23 @@ class UpdateClientThread(BaseUpdateThread):
class UpdateTipClient(Ui_Dialog):
- def __init__(self):
+ def __init__(self, startup: bool):
self.dialog = QDialog()
self.setupUi(self.dialog)
self.url = MD5_JSON_URL
self.update_files_list = []
self.delete_files_list = []
self.root = Path(__file__).parent.parent.parent.parent
- self.is_start_thread()
+ self.is_start_thread(startup)
- def is_start_thread(self):
+ def is_start_thread(self, startup: bool):
"""
根据根目录下是否存在.git目录,判断是否处于开发状态,开发状态不检查更新
根据设置界面检查更新checkbox是否为True,决定是否启动检查更新
"""
if self.root.joinpath('.git').is_dir():
return
- if Settings.get_instance().get('check_update'):
+ if not (startup and (not utils.get_settings_item_from_file("config.ini", "MAIN/CHECK_UPDATE"))):
self.thread = UpdateTipThread(url=self.url)
self.thread.update_files_list.connect(self.set_update_files_list)
self.thread.delete_files_list.connect(self.set_delete_files_list)
@@ -283,7 +282,6 @@ class UpdateTipClient(Ui_Dialog):
def set_exist_update(self, flag):
"""
存在更新则启动界面
- TODO:暂时不要启动这样的更新界面了。要更新的话,手动更新.因为现在设置项还没有做好。
"""
if flag:
self.init_gui()
diff --git a/load_modules.py b/load_modules.py
index 01602d0e14176d3e30092023007576f17f827bf9..14542a2d06d4e094da886818aa39eee2c224d0bb 100644
--- a/load_modules.py
+++ b/load_modules.py
@@ -1,8 +1,11 @@
+import logging
+import os
+
from PySide2.QtCore import QTranslator, QSettings
from PySide2.QtGui import QFontDatabase
from PySide2.QtWidgets import QApplication
-from utils import *
+from utils import get_root_dir, get_config_file_dir
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
@@ -18,14 +21,12 @@ def load_translator(app: QApplication):
app.translator = QTranslator()
app.translator2 = QTranslator()
- settings = QSettings(os.path.join(get_root_dir(), "config.ini"), QSettings.IniFormat)
+ settings = QSettings(get_config_file_dir("config.ini"), QSettings.IniFormat)
language = settings.value("MAIN/LANGUAGE")
logger.debug("获取设置项MAIN/LANGUAGE: %s" % language)
- print(get_root_dir())
path_lang = os.path.join(get_root_dir(), 'languages', '{}'.format(language), '{}.qm'.format(language))
logger.debug("翻译文件的路径:%s" % path_lang)
-
if os.path.isfile(path_lang):
app.translator.load(path_lang)
app.installTranslator(app.translator)
diff --git a/packages/applications_toolbar/applications_toolbar.py b/packages/applications_toolbar/applications_toolbar.py
index 76cafa0aad226fa003914dd31c4d41263a29b53b..2ef583f5a1f5d343b7d67361c53d31ad9393410d 100644
--- a/packages/applications_toolbar/applications_toolbar.py
+++ b/packages/applications_toolbar/applications_toolbar.py
@@ -269,7 +269,7 @@ class PMApplicationsToolBar(PMGToolBar):
Returns:
"""
- work_dir = self.extension_lib.Program.get_settings()['work_dir']
+ work_dir = self.extension_lib.Program.get_work_dir()
app_paths = APPManager.get_instance().get_app_paths()
path_index = 1 if len(app_paths) > 1 else 0
dlg = PMGPanelDialog(parent=self, views=[])
@@ -299,7 +299,7 @@ class PMApplicationsToolBar(PMGToolBar):
Returns:
"""
- work_dir = self.extension_lib.Program.get_settings()['work_dir']
+ work_dir = self.extension_lib.Program.get_work_dir()
dev_path = QFileDialog.getExistingDirectory(self, self.tr('Select Packup App Developing Folder'),
directory=work_dir)
diff --git a/packages/applications_toolbar/dev_tools.py b/packages/applications_toolbar/dev_tools.py
index 7702388164f242efff1f82b5948ae1965c755ca7..c4f82c85e6557c491f9ce0fd4d7002865d72f4db 100644
--- a/packages/applications_toolbar/dev_tools.py
+++ b/packages/applications_toolbar/dev_tools.py
@@ -53,7 +53,7 @@ class DevelopTools(QObject):
def open_designer(self):
import subprocess
- self.workdir = self.extension_lib.Program.get_settings()['work_dir']
+ self.workdir = self.extension_lib.Program.get_work_dir()
if self.check_installed(self.designer_path):
subprocess.Popen(self.designer_path, cwd=self.workdir)
@@ -136,7 +136,7 @@ class DevelopTools(QObject):
"""
ret = self.show_covered_message('.ui', '.py')
if ret == QMessageBox.Ok:
- work_dir = self.extension_lib.Program.get_settings()['work_dir']
+ work_dir = self.extension_lib.Program.get_work_dir()
ui_files = self.list_files(work_dir, '.ui')
for ui_file_path in ui_files:
try:
@@ -156,7 +156,7 @@ class DevelopTools(QObject):
Returns:
"""
- work_dir = self.extension_lib.Program.get_settings()['work_dir']
+ work_dir = self.extension_lib.Program.get_work_dir()
pro_path = ''
for name in os.listdir(work_dir):
if name.endswith('.pro'):
@@ -211,7 +211,7 @@ class DevelopTools(QObject):
Returns:
"""
- work_dir = self.extension_lib.Program.get_settings()['work_dir']
+ work_dir = self.extension_lib.Program.get_work_dir()
ret = self.show_covered_message(self.tr('.py files in working directory with tr() or translate() functions'),
'.ts')
if ret == QMessageBox.Ok:
@@ -257,7 +257,7 @@ class DevelopTools(QObject):
"""
ret = self.show_covered_message('.qrc', '*_rc.py')
if ret == QMessageBox.Ok:
- work_dir = self.extension_lib.Program.get_settings()['work_dir']
+ work_dir = self.extension_lib.Program.get_work_dir()
qrcs = self.list_files(work_dir, '.qrc')
for qrc_path in qrcs:
try:
diff --git a/packages/code_editor/codeeditor/tabwidget.py b/packages/code_editor/codeeditor/tabwidget.py
index ea32224e714c9d6b1af286c9d475431e2f7ebc95..fa0bbcc75b2371666da449048c9bfd1041b17c74 100644
--- a/packages/code_editor/codeeditor/tabwidget.py
+++ b/packages/code_editor/codeeditor/tabwidget.py
@@ -21,26 +21,26 @@ translated into English by those websites.
__version__ = '0.1'
+import sys
+import cgitb
import logging
import os
-import sys
import re
import time
from contextlib import redirect_stdout
from io import StringIO
from queue import Queue
-from typing import TYPE_CHECKING, List
-import pmgwidgets
-from PySide2.QtCore import QDir, QLocale, QObject, Signal, QThread, QTemporaryFile, QTimer
+from typing import List
+from typing import TYPE_CHECKING, Dict, Union, Tuple, Optional, Any
+
+from PySide2.QtCore import QDir, QObject, Signal, QThread, QTemporaryFile, QTimer
from PySide2.QtGui import QCloseEvent
from PySide2.QtWidgets import QTabWidget, QFileDialog, QMessageBox, QApplication, QSizePolicy, QWidget, QComboBox
-
-from packages.code_editor.codeeditor.qtpyeditor import PythonHighlighter
-
# TODO to remove (use extensionlib)
from flake8.main.application import Application
-from typing import TYPE_CHECKING, Dict, Union, Tuple, Optional, Any
+import pmgwidgets
+from packages.code_editor.codeeditor.qtpyeditor import PythonHighlighter
from pmgwidgets import PMDockObject, in_unit_test, PMGFileSystemWatchdog, UndoManager
if TYPE_CHECKING or in_unit_test():
@@ -742,7 +742,8 @@ class PMCodeEditTabWidget(QTabWidget, PMDockObject):
# 打开文件
self.extension_lib.UI.get_toolbar_widget('code_editor_toolbar', 'button_open_script').clicked.connect(
self.slot_open_script)
- interpreters = self.extension_lib.Program.get_settings()['external_interpreters']
+ interpreters = self.extension_lib.Program.get_settings_item_from_file("config.ini",
+ "RUN/EXTERNAL_INTERPRETERS")
interpreter_names = [self.tr('Builtin (3.8.5)')] + [d['name'] for d in interpreters]
combo_box: QComboBox = self.extension_lib.UI.get_toolbar_widget('code_editor_toolbar',
'combobox_interpreter')
@@ -821,7 +822,7 @@ class PMCodeEditTabWidget(QTabWidget, PMDockObject):
Returns:
"""
- interpreters = self.extension_lib.Program.get_settings()['external_interpreters']
+ interpreters = self.extension_lib.Program.get_settings_item_from_file("config.ini", 'RUN/EXTERNAL_INTERPRETERS')
combo.clear()
combo.addItem(self.tr('Builtin (%s)' % sys.version.split()[0]))
for interpreter in interpreters:
@@ -838,9 +839,8 @@ class PMCodeEditTabWidget(QTabWidget, PMDockObject):
elif interpreter_index == 0:
self._current_executable = sys.executable
else:
- print(self.extension_lib.Program.get_settings()['external_interpreters'], interpreter_index)
self._current_executable = \
- self.extension_lib.Program.get_settings()['external_interpreters'][interpreter_index - 1]['path']
+ self.extension_lib.Program.get_settings_item_from_file("config.ini", 'RUN/EXTERNAL_INTERPRETERS')[interpreter_index - 1]['path']
def on_tab_switched(self, index: int) -> None:
for i in range(self.count()):
@@ -955,9 +955,7 @@ class PMCodeEditTabWidget(QTabWidget, PMDockObject):
if __name__ == '__main__':
- import sys
- import cgitb
- import logging
+
cgitb.enable(format='text')
logging.basicConfig(level=logging.INFO)
@@ -976,11 +974,9 @@ if __name__ == '__main__':
w.setMinimumHeight(600)
w.setup_ui()
code_editor_root_directory = os.path.dirname(__file__)
- # w.slot_new_script(
- # '/home/hzy/Desktop/create_dataset.py') # os.path.join(code_editor_root_directory, 'tests', 'test_file.py'))
w.slot_new_script(r'C:/Users/12957/documents/developing/Python/pyminer_workdir/app_designer.py')
w.currentWidget().goto_line(5)
- # w.on_work_dir_changed(r'C:\Users\12957\AppData')
- # w.slot_new_script(r'c:/users/12957/desktop/test.md')
- # w.on_work_dir_changed('c:/users/12957/desktop')
+ # w.on_work_dir_changed(r'')
+ # w.slot_new_script(r'')
+ # w.on_work_dir_changed('')
sys.exit(app.exec_())
diff --git a/packages/code_editor/main.py b/packages/code_editor/main.py
index 7c1bd8fda30ac5b96691a54c68016ae3b308258b..d5e1fb5fc46ffa090b7d412400671c233dec7dc6 100644
--- a/packages/code_editor/main.py
+++ b/packages/code_editor/main.py
@@ -1,7 +1,6 @@
-import sys
import os
-import time
-from typing import Dict, Union, Any
+import sys
+from typing import Dict, Union
from PySide2.QtCore import QLocale, QTranslator
from PySide2.QtWidgets import QApplication
@@ -71,15 +70,14 @@ class Extension(BaseExtension):
Deal with events that settings changed.
:return:
"""
- theme = self.extension_lib.Program.get_settings()['theme']
- work_dir = self.extension_lib.Program.get_settings()['work_dir']
+ theme = self.extension_lib.Program.get_theme()
+ work_dir = self.extension_lib.Program.get_work_dir()
if theme != self.editor_widget._color_scheme:
if theme.lower() in ('fusion', 'windows', 'windowsvista'):
self.editor_widget.set_color_scheme('light')
else:
self.editor_widget.set_color_scheme('dark')
-
- work_dir = self.extension_lib.Program.get_settings()['work_dir']
+ print(work_dir)
self.editor_widget.on_work_dir_changed(work_dir)
def bind_event(self):
diff --git a/packages/dataio/export.py b/packages/dataio/export.py
index c8c2c0d032691d3573cf906f4690a78d3f8bbc1a..568e26693d5289adfe85e83d9c846a91414d007a 100644
--- a/packages/dataio/export.py
+++ b/packages/dataio/export.py
@@ -16,7 +16,7 @@ class ExportDialog(QDialog):
super(ExportDialog, self).__init__(parent=None)
self.normal = False
if initial_path == '' and not in_unit_test():
- initial_path = self.extension_lib.Program.get_settings()['work_dir']
+ initial_path = self.extension_lib.Program.get_work_dir()
self.setLayout(QVBoxLayout())
self.initial_var_name = initial_var_name
self.initial_path = initial_path
diff --git a/packages/dataio/sample.py b/packages/dataio/sample.py
index 30f0c790d73186a1cfbbc34c779a1a412e855c3c..4f207de6d1a9cc5bbf011b6f564d583620a2f942 100644
--- a/packages/dataio/sample.py
+++ b/packages/dataio/sample.py
@@ -237,7 +237,7 @@ class ImportDialog(QDialog):
def get_work_dir(self) -> str:
"""获取工作路径"""
- return self.extension_lib.Program.get_settings()['work_dir']
+ return self.extension_lib.Program.get_work_dir()
def center(self):
"""将窗口置于中心"""
diff --git a/packages/file_tree/main.py b/packages/file_tree/main.py
index d86e7bdc07ea33982b585c7948ccb6332032c330..697259db8ab8d6eae4938f4cb07f8393700d082b 100644
--- a/packages/file_tree/main.py
+++ b/packages/file_tree/main.py
@@ -1,11 +1,11 @@
import os
from typing import Callable
-from PySide2.QtWidgets import QApplication
from PySide2.QtCore import QLocale, QTranslator
+from PySide2.QtWidgets import QApplication
-from .file_tree import PMFilesTree
from features.extensions.extensionlib import BaseExtension, BaseInterface
+from .file_tree import PMFilesTree
file_name = os.path.join(os.path.dirname(__file__), 'translations', 'qt_%s.qm' % QLocale.system().name())
app = QApplication.instance()
@@ -23,9 +23,11 @@ class Extension(BaseExtension):
files_tree: 'PMFilesTree' = self.widgets['PMFilesTree']
files_tree.extension_lib = self.extension_lib
self.interface.file_widget = files_tree
- settings = self.extension_lib.Program.get_settings()
- self.extension_lib.Signal.get_settings_changed_signal().connect( # 当主界面设置改变信号发出时,改变工作路径。
- lambda: files_tree.change_current_path(settings['work_dir']))
+ def on_settings_changed():
+ work_dir = self.extension_lib.Program.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR")
+ files_tree.change_current_path(work_dir)
+
+ self.extension_lib.Signal.get_settings_changed_signal().connect(on_settings_changed) # 当主界面设置改变信号发出时,改变工作路径。
class Interface(BaseInterface):
diff --git a/packages/ipython_console/README.md b/packages/ipython_console/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..561b0588c98588add129d24189b828ce84e86aa1
--- /dev/null
+++ b/packages/ipython_console/README.md
@@ -0,0 +1,4 @@
+- requirements_ipython_node.txt:一个IPython作为连接到外部的IPython节点,至少需要装的包。
+这些包看起来不少,但是每个都比较小,即使用国外镜像源也很快。
+
+-
\ No newline at end of file
diff --git a/packages/ipython_console/initialize.py b/packages/ipython_console/initialize.py
index fd1f9dd362887959286ae89ddb3d0026ef1e44c9..433382e4b850f3be38234ef66d96445a5df9aad2 100644
--- a/packages/ipython_console/initialize.py
+++ b/packages/ipython_console/initialize.py
@@ -7,23 +7,30 @@
import types
import typing
-import matplotlib.pyplot as plt
-import numpy as np
-import pandas as pd
-import scipy.integrate
-import scipy.stats
-
-__packages = [np, plt, pd, scipy.integrate, scipy.stats]
-from IPython.core.magic import register_line_cell_magic
-from core import *
from pyminer_comm import modify_settings, set_data_desc_dic
from pyminer_comm.base import dict_to_b64, b64_to_dict, dict_to_pickle, pickle_to_dict, DataDesc, is_big_variable, \
NoPreviewError
+try:
+ import matplotlib.pyplot as plt
+ import numpy as np
+ import pandas as pd
+ import scipy.integrate
+ import scipy.stats
+ from core import *
+
+ __packages = [np, plt, pd, scipy.integrate, scipy.stats]
+except Exception as e:
+ import traceback
+
+ traceback.print_exc()
+
if typing.TYPE_CHECKING:
from IPython.core.interactiveshell import InteractiveShell
from IPython.core.getipython import get_ipython
+from IPython.core.magic import register_line_cell_magic
+
__ip: 'InteractiveShell' = get_ipython()
__ip.builtin_vars = [__k for __k in globals().keys()] # 内置保留变量,不可删除或者清空。
@@ -51,31 +58,43 @@ def __init_server():
server = Flask('ipython_data_server')
__ip = get_ipython()
__ip.shms = {}
+ log.debug("started server!")
def get_preview(var: typing.Any):
if is_big_variable(var):
- if isinstance(var, pd.DataFrame):
- if var.shape[0] > DataDesc.max_pandas_rows:
- return var.iloc[:DataDesc.max_pandas_rows, :]
- else:
- return var
+ if isinstance(var, (int, float, complex)):
+ return var
+ if isinstance(var, (list, tuple)):
+ return var[:DataDesc.max_len]
elif isinstance(var, str):
if len(var) > DataDesc.max_str_len:
return var[:DataDesc.max_str_len]
else:
return var
- elif isinstance(var, (list, tuple)):
- return var[:DataDesc.max_len]
- elif isinstance(var, np.ndarray):
- if is_big_variable(var):
- return NoPreviewError(
- 'Big numpy.ndarray with shape: %s, dtype:%s, memory usage: %s MB, cannot be viewed.'
- % (repr(var.shape), repr(var.dtype), repr(var.nbytes / 1024 / 1024)))
- else:
- return var
+ try:
+ if isinstance(var, pd.DataFrame):
+ if var.shape[0] > DataDesc.max_pandas_rows:
+ return var.iloc[:DataDesc.max_pandas_rows, :]
+ else:
+ return var
+
+ if isinstance(var, np.ndarray):
+ if is_big_variable(var):
+ return NoPreviewError(
+ 'Big numpy.ndarray with shape: %s, dtype:%s, memory usage: %s MB, cannot be viewed.'
+ % (repr(var.shape), repr(var.dtype), repr(var.nbytes / 1024 / 1024)))
+ else:
+ return var
+
+ except Exception as e:
+ return e
+
+
else:
return NoPreviewError('Big Variable typed %s cannot be viewed.' % (type(var))) # 无法产生预览视图。
+ else:
+ return repr(var)
def write_log(arg):
if os.path.exists(r'c:\users\hzy\Desktop\log.txt'):
@@ -361,59 +380,16 @@ def __cell_exec_func(raw_cell, store_history=False, silent=False, shell_futures=
Returns:
"""
- import ast
__ip = get_ipython()
__cwd = os.getcwd()
- class PyMinerIPyConsoleNodeTransformer(ast.NodeTransformer):
- def __init__(self):
- super(PyMinerIPyConsoleNodeTransformer, self).__init__()
- self.identifier_list = []
- self.str_list = []
-
- def visit_Name(self, node: ast.Name):
- """
-
- Args:
- node:
-
- Returns:
-
- """
- self.identifier_list.append(node.id)
-
- def visit_Str(self, node: ast.Str):
- """
-
- Args:
- node:
-
- Returns:
-
- """
- self.str_list.append(node.s)
-
- def show_identifiers_might_changed(self, code):
- """
-
- Args:
- code:
-
- Returns:
-
- """
- self.identifier_list = []
- self.str_list = []
- self.visit(ast.parse(code))
- return [s for s in list(set(self.identifier_list + self.str_list)) if s.isidentifier()]
-
- s = get_ipython().original_run_cell_func(raw_cell, store_history=store_history, silent=silent,
- shell_futures=shell_futures)
+ __ret = get_ipython().original_run_cell_func(raw_cell, store_history=store_history, silent=silent,
+ shell_futures=shell_futures)
__ip.var_name_list = list(__ip.filter_vars(globals()).keys())
__ip.update_workspace()
if __cwd != os.getcwd():
- modify_settings({'work_dir': os.getcwd()})
- return s
+ modify_settings({'MAIN/PATH_WORKDIR': os.getcwd()})
+ return __ret
def __chdir(path: str):
diff --git a/packages/ipython_console/ipythonqtconsole.py b/packages/ipython_console/ipythonqtconsole.py
index 3ea9eec9399235c69921f1823fda5798fdf3c20d..e10b1683c6fbf14cf9592d60807c7e7b3d5f8835 100644
--- a/packages/ipython_console/ipythonqtconsole.py
+++ b/packages/ipython_console/ipythonqtconsole.py
@@ -10,10 +10,9 @@ Created on 2020/8/24
"""
import os
from typing import Tuple
-import time
-from pmgwidgets import PMDockObject, get_ipython_console_class, in_unit_test
+from pmgwidgets import PMDockObject, in_unit_test
+from pmgwidgets.widgets.basic.others.console import PMGIpythonConsole
from PySide2.QtWidgets import QApplication
-PMGIpythonConsole = get_ipython_console_class()
if QApplication.instance() is not None:
PMGIpythonConsole.install_translator()
@@ -38,7 +37,7 @@ class ConsoleWidget(PMGIpythonConsole, PMDockObject):
def setup_ui(self):
super().setup_ui()
if not in_unit_test():
- style = self.lib.Program.get_settings()['theme']
+ style = self.lib.Program.get_theme()
self.change_ui_theme(style)
def connect_to_datamanager(self, data_manager):
@@ -57,11 +56,10 @@ class ConsoleWidget(PMGIpythonConsole, PMDockObject):
if in_unit_test():
pwd = os.path.dirname(__file__)
else:
- pwd = self.extension_lib.Program.get_settings()['work_dir']
+ pwd = self.extension_lib.Program.get_work_dir()
pwd = pwd.replace('\\', '\\\\')
from utils import get_root_dir
cmd = 'import sys;sys.path.append(r\'%s\')' % get_root_dir()
- print(cmd)
self.execute_command(cmd, True, '')
cdcmd = 'import os;os.chdir(\'%s\')' % pwd # 启动时切换到当前工作路径。
self.execute_command(cdcmd, True, '')
diff --git a/packages/ipython_console/lexersplit.py b/packages/ipython_console/lexersplit.py
deleted file mode 100644
index 7ee30f30b77e0e2060ab157c3e92cbb4937f1973..0000000000000000000000000000000000000000
--- a/packages/ipython_console/lexersplit.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import ast
-import typing
-
-
-class NodeVisitor(ast.NodeVisitor):
- def visit_Name(self, node: ast.Name) -> typing.Any:
- print(node)
-
-
-class NodeTransformer(ast.NodeTransformer):
- # def visit_Str(self, tree_node):
- # return ast.Str('String: ' + tree_node.s)
- def __init__(self):
- super(NodeTransformer, self).__init__()
- self.identifier_list = []
- self.str_list = []
-
- def visit_Name(self, node: ast.Name):
- """
-
- Args:
- node:
-
- Returns:
-
- """
- self.identifier_list.append(node.id)
-
- def visit_Str(self, node: ast.Str) -> typing.Any:
- """
-
- Args:
- node:
-
- Returns:
-
- """
- self.str_list.append(node.s)
-
- def show_identifiers_might_changed(self, code) -> list:
- """
-
- Args:
- code:
-
- Returns:
-
- """
- self.identifier_list = []
- self.str_list = []
- self.visit(ast.parse(code))
- return [s for s in list(set(self.identifier_list + self.str_list)) if s.isidentifier()]
-
-
-if __name__ == '__main__':
- s = '''
- class A:
- def aaa():
- b=123
- print(b)
- fruits = ['grapes', 'mango']
- name = 'peter'
- for fruit in fruits:
- print('{} likes {}'.format(name, fruit))
- '''
-
- # NodeTransformer().visit(tree_node)
- print(NodeTransformer().show_identifiers_might_changed(s))
- # NodeVisitor().visit(tree_node)
diff --git a/packages/ipython_console/main.py b/packages/ipython_console/main.py
index c730eaae30249ae4ad10d9149e231081e061446f..1492208da5d4cd739105b32b3cb2408ba6a53f5b 100644
--- a/packages/ipython_console/main.py
+++ b/packages/ipython_console/main.py
@@ -37,16 +37,16 @@ class Extension(BaseExtension):
self.interface.widget = self.console
self.extension_lib.Signal.get_settings_changed_signal().connect(self.on_settings_changed)
self.extension_lib.Signal.get_events_ready_signal().connect(self.on_settings_changed)
- self._work_dir = self.extension_lib.Program.get_settings()['work_dir']
+ self._work_dir = self.extension_lib.Program.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR")
def on_settings_changed(self):
"""
如果设置项发生改变,重新加载主题文件。
TODO:倘若ipython发生改变之后,工作路径如何跟着改变?
"""
- settings = self.extension_lib.Program.get_settings()
- self.console.change_ui_theme(settings['theme'])
- work_dir = settings['work_dir']
+ theme = self.extension_lib.Program.get_theme()
+ self.console.change_ui_theme(theme)
+ work_dir = self.extension_lib.Program.get_work_dir()
if not os.path.samefile(work_dir, self._work_dir): # samefile函数:既可判断是否为同一文件,也可判断是否为同一文件夹
self.command = self.interface.run_command("get_ipython().chdir(\'%s\')" % work_dir.replace('\\', '\\\\'),
hidden=False)
diff --git a/packages/ipython_console/requirements_ipython_node.txt b/packages/ipython_console/requirements_ipython_node.txt
new file mode 100644
index 0000000000000000000000000000000000000000..92f07469576fe5cbed28d8215cbda3d743568fd2
--- /dev/null
+++ b/packages/ipython_console/requirements_ipython_node.txt
@@ -0,0 +1,4 @@
+cloudpickle
+Flask
+ipykernel
+ipython
diff --git a/packages/pm_calc/fastui/dblquad.py b/packages/pm_calc/fastui/dblquad.py
new file mode 100644
index 0000000000000000000000000000000000000000..853c7391b4f0c79078466e7f16859f133c696e66
--- /dev/null
+++ b/packages/pm_calc/fastui/dblquad.py
@@ -0,0 +1,210 @@
+import ast
+from typing import Any, List, Tuple
+
+from PySide2.QtWidgets import QApplication
+
+from pmgwidgets import FunctionGUIDialog
+
+
+class CodeVisitor(ast.NodeVisitor):
+ def __init__(self):
+ super(CodeVisitor, self).__init__()
+ self.preserved = {"pi", "e"}
+ self.called = set()
+ self.func_args = set()
+ self._names = set()
+
+ def visit_Name(self, node: ast.Name) -> Any:
+ self._names.add(node.id)
+
+ def visit_Call(self, node: ast.Call) -> Any:
+ self.generic_visit(node)
+ self.called.add(node.func.id)
+
+ def get_result(self) -> Tuple[List[str], List[str]]:
+ """
+
+ Returns: 定义的名称,以及调用的ID名称。
+
+ """
+ names = self._names.copy()
+ names.difference_update(self.preserved)
+ names.difference_update(self.called)
+ return list(names), list(self.called)
+
+
+class Function():
+ def __init__(self, s):
+ self.name = s
+
+ def __repr__(self):
+ return self.name
+
+
+def convert_to_lambda(code):
+ print(code)
+ original_code = code
+ code = code.replace("np.", "")
+ cv = CodeVisitor()
+ cv.visit(ast.parse(code))
+ args_list, funcs = cv.get_result()
+ args = ''
+ for a in args_list:
+ args += a + ","
+ args = args.strip(", ")
+
+ ret = "lambda {ARGS}: {FCN}".format(ARGS=args, FCN=original_code)
+ return Function(ret)
+
+
+dic = {
+ "title": "数据透视",
+ "func_name": "scipy.integrate.dblquad",
+ "with_object": False,
+ "args": [
+ {
+ "name": "func",
+ "title": "被积函数",
+ "optional": False,
+ "ctrl": {
+ "type": "multitype_ctrl",
+ "title": "选择被积函数",
+ "init": "x*y",
+ "types":
+ [{
+ "type_title": "输入表达式",
+ "ctrls": [
+ ("line_ctrl", "", '输入表达式并自动转换为函数', "np.sin(2*np.pi*x)"),
+ ],
+ "on_ok": lambda data: convert_to_lambda(data[""])
+ }, {
+ "type_title": "输入函数",
+ "ctrls": [
+ ("line_ctrl", "", '输入函数代码', "lambda x: np.sin(2*np.pi*x)"),
+ ],
+ "on_ok": lambda data: Function(data[""])
+ }, {
+ "type_title": "选择变量",
+ "ctrls": [
+ ("vars_combo_ctrl", "variable", "选择变量", ""),
+ ],
+ }]
+ }
+ },
+ {
+ "name": "hfun",
+ "title": "内层函数上界",
+ "optional": False,
+ "ctrl": {
+ "type": "multitype_ctrl",
+ "title": "内层函数上界",
+ "init": "np.sin(2*np.pi*x)",
+ "types":
+ [{
+ "type_title": "输入表达式",
+ "ctrls": [
+ ("line_ctrl", "", '输入表达式并自动转换为函数', "np.sin(2*np.pi*x)"),
+ ],
+ "on_ok": lambda data: convert_to_lambda(data[""])
+ }, {
+ "type_title": "输入函数",
+ "ctrls": [
+ ("line_ctrl", "", '输入函数代码', "lambda x: np.sin(2*np.pi*x)"),
+ ],
+ "on_ok": lambda data: Function(data[""])
+ }, {
+ "type_title": "选择变量",
+ "ctrls": [
+ ("vars_combo_ctrl", "variable", "选择变量", ""),
+ ],
+ }]
+ }
+ },
+ {
+ "name": "gfun",
+ "title": "内层函数下界",
+ "optional": False,
+ "ctrl": {
+ "type": "multitype_ctrl",
+ "title": "内层函数下界",
+ "init": "lambda x:0",
+ "types":
+ [{
+ "type_title": "输入表达式",
+ "ctrls": [
+ ("line_ctrl", "", '输入表达式并自动转换为函数', "np.sin(2*np.pi*x)"),
+ ],
+ "on_ok": lambda data: convert_to_lambda(data[""])
+ }, {
+ "type_title": "输入函数",
+ "ctrls": [
+ ("line_ctrl", "", '输入函数代码', "lambda x:0"),
+ ],
+ "on_ok": lambda data: Function(data[""])
+ }, {
+ "type_title": "选择变量",
+ "ctrls": [
+ ("vars_combo_ctrl", "variable", "选择变量", ""),
+ ],
+ }]
+ }
+ },
+ {
+ "name": "a",
+ "title": "积分下限",
+ "optional": False,
+ "ctrl": {
+ "type": "multitype_ctrl",
+ "title": "积分下限",
+ "init": 0,
+ "types":
+ [{
+ "type_title": "输入下界",
+ "ctrls": [
+ ("number_ctrl", "", '输入下界', 0),
+ ],
+ }, {
+ "type_title": "选择变量",
+ "ctrls": [
+ ("vars_combo_ctrl", "variable", "选择变量", ""),
+ ],
+ }]
+ }
+ },
+ {
+ "name": "b",
+ "title": "积分上限",
+ "optional": False,
+ "ctrl": {
+ "type": "multitype_ctrl",
+ "title": "积分上限",
+ "init": 1,
+ "types":
+ [{
+ "type_title": "输入数值",
+ "ctrls": [
+ ("number_ctrl", "", '输入数值', 1),
+ ]
+ }, {
+ "type_title": "选择变量",
+ "ctrls": [
+ ("vars_combo_ctrl", "variable", "选择变量", ""),
+ ],
+ }]
+ }
+ },
+ ]
+
+}
+
+
+class PivotDialog(FunctionGUIDialog):
+ def __init__(self):
+ FunctionGUIDialog.__init__(self, dic)
+
+
+if __name__ == '__main__':
+ app = QApplication([])
+ md = PivotDialog()
+ md.show()
+ app.exec_()
diff --git a/packages/pmagg/ui/linestyles.py b/packages/pmagg/ui/linestyles.py
index 9689a82fe7d4f4dc5be95b99121329af068049db..f59b5dc3b830a6b60ff76364b8a128ca876ebaf0 100644
--- a/packages/pmagg/ui/linestyles.py
+++ b/packages/pmagg/ui/linestyles.py
@@ -3,7 +3,7 @@
# @Author : 别着急慢慢来
# @FileName: linestyles.py
# matplotlib中的常见颜色
-from matplotlib.colors import LogNorm, NoNorm, BoundaryNorm, DivergingNorm, PowerNorm, SymLogNorm, TwoSlopeNorm, \
+from matplotlib.colors import LogNorm, NoNorm, BoundaryNorm, PowerNorm, SymLogNorm, TwoSlopeNorm, \
Normalize
languages = ['en', 'zh_CN']
diff --git a/packages/qt_vditor/client.py b/packages/qt_vditor/client.py
index 74dde8215f4af3c2ace1a36953aaea959829ab18..2031bd9714864fe4842140271260808a8ecf4895 100644
--- a/packages/qt_vditor/client.py
+++ b/packages/qt_vditor/client.py
@@ -1,11 +1,12 @@
+import json
import os
-from PySide2 import QtWidgets, QtCore
-from PySide2.QtWebEngineWidgets import QWebEngineView
-import sys
import re
+import sys
import time
+
import requests
-import json
+from PySide2 import QtWidgets, QtCore
+from PySide2.QtWebEngineWidgets import QWebEngineView
class Window(QtWidgets.QDialog):
@@ -80,6 +81,6 @@ class Window(QtWidgets.QDialog):
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = Window(url='http://127.0.0.1:5000/qt_vditor')
- win.load_file(file_path='D:/pyminer/pyminer2/extensions/packages/pmagg/sample/sample_code.md')
+ win.load_file(file_path=os.path.join(os.path.dirname(__file__), "examples", "sample.md"))
win.show()
app.exec_()
diff --git a/packages/qt_vditor/examples/sample.md b/packages/qt_vditor/examples/sample.md
new file mode 100644
index 0000000000000000000000000000000000000000..da6e237a1363dd5646a42d257fd7914ee2f66396
--- /dev/null
+++ b/packages/qt_vditor/examples/sample.md
@@ -0,0 +1,7 @@
+# 这是一个Markdown文件的一级标题
+## 这是一个Markdown文件的二级标题
+```python
+def func():
+ print("Hello Vditor!")
+func()
+```
\ No newline at end of file
diff --git a/packages/socket_server/server_by_socket.py b/packages/socket_server/server_by_socket.py
index 03895aa8cb079100e164e0778efac9a4258e69af..9975e4f22edfc9bfc896ea785ef72710900b80e1 100644
--- a/packages/socket_server/server_by_socket.py
+++ b/packages/socket_server/server_by_socket.py
@@ -1,14 +1,13 @@
import json
import logging
+import queue
import sys
-import time
-from typing import Dict, Any, List, Tuple
+import threading
+from typing import Dict, Any
-import cloudpickle
+from PySide2.QtCore import Signal, QObject, QThread
from PySide2.QtWidgets import QApplication
-from PySide2.QtCore import Signal, QTimer, QObject, QThread
-import threading
-import queue
+
from pyminer_comm.base import b64_to_dict, dict_to_b64, DataDesc, get_protocol
logger = logging.getLogger(__name__)
@@ -18,17 +17,10 @@ INTERFACE_CALLED = 3
from flask import Flask, request
app = Flask(__name__)
-worker: 'LoopWork' = None
message_queue: queue.Queue = queue.Queue()
extension_lib = None
-@app.route('/get_data_desc')
-def hello_world():
- global message_queue
- return 'Hello World!'
-
-
@app.route('/modify_settings')
def modify_settings():
global message_queue
@@ -56,17 +48,27 @@ def get_settings():
:return:
"""
global message_queue
- return json.dumps(extension_lib.Program.get_settings())
+ return "['Warning this method was deprecated']"
@app.route('/get_stylesheet')
def get_stylesheet():
+ """
+ 获取QApplication的样式表
+ Returns:
+
+ """
assert QApplication.instance() is not None
return QApplication.instance().styleSheet()
@app.route('/set_data')
def modify_data_descs():
+ """
+ 将工作空间中设置为data_desc型变量
+ Returns:
+
+ """
global message_queue
try:
datadesc_dict = b64_to_dict(request.args.get('msg'))
@@ -83,6 +85,11 @@ def modify_data_descs():
@app.route('/interface_call')
def run_command():
+ """
+ 运行命令,调用接口函数。
+ Returns:
+
+ """
global message_queue
try:
settings = request.args.get('msg')
@@ -102,16 +109,6 @@ def run_command():
return "Failed!"
-class LoopWork(QObject):
- def __init__(self, server_obj: 'Flask'):
- super().__init__()
- self.server_obj = server_obj
- self.threads = []
-
- def work(self):
- app.run(port=12306)
-
-
class QueueWork(QObject):
signal_queue_recv = Signal(object)
@@ -149,10 +146,9 @@ class PMGServer(QObject):
def __init__(self, parent=None):
super().__init__(parent)
- global worker
self.queue_loop_thread = QThread()
- self.queue_worker = QueueWork()
+ self.queue_worker = QueueWork() # 队列处理
self.queue_worker.moveToThread(self.queue_loop_thread)
@@ -172,8 +168,11 @@ class PMGServer(QObject):
def on_recv(self, msg: object):
"""
- :param msg:
- :return:
+ Args:
+ msg: 收到的信息
+
+ Returns:
+
"""
if msg[0] == DATA_CHANGED:
self.signal_data_set.emit(msg[1])
@@ -181,8 +180,18 @@ class PMGServer(QObject):
self.signal_settings_changed.emit(msg[1])
elif msg[0] == INTERFACE_CALLED:
self.signal_interface_called.emit(msg[1]['interface'], msg[1]['method'], msg[1]['kwargs'], msg[2])
+ else:
+ logger.error("received error:" + repr(object))
def on_data_set(self, data: Dict[str, Any]):
+ """
+ 当数据设置时的回调
+ Args:
+ data:
+
+ Returns:
+
+ """
names = self.extension_lib.Data.get_all_variable_names()
for name in names:
if name not in data.keys():
@@ -192,14 +201,16 @@ class PMGServer(QObject):
def on_settings_changed(self, settings: Dict[str, Any]):
"""
- 改变设置
- :param settings
- :return:
+ 改变设置时的回调
+ Args:
+ settings:
+
+ Returns:
+
"""
- for param_name, param_val in settings.items():
- if param_name not in self.extension_lib.Program.get_settings().keys():
- raise ValueError('Parameter name \'%s\' not in settings!' % param_name)
- self.extension_lib.Program.update_settings(settings)
+ for k, v in settings.items():
+ self.extension_lib.Program.write_settings_item_to_file("config.ini", k, v)
+ self.extension_lib.Signal.get_settings_changed_signal().emit()
def on_interface_called(self, interface_name: str, method_name: str, kwargs: Dict, res_queue: queue.Queue):
interface = self.extension_lib.get_interface(interface_name)
@@ -221,7 +232,7 @@ def run_server(port: int = None, ext_lib=None):
extension_lib = ext_lib
server = PMGServer()
- server_thread = threading.Thread(target=app.run, kwargs={'port': 12306})
+ server_thread = threading.Thread(target=app.run, kwargs={'port': port})
server_thread.setDaemon(True)
server_thread.start()
diff --git a/pmgui.py b/pmgui.py
index 52f2bddc5d7f9a1db8c15a2678236d3e3730a57f..7e425da5bab7aad32aa82b6cdb63c38713d00081 100644
--- a/pmgui.py
+++ b/pmgui.py
@@ -1,33 +1,8 @@
-import datetime
-import getpass
-import os
-import time
-
+from PySide2.QtCore import Qt
from PySide2.QtWidgets import QTextEdit
-from pmgwidgets import PMGToolBar, ActionWithMessage, PMDockObject, create_icon
-
-from typing import List, Callable, Tuple, ClassVar
-
-from PySide2.QtCore import Signal, QTimer, Qt, QTranslator, QLocale, QSize, QCoreApplication
-from PySide2.QtGui import QCloseEvent, QTextCursor, QResizeEvent, QFontDatabase, QMoveEvent, QFont, QIcon, QPixmap
-from PySide2.QtWidgets import QApplication, QTextEdit, QMessageBox, QToolBar, QSplashScreen, QStatusBar, QTextBrowser, \
- QDialog, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
-from utils import get_main_window, get_application
from pmgwidgets import PMGToolBar, ActionWithMessage, PMDockObject, create_icon
-from features.extensions.extensions_manager.manager import extensions_manager
-from features.main_window import base
-from features.io.settings import Settings
-from features.io.settings import load_theme
-from features.interpretermanager.interpretermanager import InterpreterManagerWidget
-from features.util.update import perform_update, UpdateTipClient
-from features.feedback import FeedbackClient
-from features.ui.widgets.controlpanel import PMPageExt
-from features.ui.pmwidgets import BaseMainWindow
-from multiprocessing import shared_memory
-import utils
-import logging
-
+from utils import get_main_window, get_application
def updateSplashMsg(ext_load_status: dict):
@@ -40,6 +15,7 @@ def updateSplashMsg(ext_load_status: dict):
except TypeError:
return
+
class PMToolBarHome(PMGToolBar):
"""
定义菜单工具栏按钮。
@@ -174,362 +150,3 @@ class PMToolBarHome(PMGToolBar):
class LogOutputConsole(QTextEdit, PMDockObject):
pass
-
-class MainWindow(BaseMainWindow):
- setupui_tasks: List[Callable] = []
- boot_timer: QTimer = None
- close_signal = Signal()
- window_geometry_changed_signal = Signal()
-
- layouts_ready_signal = Signal()
- widgets_ready_signal = Signal()
- events_ready_signal = Signal()
-
- settings_changed_signal = Signal()
-
- @classmethod
- def __new__(cls, *args):
- if not hasattr(cls, 'instance'):
- instance = super().__new__(cls)
- cls.instance = instance
- return cls.instance
-
- def __init__(self, parent=None):
- super().__init__(parent)
-
- t00 = time.time()
- settings = Settings()
- self.main_option_form = base.OptionForm()
- self.project_wizard: base.ProjectWizardForm = None
- self.settings_changed_signal.connect(self.on_settings_changed)
- self.main_option_form.add_page(self.tr('Interpreter'), InterpreterManagerWidget())
-
- utils._main_window = self
-
- # 主窗体默认大小
- self.resize(1920, 1080)
- self.setIconSize(QSize(40, 40))
- # 设置状态栏
- self.statusBar = QStatusBar()
- version = utils.get_python_version()
- self.statusBar.showMessage(version, 0)
- self.setStatusBar(self.statusBar)
-
- root_dir = os.path.dirname(__file__)
- utils._root_dir = root_dir
-
- self.init_toolbar_tab()
- tb_home = PMToolBarHome()
- self.add_toolbar('toolbar_home', tb_home, text=tb_home.get_toolbar_text())
- self.setDockNestingEnabled(True)
- self.setWindowTitle('PyMiner')
-
- self.log_output_console = LogOutputConsole(self)
-
- self.add_widget_on_dock(
- 'log_output_console',
- self.log_output_console,
- text=self.tr('Logs'),
- side='right')
-
- # 初始化日志
- self.slot_flush_console('info', 'system', self.tr('Welcome to PyMiner'))
-
- self.extensions_manager = extensions_manager
- self.extensions_manager.load_from_extension_folder(updateSplashMsg)
-
- self.ext_manager_widget = PMPageExt(self)
- dw = self.add_widget_on_dock(
- 'extension_panel',
- self.ext_manager_widget,
- text=self.tr('Plugs'),
- side='left')
- dw.setMaximumWidth(400)
-
- load_theme(settings['theme']) # 组件都加载后再设置主题,否则可能有些组件不生效
- self.show()
- self.load_layout()
- self.switch_toolbar('toolbar_home') # 启动完成时,将工具栏切换到‘主页’
-
- self.on_main_window_shown()
- # self.first_form_display()
-
- self.start_pmlocalserver() # 只要在插件加载完成之后启动就行,目前放在最后
- self.update_tip_client = UpdateTipClient() # 启动程序,检查更新,弹窗提醒
-
- t01 = time.time()
- logging.debug('Time Elapsed for loading main window contents: %f' % (t01 - t00))
-
- def start_pmlocalserver(self):
- """
- 启动本地flask服务器pmlocalserver
- Returns:None
-
- """
- server.server_thread.start()
-
- def clear_workspace(self):
- from features.extensions.extensionlib.extension_lib import extension_lib
- extension_lib.get_interface('ipython_console').run_command('Clearing_Variables_ =\'Clear All\'',
- hint_text=self.tr('Start Clear...'), hidden=False)
- extension_lib.get_interface('ipython_console').run_command('get_ipython().clear_all()',
- hint_text=self.tr('Clear all variables'),
- hidden=False)
-
- def add_toolbar(self, name: str, toolbar: PMGToolBar,
- text: str = 'untitled toolbar'):
- """
- 添加一个工具栏。
- """
- if toolbar.insert_after() == '':
- b = self.top_toolbar_tab.add_button(name, text)
- else:
- b = self.top_toolbar_tab.insert_button(name, text, toolbar.insert_after())
- toolbar.tab_button = b
- b.clicked.connect(lambda: self.on_toolbar_switch_button_clicked(name))
-
- if hasattr(self, 'toolbar_path'):
- self.insertToolBar(self.toolbar_path, toolbar)
- self.insertToolBarBreak(self.toolbar_path)
- else:
- self.addToolBarBreak(Qt.TopToolBarArea)
- self.addToolBar(toolbar)
- toolbar.setObjectName(name)
- self.toolbars[name] = toolbar
- toolbar.setMovable(False)
- toolbar.setFloatable(False)
-
- if self._current_toolbar_name != '':
- self.refresh_toolbar_appearance()
-
- # def insert_toolbar(self, name: str, toolbar: QToolBar, text: str, insert_after: str):
- # """
- # 插入一个工具栏。
- # """
- # b = self.top_toolbar_tab.add_button(text)
- # toolbar.tab_button = b
- # b.clicked.connect(lambda: self.on_toolbar_switch_button_clicked(name))
- #
- # if hasattr(self, 'toolbar_path'):
- # self.insertToolBar(self.toolbar_path, toolbar)
- # self.insertToolBarBreak(self.toolbar_path)
- # else:
- # self.addToolBarBreak(Qt.TopToolBarArea)
- # self.addToolBar(toolbar)
- # toolbar.setObjectName(name)
- # self.toolbars[name] = toolbar
- # toolbar.setMovable(False)
- # toolbar.setFloatable(False)
- #
- # if self._current_toolbar_name != '':
- # self.refresh_toolbar_appearance()
-
- def moveEvent(self, a0: 'QMoveEvent') -> None:
- self.window_geometry_changed_signal.emit()
-
- def resizeEvent(self, a0: QResizeEvent) -> None:
- """
- 窗口大小调节,或者位置改变的信号。
- Window size adjustment, or a signal of a change in position.
- """
- self.size_restriction_acquire()
- super().resizeEvent(a0)
- self.delayed_call(500, self.size_restriction_release)
- self.window_geometry_changed_signal.emit()
-
- def on_settings_changed(self):
- load_theme(Settings.get_instance()['theme'])
-
- def delayed_call(self, time_ms: int, callback: Callable) -> None:
- """
- 封装了QTimer.SingleShot
- :param time_ms:
- :param callback:
- :return:
- """
- timer = QTimer()
- timer.singleShot(time_ms, callback)
-
- def size_restriction_acquire(self) -> None:
- """
- 设置插件尺寸的最大值。
- 控件需要指定get_split_portion_hint才可以。
- :return:
- """
- for k in self.dock_widgets.keys():
- dw = self.dock_widgets[k]
- horizontal_portion_hint = dw.widget().get_split_portion_hint()[0]
- if horizontal_portion_hint is not None:
- dw.setMaximumWidth(int(self.width() * horizontal_portion_hint))
- dw.setMinimumWidth(int(self.width() * horizontal_portion_hint))
-
- def size_restriction_release(self):
- for w_name in self.dock_widgets.keys():
- self.dock_widgets[w_name].setMaximumWidth(100000)
- self.dock_widgets[w_name].setMaximumHeight(100000)
- self.dock_widgets[w_name].setMinimumHeight(0)
- self.dock_widgets[w_name].setMinimumWidth(0)
-
- def on_main_window_shown(self):
- """
- 在界面显示后触发的事件。
- Returns: None
- """
- t0 = time.time()
- super().on_main_window_shown()
-
- self.layouts_ready_signal.emit()
- for task in self.setupui_tasks:
- task()
- self.widgets_ready_signal.emit()
- t1 = time.time()
- logging.info('Layout ready time elapsed:%f' % (t1 - t0))
- self.set_dock_titlebar_visible(Settings.get_instance()['dock_titlebar_visible'])
- self.bind_events()
- self.events_ready_signal.emit()
- t2 = time.time()
- logging.info('Events ready, time elapsed:%f' % (t2 - t1))
-
- def first_form_display(self):
- """
- 显示"快速操作"窗口
- Displays the "Quick Action" window
- """
- self.main_first_form = base.FirstForm(parent=self)
- self.main_first_form.show()
-
- def login_form_display(self):
- """
- 显示"登录"窗口
- Displays the "Quick Action" window
- """
- shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token
- buff = shared_memo.buf
- token = bytes(buff[:199]).decode().replace("\x00", "")
- if token != "":
- self.main_login_form = base.LoginedForm(parent=self)
- self.main_login_form.exec_()
- else:
- self.main_login_form = base.LoginForm(parent=self)
- self.main_login_form.exec_()
-
- def main_appstore_dispaly(self):
- """
- 显示"应用商店"窗口
- Displays the "App Store" window
- """
- self.appstore = MarketplaceForm()
- self.appstore.show()
-
- def main_option_display(self):
- """
- 显示"选项"窗口
- """
- if self.main_option_form is None:
- self.main_option_form = base.OptionForm()
- self.main_option_form.exec_()
-
- def main_help_display(self):
- """
- 打开帮助页面
- """
- utils.open_url("https://gitee.com/py2cn/pyminer/wikis")
-
- def main_check_update_display(self):
- """
- 打开'检查更新'页面
- """
- perform_update()
-
- def main_install_update(self):
- closed = self.close()
- if closed:
- from pmgwidgets import run_python_file_in_terminal
- path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'update', 'update.py')
- run_python_file_in_terminal(path + ' -i')
-
- def main_feedback_display(self):
- """
- 打开'反馈'页面
- """
- FeedbackClient()
- # reply = QMessageBox.information(self, self.tr('Feedback'), self.tr(
- # 'You can give feedback through issue on suggestions or problems encountered in use'),
- # QMessageBox.Yes | QMessageBox.No,
- # QMessageBox.Yes)
- # if reply == QMessageBox.Yes:
- # utils.open_url("https://gitee.com/py2cn/pyminer/issues")
-
- def main_homesite_display(self):
- """
- 打开官方网站页面
- """
- utils.open_url("http://www.pyminer.com")
-
- def main_markdown_display(self):
- print("TODO 添加markdown编辑器代码")
-
- def main_new_script_display(self):
- from features.extensions.extensionlib.extension_lib import extension_lib
- extension_lib.get_interface('code_editor').open_script('')
-
- def main_community_display(self):
- """
- 打开帮助页面
- """
- utils.open_url("https://www.kuxai.com/")
-
- def main_project_wizard_display(self):
- """
- 打开新建项目向导
- """
- self.wizard = project_wizard = base.ProjectWizardForm(parent=self)
- project_wizard.exec_()
-
- def main_about_display(self):
- """
- 打开关于页面,并将当前操作系统信息写入页面
- """
- self.about_me = base.AboutForm()
- self.about_me.show()
-
- def closeEvent(self, a0: QCloseEvent) -> None:
- """
- 主窗体退出时的事件,包括弹框提示等。Mac 上测试点击无法退出,修改为QMessageBox.Warning
- """
- reply = QMessageBox(QMessageBox.Warning, self.tr('Close'), self.tr('Are you sure close?'))
- reply.addButton(self.tr('OK'), QMessageBox.ActionRole)
- reply.addButton(self.tr('Cancel'), QMessageBox.RejectRole)
- if reply.exec_() == QMessageBox.RejectRole:
- a0.ignore()
- return
- else:
- a0.accept()
- self.delete_temporary_dock_windows()
- self.save_layout() # TODO:PySide2上存储布局有问题。
- Settings.get_instance().save()
- self.close_signal.emit()
- self.extensions_manager.stop()
- for k in self.dock_widgets.keys():
- self.dock_widgets[k].widget().closeEvent(a0)
- super().closeEvent(a0)
-
- def slot_flush_console(self, level: str, module, content):
- """刷新主窗体执行情况日志
-
- Args:
- level: 报错级别,包括 ``info`` , ``warnning`` , ``error`` 。
- module: 业务模块名称,例如 数据获取,数据处理,数据探索,统计,模型,可视化,评估
- content: 具体显示的内容
- """
- create_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 日志记录时间
- user = getpass.getuser()
- msg = create_time + ' ' + user + ' ' + level.upper() + ' [' + module + ']' + ':' + content
- if level == "error":
- html = "" + msg + ""
- else:
- html = "" + msg + ""
-
- console = self.log_output_console # 由于代码重构,这里出现了不同。
- console.moveCursor(QTextCursor.End)
- console.append(html)
diff --git a/pmgwidgets/utilities/platform/fileutils.py b/pmgwidgets/utilities/platform/fileutils.py
index 757a564575af47350f7fc19d17f44707257d95ba..f681e9dd412e92818792d333d97f6bc50315e29d 100644
--- a/pmgwidgets/utilities/platform/fileutils.py
+++ b/pmgwidgets/utilities/platform/fileutils.py
@@ -1,4 +1,5 @@
import os
+
import chardet
@@ -129,9 +130,5 @@ def copy_paste(source_path: str, target_path: str):
if __name__ == '__main__':
- # move_to_trash('C:/Users/12957/Desktop/1.jpg')
- create_file_if_not_exist(r'c:/users/12957/Desktop/rwrweew/ddddd/ggwewe/aaaaaa/as.a')
- create_file_if_not_exist(r'c:/users/12957/Desktop/rwrweew/ddddd/ggwewe/aaaaaa/aa.s')
- print(get_parent_path(r'c:/users/12957/desktop', 2))
- print(load_json(
- r'/pyminer2/extensions/packages/code_editor/customized/settings.json'))
+ print(get_parent_path(os.path.dirname(__file__), 2))
+ print(load_json(r'/pyminer2/extensions/packages/code_editor/customized/settings.json'))
diff --git a/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py
new file mode 100644
index 0000000000000000000000000000000000000000..f29581fd40a7539d9989e9cadd83cff8443c803c
--- /dev/null
+++ b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.py
@@ -0,0 +1,97 @@
+import os
+
+from PySide2 import QtCore
+from PySide2.QtCore import QItemSelectionModel
+from PySide2.QtWidgets import QApplication, QDialog
+from .Ui_ConsoleHistoryDialog import Ui_ConsoleHistoryDialog
+
+
+class ConsoleHistoryDialog(QDialog, Ui_ConsoleHistoryDialog):
+ """
+ Class implementing the shell history dialog.
+ """
+
+ def __init__(self, console):
+ super().__init__()
+ self.setupUi(self)
+ self.__console = console
+
+ self.deleteButton.clicked.connect(self.on_deleteButton_clicked)
+ self.copyButton.clicked.connect(self.on_copyButton_clicked)
+ self.reloadButton.clicked.connect(self.on_reloadButton_clicked)
+ self.historyList.itemSelectionChanged.connect(
+ self.on_historyList_itemSelectionChanged)
+
+ self.reloadButton.click()
+
+ @QtCore.Slot(QtCore.QModelIndex)
+ def select(self, item):
+ print(item.data())
+
+ @QtCore.Slot()
+ def on_historyList_itemSelectionChanged(self):
+ """
+ Private slot to handle a change of the selection.
+ """
+ selected = len(self.historyList.selectedItems()) > 0
+ self.deleteButton.setEnabled(selected)
+ self.copyButton.setEnabled(selected)
+ self.executeButton.setEnabled(selected)
+
+ @QtCore.Slot()
+ def on_deleteButton_clicked(self):
+ """
+ Private slot to delete the selected entries from the history.
+ """
+ for itm in self.historyList.selectedItems():
+ ditm = self.historyList.takeItem(self.historyList.row(itm))
+ del ditm
+ self.historyList.scrollToItem(self.historyList.currentItem())
+ self.historyList.setFocus()
+
+ @QtCore.Slot()
+ def on_copyButton_clicked(self):
+ cmds = self.selected_cmds()
+ QApplication.clipboard().setText(cmds)
+
+ @QtCore.Slot()
+ def on_executeButton_clicked(self):
+ cmds = self.selected_cmds()
+ self.__console.hint_command(cmds)
+ self.__console.do_execute(cmds, True, '')
+ # reload the list because shell modified it
+ self.on_reloadButton_clicked()
+
+ @QtCore.Slot()
+ def on_reloadButton_clicked(self):
+ """
+ Private slot to reload the history.
+ """
+ history = self.__console.history_tail(0)
+
+ self.historyList.clear()
+ self.historyList.addItems(history)
+ self.historyList.setCurrentRow(
+ self.historyList.count() - 1,
+ QItemSelectionModel.SelectionFlag.Select)
+
+ self.historyList.scrollToItem(self.historyList.currentItem())
+
+ @QtCore.Slot(QtCore.QModelIndex)
+ def on_historyList_doubleClicked(self, item):
+ self.on_executeButton_clicked()
+
+ def get_history(self):
+ history = []
+ for index in range(self.historyList.count()):
+ history.append(self.historyList.item(index).text())
+ return history
+
+ def selected_cmds(self):
+ lines = []
+ for index in range(self.historyList.count()):
+ # selectedItems() doesn't seem to preserve the order
+ itm = self.historyList.item(index)
+ if itm.isSelected():
+ lines.append(itm.text())
+ return (os.linesep.join(lines) + os.linesep).rstrip(os.linesep)
diff --git a/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui
new file mode 100644
index 0000000000000000000000000000000000000000..59fb25071e01b00c6c25df2d5d9fc3a43f153b58
--- /dev/null
+++ b/pmgwidgets/widgets/basic/others/ConsoleHistoryDialog.ui
@@ -0,0 +1,158 @@
+
+ ShellHistoryDialog
+
+
+
+ 0
+ 0
+ 540
+ 506
+
+
+
+ Shell History
+
+
+ true
+
+
+ -
+
+
+
+ Monospace
+
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+ true
+
+
+ QAbstractItemView::ExtendedSelection
+
+
+ true
+
+
+
+ -
+
+
-
+
+
+ false
+
+
+ Delete the selected entries
+
+
+ &Delete
+
+
+
+ -
+
+
+ false
+
+
+ Copy the selected entries to the current editor
+
+
+ C&opy
+
+
+
+ -
+
+
+ false
+
+
+ Execute the selected entries
+
+
+ &Execute
+
+
+
+ -
+
+
+ Reload the history
+
+
+ &Reload
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 72
+ 208
+
+
+
+
+
+
+ -
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+ historyList
+ deleteButton
+ copyButton
+ executeButton
+ reloadButton
+ buttonBox
+
+
+
+
+ buttonBox
+ accepted()
+ ShellHistoryDialog
+ accept()
+
+
+ 333
+ 487
+
+
+ 323
+ 505
+
+
+
+
+ buttonBox
+ rejected()
+ ShellHistoryDialog
+ reject()
+
+
+ 167
+ 490
+
+
+ 169
+ 504
+
+
+
+
+
diff --git a/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py b/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py
new file mode 100644
index 0000000000000000000000000000000000000000..e555d7aeaa3f82bbcf87ef1b1d224832f118e046
--- /dev/null
+++ b/pmgwidgets/widgets/basic/others/Ui_ConsoleHistoryDialog.py
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+# Form generated from reading UI file 'ConsoleHistoryDialog.ui'
+##
+# Created by: Qt User Interface Compiler version 6.1.0
+##
+# WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide2.QtCore import *
+from PySide2.QtGui import *
+from PySide2.QtWidgets import *
+
+
+class Ui_ConsoleHistoryDialog(object):
+ def setupUi(self, ConsoleHistoryDialog):
+ if not ConsoleHistoryDialog.objectName():
+ ConsoleHistoryDialog.setObjectName(u"ConsoleHistoryDialog")
+ ConsoleHistoryDialog.resize(540, 506)
+ ConsoleHistoryDialog.setSizeGripEnabled(True)
+ self.gridLayout = QGridLayout(ConsoleHistoryDialog)
+ self.gridLayout.setObjectName(u"gridLayout")
+ self.historyList = QListWidget(ConsoleHistoryDialog)
+ self.historyList.setObjectName(u"historyList")
+ font = QFont()
+ font.setFamilies([u"Monospace"])
+ self.historyList.setFont(font)
+ self.historyList.setEditTriggers(QAbstractItemView.NoEditTriggers)
+ self.historyList.setAlternatingRowColors(True)
+ self.historyList.setSelectionMode(QAbstractItemView.ExtendedSelection)
+ self.historyList.setWordWrap(True)
+
+ self.gridLayout.addWidget(self.historyList, 0, 0, 1, 1)
+
+ self.verticalLayout = QVBoxLayout()
+ self.verticalLayout.setObjectName(u"verticalLayout")
+ self.deleteButton = QPushButton(ConsoleHistoryDialog)
+ self.deleteButton.setObjectName(u"deleteButton")
+ self.deleteButton.setEnabled(False)
+
+ self.verticalLayout.addWidget(self.deleteButton)
+
+ self.copyButton = QPushButton(ConsoleHistoryDialog)
+ self.copyButton.setObjectName(u"copyButton")
+ self.copyButton.setEnabled(False)
+
+ self.verticalLayout.addWidget(self.copyButton)
+
+ self.executeButton = QPushButton(ConsoleHistoryDialog)
+ self.executeButton.setObjectName(u"executeButton")
+ self.executeButton.setEnabled(False)
+
+ self.verticalLayout.addWidget(self.executeButton)
+
+ self.reloadButton = QPushButton(ConsoleHistoryDialog)
+ self.reloadButton.setObjectName(u"reloadButton")
+
+ self.verticalLayout.addWidget(self.reloadButton)
+
+ self.verticalSpacer = QSpacerItem(
+ 72, 208, QSizePolicy.Minimum, QSizePolicy.Expanding)
+
+ self.verticalLayout.addItem(self.verticalSpacer)
+
+ self.gridLayout.addLayout(self.verticalLayout, 0, 1, 1, 1)
+
+ self.buttonBox = QDialogButtonBox(ConsoleHistoryDialog)
+ self.buttonBox.setObjectName(u"buttonBox")
+ self.buttonBox.setStandardButtons(
+ QDialogButtonBox.Cancel | QDialogButtonBox.Ok)
+
+ self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 2)
+
+ QWidget.setTabOrder(self.historyList, self.deleteButton)
+ QWidget.setTabOrder(self.deleteButton, self.copyButton)
+ QWidget.setTabOrder(self.copyButton, self.executeButton)
+ QWidget.setTabOrder(self.executeButton, self.reloadButton)
+ QWidget.setTabOrder(self.reloadButton, self.buttonBox)
+
+ self.retranslateUi(ConsoleHistoryDialog)
+ self.buttonBox.accepted.connect(ConsoleHistoryDialog.accept)
+ self.buttonBox.rejected.connect(ConsoleHistoryDialog.reject)
+
+ QMetaObject.connectSlotsByName(ConsoleHistoryDialog)
+ # setupUi
+
+ def retranslateUi(self, ConsoleHistoryDialog):
+ ConsoleHistoryDialog.setWindowTitle(QCoreApplication.translate(
+ "ConsoleHistoryDialog", u"Shell History", None))
+# if QT_CONFIG(tooltip)
+ self.deleteButton.setToolTip(QCoreApplication.translate(
+ "ConsoleHistoryDialog", u"Delete the selected entries", None))
+#endif // QT_CONFIG(tooltip)
+ self.deleteButton.setText(QCoreApplication.translate(
+ "ConsoleHistoryDialog", u"&Delete", None))
+# if QT_CONFIG(tooltip)
+ self.copyButton.setToolTip(QCoreApplication.translate(
+ "ConsoleHistoryDialog", u"Copy the selected entries to the current editor", None))
+#endif // QT_CONFIG(tooltip)
+ self.copyButton.setText(QCoreApplication.translate(
+ "ConsoleHistoryDialog", u"C&opy", None))
+# if QT_CONFIG(tooltip)
+ self.executeButton.setToolTip(QCoreApplication.translate(
+ "ConsoleHistoryDialog", u"Execute the selected entries", None))
+#endif // QT_CONFIG(tooltip)
+ self.executeButton.setText(QCoreApplication.translate(
+ "ConsoleHistoryDialog", u"&Execute", None))
+# if QT_CONFIG(tooltip)
+ self.reloadButton.setToolTip(QCoreApplication.translate(
+ "ConsoleHistoryDialog", u"Reload the history", None))
+#endif // QT_CONFIG(tooltip)
+ self.reloadButton.setText(QCoreApplication.translate(
+ "ConsoleHistoryDialog", u"&Reload", None))
+ # retranslateUi
diff --git a/pmgwidgets/widgets/basic/others/console.py b/pmgwidgets/widgets/basic/others/console.py
index 8cb374e41cc8b055d2d36acf061de410ae260c70..591f5e908683aadd7407b4d60942c49119787636 100644
--- a/pmgwidgets/widgets/basic/others/console.py
+++ b/pmgwidgets/widgets/basic/others/console.py
@@ -8,18 +8,21 @@ Created on 2020/8/24
@file: console.py
@description: Console Widget
"""
-
+import logging
import os
+import sys
+import json
from typing import Tuple, Dict, Callable
from PySide2.QtCore import QObject, Signal, QThread, QWaitCondition, QMutex, QPoint, QCoreApplication, QTranslator, \
QLocale
from PySide2.QtGui import QTextCursor
-from PySide2.QtWidgets import QMessageBox, QMenu, QApplication
+from PySide2.QtWidgets import QMessageBox, QMenu, QApplication, QDialog
from qtconsole import styles
from qtconsole.manager import QtKernelManager
from qtconsole.rich_jupyter_widget import RichJupyterWidget
from qtconsole.styles import default_light_syntax_style, default_light_style_sheet
+from features.io import settings
default_dark_style_template = styles.default_template + """\
.in-prompt { color: #ff00ff; }
@@ -29,6 +32,10 @@ default_dark_style_sheet = default_dark_style_template % dict(
bgcolor='#19232d', fgcolor='white', select="#ccc")
default_dark_syntax_style = 'monokai' # 'default'
+logging.basicConfig(stream=sys.stderr)
+logger = logging.getLogger(__name__)
+logger.setLevel(logging.DEBUG)
+
class ConsoleInitThread(QObject):
initialized = Signal(object, object)
@@ -40,7 +47,12 @@ class ConsoleInitThread(QObject):
def run(self):
self.mutex.lock()
- kernel_manager = QtKernelManager(kernel_name='python3')
+ kernel_manager = QtKernelManager(kernel_name="python3")
+ logger.debug("installed kernel start method")
+
+ # kernel_manager.kernel_spec.argv[0] = r"C:\Users\12957\AppData\Local\Programs\Python\Python38\python.exe"
+ kernel_manager.kernel_spec.argv[0] = sys.executable
+ # 这一步的目的是,指明要连接到的解释器。
kernel_manager.start_kernel()
kernel_client = kernel_manager.client()
@@ -68,6 +80,8 @@ class PMGIpythonConsole(RichJupyterWidget):
self.is_first_execution = True
self.confirm_restart = False
+ self.history_path = os.path.join(settings.get_pyminer_data_path(), 'console_history.json')
+ self.history = []
self.commands_pool = []
self.command_callback_pool: Dict[str, Callable] = {}
@@ -116,6 +130,7 @@ class PMGIpythonConsole(RichJupyterWidget):
self.init_thread.finished.connect(self.init_thread.deleteLater)
self.init_thread.started.connect(self.console_object.run)
self.init_thread.start()
+ logger.debug("setup--ui")
cursor: QTextCursor = self._prompt_cursor
cursor.movePosition(QTextCursor.End)
@@ -133,16 +148,33 @@ class PMGIpythonConsole(RichJupyterWidget):
trans = trans_dic.get(action.text())
trans = trans if trans is not None else action.text()
action.setText(trans)
- restart_action = menu.addAction(_translate("PMGIpythonConsole", 'Restart'))
+ history_action = menu.addAction(
+ _translate("PMGIpythonConsole", 'History'))
+ history_action.triggered.connect(self.show_history)
+
+ restart_action = menu.addAction(
+ _translate("PMGIpythonConsole", 'Restart'))
restart_action.triggered.connect(self.slot_restart_kernel)
- stop_action = menu.addAction(_translate("PMGIpythonConsole", 'Interrupt'))
+ stop_action = menu.addAction(
+ _translate("PMGIpythonConsole", 'Interrupt'))
# stop_action.triggered.connect(self.request_interrupt_kernel)
stop_action.triggered.connect(self.on_interrupt_kernel)
# stop_action.setEnabled(self._executing)
return menu
+ def show_history(self):
+ """
+ Public slot to show the shell history dialog.
+ """
+ from .ConsoleHistoryDialog import ConsoleHistoryDialog
+ # import readline
+ dlg = ConsoleHistoryDialog(self)
+ if dlg.exec() == QDialog.DialogCode.Accepted:
+ self.history = dlg.get_history()
+ super()._set_history(self.history)
+
def on_interrupt_kernel(self):
"""
当点击中断执行时。
@@ -200,6 +232,8 @@ class PMGIpythonConsole(RichJupyterWidget):
return 'Welcome To PMGWidgets Ipython Console!\n'
def closeEvent(self, event):
+ self.history = self.history_tail(0)
+ self.save_history()
if self.init_thread.isRunning():
self.console_object.stop()
self.init_thread.quit()
@@ -224,6 +258,14 @@ class PMGIpythonConsole(RichJupyterWidget):
:param hint_text: 运行代码前显示的提示
:return: str 执行命令的 msgid
"""
+ self.hint_command(hint_text)
+ if self.kernel_client is None:
+ self.commands_pool.append((source, hidden, hint_text))
+ return ''
+ else:
+ return self.pmexecute(source, hidden)
+
+ def hint_command(self, hint_text: str = '') -> str:
cursor: QTextCursor = self._prompt_cursor
cursor.movePosition(QTextCursor.End)
# 运行文件时,显示文件名,无换行符,执行选中内容时,包含换行符
@@ -237,13 +279,9 @@ class PMGIpythonConsole(RichJupyterWidget):
# 删除多余的continuation_prompt
self.undo()
- self._finalize_input_request() # display input string buffer in console.
+ # display input string buffer in console.
+ self._finalize_input_request()
cursor.movePosition(QTextCursor.End)
- if self.kernel_client is None:
- self.commands_pool.append((source, hidden, hint_text))
- return ''
- else:
- return self.pmexecute(source, hidden)
def _handle_stream(self, msg):
parent_header = msg.get('parent_header')
@@ -304,6 +342,22 @@ class PMGIpythonConsole(RichJupyterWidget):
directory=os.path.join(os.path.dirname(__file__), 'translations'))
app.installTranslator(_trans)
+ def _set_history(self, history):
+ """ 重写的方法。重新管理历史记录。
+ """
+ self.load_history()
+ super()._set_history(self.history)
+
+ def load_history(self):
+ if os.path.exists(self.history_path):
+ with open(self.history_path) as f:
+ history = json.load(f)
+ self.history = history['history']
+
+ def save_history(self):
+ history = {'history': self.history}
+ with open(self.history_path, 'w') as f:
+ json.dump(history, f)
if __name__ == '__main__':
import sys
@@ -311,7 +365,7 @@ if __name__ == '__main__':
cgitb.enable(format='text')
app = QApplication([])
- os.environ['IPYTHON_AS_PYMINER_NODE'] = '1'
+ # os.environ['IPYTHON_AS_PYMINER_NODE'] = '1'
PMGIpythonConsole.install_translator()
w = PMGIpythonConsole()
w.show()
diff --git a/pmgwidgets/widgets/composited/fastui.py b/pmgwidgets/widgets/composited/fastui.py
index 6d2df6b05db6940f943ff0025e88cf1181ed345c..6f3a80a77e0c30f118f4cac1baa3f18190329ad7 100644
--- a/pmgwidgets/widgets/composited/fastui.py
+++ b/pmgwidgets/widgets/composited/fastui.py
@@ -241,15 +241,16 @@ class FunctionGUIDialog(DFOperationDialog):
if arg["optional"]:
optional_names.append(arg["name"])
views.append(("check_ctrl", arg["name"] + "#enable", "", True))
+ arg["ctrl"]["name"] = arg["name"]
views.append(arg["ctrl"])
self.panel.set_items(views)
-
for op_name in optional_names:
self.panel.set_as_controller(op_name + "#enable", [op_name], True, )
def get_value_code(self) -> str:
values = self.panel.get_value_with_filter() # 只获取使能并且可见的控件的值
+ print(values,self.panel.widgets_dic)
values = {k: v for k, v in values.items() if k.isidentifier()}
varname = self.combo_box.currentText()
args_str = ''
@@ -261,7 +262,7 @@ class FunctionGUIDialog(DFOperationDialog):
code = '{var_name}.{method_name}({args})'.format(var_name=varname,
method_name=self.func_name,
args=args_str)
-
+ print(code,values)
return code
diff --git a/pmgwidgets/widgets/extended/entries/funcctrl.py b/pmgwidgets/widgets/extended/entries/funcctrl.py
new file mode 100644
index 0000000000000000000000000000000000000000..a3820c22b51d4971476b06eb174de68355b0a68f
--- /dev/null
+++ b/pmgwidgets/widgets/extended/entries/funcctrl.py
@@ -0,0 +1,101 @@
+import ast
+import astunparse
+from typing import Any, Tuple, List
+
+from PySide2.QtWidgets import QLineEdit, QLabel, QHBoxLayout, QPushButton, QMessageBox
+
+from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget
+
+
+class CodeVisitor(ast.NodeVisitor):
+ def __init__(self):
+ super(CodeVisitor, self).__init__()
+ self.preserved = {"pi", "e"}
+ self.called = set()
+ self.func_args = set()
+ self._names = set()
+
+ def visit_Name(self, node: ast.Name) -> Any:
+ self._names.add(node.id)
+
+
+ def visit_Call(self, node: ast.Call) -> Any:
+ self.generic_visit(node)
+ self.called.add(node.func.id)
+
+ def get_result(self) -> Tuple[List[str], List[str]]:
+ """
+
+ Returns: 定义的名称,以及调用的ID名称。
+
+ """
+ names = self._names.copy()
+ names.difference_update(self.preserved)
+ names.difference_update(self.called)
+ return list(names), list(self.called)
+
+
+# n = ast.parse("x*cos(v,sin(2*pi*x))")
+# print(CodeVisitor().visit(n))
+# print(cv := CodeVisitor())
+# cv.visit(n)
+# print(cv.get_result())
+# # # print(ast.get_source_segment("x*cos(v,sin(2*pi*x))",n))
+# # print(ast.dump(n))
+# # print(astunparse.unparse(n))
+
+
+class PMGFuncCtrl(BaseExtendedWidget):
+ """
+
+ 输入:一个有效的函数表达式。
+ 其中,里面的变量名会自动进行检测。
+
+ """
+
+ def __init__(self, layout_dir: str, title: str, initial_value: str):
+ super().__init__(layout_dir)
+ self.allowed_chars = set(' ,[](){}:1234567890.+-*/')
+ self.on_check_callback = None
+ self.prefix = QLabel(text=title)
+ self.type = type
+ entryLayout = QHBoxLayout()
+ self.ctrl = QLineEdit()
+ self.central_layout.addWidget(self.prefix)
+ self.central_layout.addLayout(entryLayout)
+ entryLayout.addWidget(self.ctrl)
+ self.set_value(initial_value)
+
+ def get_code(self) -> str:
+ text = self.ctrl.text()
+ if self.type == 'safe':
+ for char in text:
+ if char not in self.allowed_chars:
+ return None
+ return text
+
+ def set_value(self, obj: Any):
+ try:
+ self.ctrl.setText(repr(obj))
+ except:
+ import traceback
+ traceback.print_exc()
+
+ def get_value(self) -> object:
+ if self.get_code() is not None:
+ try:
+ return eval(self.ctrl.text())
+ except:
+ import traceback
+ traceback.print_exc()
+ return None
+ else:
+ return None
+
+ def on_eval_test(self):
+ """
+ 点击计算按钮,弹出对话框显示计算结果。
+ :return:
+ """
+ val = self.get_value()
+ QMessageBox.information(self, self.tr('Result'), repr(val), QMessageBox.Ok)
diff --git a/pmgwidgets/widgets/extended/others/multitypeparaminput.py b/pmgwidgets/widgets/extended/others/multitypeparaminput.py
index fb60d0cf00fbc307c34312e350569a508f4d0e20..65f20666025da1d0ab1b450edf5b505768125939 100644
--- a/pmgwidgets/widgets/extended/others/multitypeparaminput.py
+++ b/pmgwidgets/widgets/extended/others/multitypeparaminput.py
@@ -35,7 +35,7 @@ class PMGMultiTypeCtrl(BaseExtendedWidget):
index = self.get_type_index()
self.sub_panel.set_items([self.ctrls[index]["ctrls"]])
- print(self.get_value())
+ # print(self.get_value())
# self.setFixedSize(0)
def on_param_changed(self, event):
diff --git a/pmlocalserver/server.py b/pmlocalserver/server.py
index 80e2d11a18462b9bd5d77eabe54cb70a5f4d3cb8..745325d7dc6f4aecde3bd60b6d987d2883f7dd47 100644
--- a/pmlocalserver/server.py
+++ b/pmlocalserver/server.py
@@ -1,6 +1,8 @@
-from flask import Flask
+import threading
+from flask import Flask
from flask_cors import CORS
+
import threading
from multiprocessing import shared_memory
diff --git a/pyminer_comm/base/datadesc.py b/pyminer_comm/base/datadesc.py
index 19cdf9967517202228b6786d662a961c02f1e730..7faa7753a6da4634be5347e304c03b85a0d37ed8 100644
--- a/pyminer_comm/base/datadesc.py
+++ b/pyminer_comm/base/datadesc.py
@@ -33,24 +33,34 @@ class NoPreviewError(Exception):
def is_big_variable(var):
- import pandas as pd
- import numpy as np
+ """
+ 判断是否为大型变量。
+ 对于较大的变量,需要采用预览模式。
+ Args:
+ var:
+
+ Returns:
+ """
if isinstance(var, (int, bool, float)):
return sys.getsizeof(var) > DataDesc.threshold_pandas
- if isinstance(var, str):
+ elif isinstance(var, str):
return len(var) > DataDesc.max_str_len
- elif isinstance(var, (pd.DataFrame, pd.Series)):
+ elif isinstance(var, dict):
+ return len(list(var.keys())) > DataDesc.max_len
+ elif isinstance(var, (list, tuple)):
+ return len(var) > DataDesc.max_len
+
+ import pandas as pd
+ import numpy as np
+ if isinstance(var, (pd.DataFrame, pd.Series)):
if isinstance(var, pd.DataFrame):
return int(var.memory_usage().sum()) - DataDesc.threshold_pandas > 0
else:
return var.memory_usage() - DataDesc.threshold_pandas > 0
elif isinstance(var, np.ndarray):
return var.nbytes > DataDesc.threshold_numpy
- elif isinstance(var, dict):
- return len(list(var.keys())) > DataDesc.max_len
- elif isinstance(var, (list, tuple)):
- return len(var) > DataDesc.max_len
+
else:
return False
diff --git a/pyminer_comm/pyminer_client/pm_client.py b/pyminer_comm/pyminer_client/pm_client.py
index 12c259dc8308e0267206ebcc7897907529ddbef6..a16f941b36265f36fdee97f649e641c38117c8d4 100644
--- a/pyminer_comm/pyminer_client/pm_client.py
+++ b/pyminer_comm/pyminer_client/pm_client.py
@@ -21,7 +21,7 @@ def modify_settings(items: Dict[str, Any]):
"""
assert isinstance(items, dict), items
res = get('modify_settings', dict_to_b64(items, protocol=get_protocol()), 12306, )
-
+ return res
def set_data_desc_dic(data: Dict[str, Any]) -> None:
for k, v in data.items():
diff --git a/requirements.txt b/requirements.txt
index 6f0eae7e0526862efe32a418e8b3239970d0d772..45dd7f3790da85cc71eaf037ff5fb6c641db9c19 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,7 +6,7 @@ jdcal>=1.4.1
joblib>=0.16.0
kiwisolver>=1.2.0
numpy==1.19.3
-matplotlib>=3.3.1
+matplotlib>=3.4.1
openpyxl>=3.0.4
xlrd>=1.2.0
pandas>=1.1.1
@@ -57,5 +57,6 @@ cx_Oracle>=8.1.0
pyminer_comm>=0.7.1
ipyparams
pathspec
+codegen
diff --git a/requirements_linux.txt b/requirements_linux.txt
index 0ebaca1065fa0b6621650af321ac7cceff31118c..aa3b7350fb4e504f406f8456907dd3bbd6828e24 100644
--- a/requirements_linux.txt
+++ b/requirements_linux.txt
@@ -6,7 +6,7 @@ helpdev>=0.7.1
jdcal>=1.4.1
joblib>=0.16.0
kiwisolver>=1.2.0
-matplotlib>=3.3.1
+matplotlib>=3.4.1
numpy==1.19.1
openpyxl>=3.0.4
pandas>=1.1.1
diff --git a/requirements_mac.txt b/requirements_mac.txt
index fa5b0d707314f26163c21cc04eeca80553a70215..9c625abe4f30fe9af411ed1b0591aaaa3652ca3f 100644
--- a/requirements_mac.txt
+++ b/requirements_mac.txt
@@ -5,7 +5,7 @@ helpdev>=0.7.1
jdcal>=1.4.1
joblib>=0.16.0
kiwisolver>=1.2.0
-matplotlib>=3.3.1
+matplotlib>=3.4.1
numpy==1.19.1
openpyxl>=3.0.4
pandas>=1.1.1
diff --git a/resources/qss/Fusion.qss b/resources/qss/Fusion.qss
index f4d798d8ffc0646ca7b202d914dd50b8f3e2f0ff..9b4ebb6ce36cb8d17f3fd113d20e06aaa2120a03 100644
--- a/resources/qss/Fusion.qss
+++ b/resources/qss/Fusion.qss
@@ -15,10 +15,10 @@ QDockWidget::title{
}
QPushButton{
- background-color: MAIN_THEME;
+ background-color: #F7F7F7;
}
QPushButton:hover{
- background-color:MARGIN_THEME;
+ background-color:#DADADA;
}
QPushButton#pmtopToolbarButton[stat="unselected"]:hover{
@@ -29,7 +29,7 @@ QPushButton#pmtopToolbarButton[stat="selected"]{
margin: 5px 5px -5px 5px;
min-width: 120px;
border-radius:5px;
- background-color: MAIN_THEME;
+ background-color: #F7F7F7;
}
QPushButton#pmtopToolbarButton[stat="unselected"]{
padding: 5px 0px 10px 0px;
@@ -66,10 +66,10 @@ QToolButton{
border-radius:5px;
}
QToolButton:hover{
- background-color:MARGIN_THEME;
+ background-color:#DADADA;
}
QToolButton::checked{
- background-color:MARGIN_THEME;
+ background-color:#DADADA;
}
QToolButton#hidebutton {
max-width: 15px;
@@ -110,14 +110,14 @@ QToolButton#stacked_tool_button::menu-indicator:image{
/*以下几行设定的是滚动条的横竖向功能*/
QScrollBar::vertical {
- background: MARGIN_THEME;
+ background: #DADADA;
border: -0px solid grey;
margin: 0px 0px 0px 0px;
width: 10px;
border-radius:5px;
}
QScrollBar::horizontal {
- background: MARGIN_THEME;
+ background: #DADADA;
border: -0px solid grey;
margin: 0px 0px 0px 0px;
height:10px;
@@ -127,17 +127,17 @@ QScrollBar::horizontal {
QScrollBar::handle:vertical{
border-radius:3px;
min-height:30px;
-background:MARGIN_THEME;
+background:#DADADA;
}
QScrollBar::handle:horizontal{
border-radius:3px;
min-width:30px;
-background:MARGIN_THEME;
+background:#DADADA;
}
QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
- background: MAIN_THEME;
+ background: #F7F7F7;
border:0px;
}
diff --git a/resources/qss/standard.qss b/resources/qss/standard.qss
index b2e7ad2a86f030513bf0ada1cad540e3248bdf5b..cb94871684ae89f7df72beb11eff51352d9105ce 100644
--- a/resources/qss/standard.qss
+++ b/resources/qss/standard.qss
@@ -5,20 +5,20 @@ github链接:
https://github.com/PyQt5/PyQt/blob/master/QScrollArea/Data/style.qss
文件加载时,将会自动替换MAIN_THEME和MARGIN_THEME为相应的颜色。
*/
-QMainWindow{background-color:MAIN_THEME;}
-QDialog{background-color:MAIN_THEME;}
+QMainWindow{background-color:#F7F7F7;}
+QDialog{background-color:#F7F7F7;}
QAbstractScrollArea{
- border:1px solid MARGIN_THEME;
+ border:1px solid #DADADA;
}
TopToolBar {
- border-bottom: 1px solid MARGIN_THEME;
- border-top: 1px solid MARGIN_THEME;
+ border-bottom: 1px solid #DADADA;
+ border-top: 1px solid #DADADA;
}
TopToolBarRight {
- border-bottom: 1px solid MARGIN_THEME;
- border-top: 1px solid MARGIN_THEME;
+ border-bottom: 1px solid #DADADA;
+ border-top: 1px solid #DADADA;
}
QDockWidget {
@@ -49,12 +49,12 @@ QDockWidget::close-button:pressed, QDockWidget::float-button:pressed {
}
QPushButton{
- border:1px solid MARGIN_THEME;
+ border:1px solid #DADADA;
border-radius:5px;
height:20px;
width:80px;
}
-QPushButton:hover{background-color:MARGIN_THEME;}
+QPushButton:hover{background-color:#DADADA;}
/*按钮停留态*/
QPushButton#pmtopToolbarButton[stat="selected"]{
/*背景颜色*/
@@ -62,7 +62,7 @@ QPushButton#pmtopToolbarButton[stat="selected"]{
padding:0px 0px 0px 0px;
border:1px;
border-radius:8px;
- background-color:MARGIN_THEME;
+ background-color:#DADADA;
}
QPushButton#pmtopToolbarButton[stat="unselected"]{
@@ -71,7 +71,7 @@ QPushButton#pmtopToolbarButton[stat="unselected"]{
padding:0px 0px 0px 0px;
border:1px;
border-radius:8px;
- background-color:MAIN_THEME;
+ background-color:#F7F7F7;
}
QPushButton#pmtopToolbarButton:hover{
@@ -86,7 +86,7 @@ QPushButton#pmtopToolbarButton:hover{
QPushButton:hover
{
/*背景颜色*/
- background-color:MARGIN_THEME;
+ background-color:#DADADA;
}
QToolBar{
height:100px;
@@ -104,7 +104,7 @@ QToolButton{
QToolButton:hover
{
/*背景颜色*/
- background-color:MARGIN_THEME;
+ background-color:#DADADA;
}
/*toolbutton下三角居中靠下显示*/
QToolButton::menu-indicator:image{
@@ -115,14 +115,14 @@ QToolButton::menu-indicator:image{
QScrollBar::vertical {
- background: MARGIN_THEME;
+ background: #DADADA;
border: -0px solid grey;
margin: 0px 0px 0px 0px;
width: 10px;
border-radius:5px;
}
QScrollBar::horizontal {
- background: MARGIN_THEME;
+ background: #DADADA;
margin: 0px 0px 0px 0px;
height:10px;
@@ -130,16 +130,16 @@ QScrollBar::horizontal {
QScrollBar::handle:vertical{
border-radius:3px;
-background:MARGIN_THEME;
+background:#DADADA;
}
QScrollBar::handle:horizontal{
border-radius:3px;
-background:MARGIN_THEME;
+background:#DADADA;
}
QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
- background: MAIN_THEME;
+ background: #F7F7F7;
border:0px;
}
QMessageBox QPushButton[text="OK"] {
diff --git a/resources/qss/windowsvista.qss b/resources/qss/windowsvista.qss
index 5c87512ef931023fdaa025d7554a47b61dea10b5..dc95f29a72661d50de888ea57b12fee417dee2a0 100644
--- a/resources/qss/windowsvista.qss
+++ b/resources/qss/windowsvista.qss
@@ -53,7 +53,7 @@ QToolButton{
border-radius:5px;
}
QToolButton:hover{
- background-color:MARGIN_THEME;
+ background-color: #DADADA;
}
QToolButton#hidebutton {
max-width: 15px;
diff --git a/run_before_commit.py b/run_before_commit.py
index 16b7e903a056cb0b0bf56c331c1660a5f4114483..7440b2e1a0f6b7d4024a864e61b8800be2516ce3 100644
--- a/run_before_commit.py
+++ b/run_before_commit.py
@@ -1,6 +1,16 @@
"""
这个文件需要在提交之前运行,从而正确的生成更新包。
+在更新之后,需要检查:
+1、最新的版本启动后,是否还会提示要更新。如果是,那么说明可能文件存在错误,或者并未正确执行此文件。
+2、最新打包的版本,其中是否因为某些包的更新而发生错误。典型例子就是Matplotlib升级成3.4.1版本之后,废止了旧的某个类,导致PMAgg不能运行。
+
+还有一些问题:
+是否需要发布大版本更新的提示?比如,当版本更新中包含pip包版本升级的时候,是否需要提示用户?
+如何处理用户升级解释器中包的问题?是否要提示,默认解释器不得安装requirements.txt中已有的包?
+
+是否需要支持切换解释器的工作空间?
+
"""
import os
@@ -9,4 +19,4 @@ import sys
from utils import get_root_dir
os.system(f"{sys.executable} {os.path.join(get_root_dir(), 'features', 'util', 'make_update.py')}")
-print("已经运行完成,现在可以提交了。")
+print("已经运行完成。现在还需要进行一次更新测试,确认已是最新版本,便可以提交到主分支了。")
diff --git a/utils/__init__.py b/utils/__init__.py
index fcb4d50b3614580f046dfb8fcdbcd9cfbea0da01..e70f3f750d54d570c6e0ec2f83899d1d0346d38b 100644
--- a/utils/__init__.py
+++ b/utils/__init__.py
@@ -3,17 +3,9 @@
#
# 通用工具,可以在全局进行调用。
-import os
-import datetime
-import logging
import webbrowser
-from .path import (
- get_root_dir,
- get_user_dir,
- get_desktop_dir,
- get_documents_dir,
-)
+from .debug import *
from .environ import (
get_python_version,
get_python_modules_directory,
@@ -21,6 +13,17 @@ from .environ import (
getScriptsPath,
getDesignerPath
)
+from .io import *
+from .path import (
+ get_root_dir,
+ get_user_dir,
+ get_desktop_dir,
+ get_documents_dir,
+ get_pyminer_data_dir,
+ get_user_config_dir,
+ get_default_config_dir,
+ get_config_file_dir
+)
from .platform import (
is_windows_platform,
is_mac_platform,
@@ -28,23 +31,20 @@ from .platform import (
is_kde_desktop,
is_gnome_desktop
)
-
-from .io import *
-from .debug import *
+from .settings import *
from .ui import *
-from typing import TYPE_CHECKING
-
if TYPE_CHECKING:
- import pmgui
-version = 'v2.1.0 Beta'
+ import app2
+ from PySide2.QtWidgets import QApplication
+# version = 'v2.1.0 Beta' 这里原有version ,但是考虑到这些信息写在静态文件中较好,所以就写在了文件中。
-_application = None
+_application = Optional["QApplication"]
_root_dir = None
-_main_window: Optional["pmgui.MainWindow"] = None
+_main_window: Optional["app2.MainWindow"] = None
-def get_application() -> None:
+def get_application() -> "QApplication":
"""
获取QApplication
Returns:
@@ -54,7 +54,7 @@ def get_application() -> None:
return _application
-def get_main_window() -> Optional["pmgui.MainWindow"]:
+def get_main_window() -> Optional["app2.MainWindow"]:
"""
获取主窗口或者主控件。
Returns:
@@ -67,8 +67,7 @@ def get_work_dir() -> 'str':
获取主窗口或者主控件。
Returns:
"""
- from features.io.settings import Settings
- return Settings.get_instance()['work_dir']
+ return get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR")
def open_url(url):
@@ -80,47 +79,46 @@ def open_url(url):
except Exception as e:
webbrowser.open_new_tab(url)
-
-def unzip_file(zip_src: str, dst_dir: str):
- """
- 解压文件
- Args:
- zip_src:
- dst_dir:
-
- Returns:
-
- """
- r = zipfile.is_zipfile(zip_src)
- if r:
- fz = zipfile.ZipFile(zip_src, 'r')
- for file in fz.namelist():
- fz.extract(file, dst_dir)
- else:
- print('This is not zip')
-
-
-def make_zip(src_path, zip_dist_path, root='', rules=None):
- """
- 创建zip包
- Args:
- src_path:
- zip_dist_path:
- root:
- rules:
-
- Returns:
-
- """
- if rules is None:
- rules = []
- z = zipfile.ZipFile(zip_dist_path, 'w', zipfile.ZIP_DEFLATED)
- for dirpath, dirnames, filenames in os.walk(src_path):
- relpath = os.path.relpath(dirpath, src_path)
- if is_neglect_path(relpath, rules):
- continue
- fpath = os.path.relpath(dirpath, src_path)
- for filename in filenames:
- filepath = os.path.join(dirpath, filename)
- z.write(filepath, os.path.join(root, fpath, filename))
- z.close()
+# def unzip_file(zip_src: str, dst_dir: str):
+# """
+# 解压文件
+# Args:
+# zip_src:
+# dst_dir:
+#
+# Returns:
+#
+# """
+# r = zipfile.is_zipfile(zip_src)
+# if r:
+# fz = zipfile.ZipFile(zip_src, 'r')
+# for file in fz.namelist():
+# fz.extract(file, dst_dir)
+# else:
+# print('This is not zip')
+#
+#
+# def make_zip(src_path, zip_dist_path, root='', rules=None):
+# """
+# 创建zip包
+# Args:
+# src_path:
+# zip_dist_path:
+# root:
+# rules:
+#
+# Returns:
+#
+# """
+# if rules is None:
+# rules = []
+# z = zipfile.ZipFile(zip_dist_path, 'w', zipfile.ZIP_DEFLATED)
+# for dirpath, dirnames, filenames in os.walk(src_path):
+# relpath = os.path.relpath(dirpath, src_path)
+# if is_neglect_path(relpath, rules):
+# continue
+# fpath = os.path.relpath(dirpath, src_path)
+# for filename in filenames:
+# filepath = os.path.join(dirpath, filename)
+# z.write(filepath, os.path.join(root, fpath, filename))
+# z.close()
diff --git a/utils/path.py b/utils/path.py
index dd93c32747998f2630c1b8ef4621f0750898a9c6..fc36a9629392bd27afbace3600a46a9eae2b431f 100644
--- a/utils/path.py
+++ b/utils/path.py
@@ -3,9 +3,12 @@
# Get application path information
# 获取应用路径信息
import os
-import sys
+import shutil
+
from PySide2.QtCore import QStandardPaths
+from .settings import SETTINGS_FILES
+
def get_root_dir() -> str:
"""
@@ -121,21 +124,71 @@ def get_path_generic_cache() -> str:
return path
-def get_path_generic_config() -> str:
- path = QStandardPaths.writableLocation(QStandardPaths.GenericConfigLocation)
+# def get_path_generic_config() -> str:
+# path = QStandardPaths.writableLocation(QStandardPaths.GenericConfigLocation)
+# return path
+
+
+# def get_path_app_data() -> str:
+# path = QStandardPaths.writableLocation(QStandardPaths.AppDataLocation)
+# return path
+
+
+# def get_path_app_config() -> str:
+# path = QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation)
+# return path
+
+
+def get_path_app_local_data() -> str:
+ path = QStandardPaths.writableLocation(QStandardPaths.AppLocalDataLocation)
return path
-def get_path_app_data() -> str:
- path = QStandardPaths.writableLocation(QStandardPaths.AppDataLocation)
+def get_pyminer_data_dir() -> str:
+ """
+ 获取PyMiner的数据文件存储位置,一般为.pyminer文件夹。
+ Returns:
+
+ """
+ path = os.path.join(os.path.expanduser('~'), '.pyminer')
+ if not os.path.exists(path):
+ os.makedirs(path)
return path
-def get_path_app_config() -> str:
- path = QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation)
+def get_default_config_dir() -> str:
+ """
+ 获取PyMiner默认设置的位置。软件第一次运行时,从这里获取设置,并且将设置拷贝到用户目录下面。。
+ Returns:
+
+ """
+ return os.path.join(get_root_dir(), "configuration")
+
+
+def get_user_config_dir() -> str:
+ """
+ 获取用户的设置目录。 .pyminer/pyminer_config
+ Returns:
+
+ """
+ path = os.path.join(get_pyminer_data_dir(), "pyminer_config")
+ if not os.path.exists(path):
+ os.makedirs(path)
return path
-def get_path_app_local_data() -> str:
- path = QStandardPaths.writableLocation(QStandardPaths.AppLocalDataLocation)
- return path
\ No newline at end of file
+def get_config_file_dir(filename: str) -> str:
+ """
+ 获取设置文件的路径
+ Args:
+ filename:
+
+ Returns:
+
+ """
+ assert filename in SETTINGS_FILES
+ user_cfg_file_path = os.path.join(get_user_config_dir(), filename)
+ if not os.path.exists(user_cfg_file_path):
+ default_cfg_file_path = os.path.join(get_default_config_dir(), filename)
+ shutil.copy(default_cfg_file_path, user_cfg_file_path)
+ return user_cfg_file_path
diff --git a/utils/settings/__init__.py b/utils/settings/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..c70020d5f7b2fe8c5d7f62e339f4c79895986c8f
--- /dev/null
+++ b/utils/settings/__init__.py
@@ -0,0 +1 @@
+from .settings import *
\ No newline at end of file
diff --git a/utils/settings/settings.py b/utils/settings/settings.py
new file mode 100644
index 0000000000000000000000000000000000000000..6ededd52be97d214061c35ac3c88d8a9caee2931
--- /dev/null
+++ b/utils/settings/settings.py
@@ -0,0 +1,88 @@
+import ast
+import os
+import shutil
+from typing import Any
+
+from PySide2.QtCore import QSettings
+
+# from features.ui.base.Preferences import Ui_Form
+
+Ui_Form = object
+
+SETTINGS_FILES = {"config.ini"}
+
+
+def get_settings_from_file(file_name: str) -> QSettings:
+ """
+ 从文件中获取设置
+ Args:
+ file_name:
+
+ Returns:
+
+ """
+ from ..path import get_config_file_dir
+ return QSettings(get_config_file_dir(file_name), QSettings.IniFormat)
+
+
+def get_settings_item_from_file(file_name: str, item: str, mode="user") -> Any:
+ """
+ 从文件中获取设置。如果用户目录下没有,就去默认目录下面寻找。
+ 这样可以解决软件更新时引入的问题。
+ 在此时会调用ast.literal_eval函数进行数据类型转换。
+ Args:
+ file_name:
+ item:
+ mode: 两种选项,有user和default。
+
+ Returns:
+
+ """
+ assert mode in {"user", "default"}
+ assert file_name in SETTINGS_FILES
+ from utils.path import get_user_config_dir, get_default_config_dir
+ user_cfg_file_path = os.path.join(get_user_config_dir(), file_name)
+ default_cfg_file_path = os.path.join(get_default_config_dir(), file_name)
+ if mode == "user":
+ if not os.path.exists(user_cfg_file_path):
+ shutil.copy(default_cfg_file_path, user_cfg_file_path)
+ val = QSettings(user_cfg_file_path, QSettings.IniFormat).value(item)
+ if val is None:
+ val = QSettings(default_cfg_file_path, QSettings.IniFormat).value(item)
+ else:
+ val = QSettings(default_cfg_file_path, QSettings.IniFormat).value(item)
+ assert val is not None, (default_cfg_file_path, item, mode)
+ try:
+ val = ast.literal_eval(val)
+ except:
+ pass
+ return val
+
+
+def write_settings_item_to_file(file_name: str, item: str, value: Any):
+ """
+ 带有类型转换地写入。
+ 一般的,设置类型只能是
+ int,float,str以及由他们repr之后组成的结果。
+
+ Args:
+ file_name:
+ item:
+ value:
+
+ Returns:
+
+ """
+ assert file_name in SETTINGS_FILES
+ from utils.path import get_config_file_dir
+
+ value_str = ""
+ if isinstance(value, str):
+ value_str = value
+ else:
+ value_str = repr(value)
+ QSettings(os.path.join(get_config_file_dir(file_name)), QSettings.IniFormat).setValue(item, value_str)
+
+
+if __name__ == '__main__':
+ print(get_settings_item_from_file("config.ini", "RUN/EXTERNAL_INTERPRETERS"))