1 Star 0 Fork 246

德仔 / pyminer

forked from pyminer / pyminer 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
app2.py 23.94 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
import time
import os
import sys
import platform
sys.path.append(os.path.dirname(__file__))
t0 = time.time()
import pmgwidgets
pmgwidgets.in_unit_test = lambda: False
import cgitb
import datetime
import getpass
import logging
from typing import List, Callable
from qtpy.QtCore import Signal, QTimer, Qt, QTranslator, QLocale, QSize
from qtpy.QtGui import QCloseEvent, QTextCursor, QResizeEvent, QFontDatabase, QMoveEvent, QFont, QIcon, QPixmap
from qtpy.QtWidgets import QApplication, QTextEdit, QMessageBox, QToolBar, QSplashScreen, QStatusBar
from pmgwidgets import PMGToolBar, ActionWithMessage, PMDockObject, create_icon
from pyminer2.extensions.extensions_manager.manager import extensions_manager
from pyminer2.features import base
from pyminer2.features.io import sample
from pyminer2.features.io.settings import Settings
from pyminer2.features.io.settings import load_theme
from pyminer2.features.util import utils
from pyminer2.ui.base.widgets.controlpanel import PMPageExt
from pyminer2.ui.pmwidgets import BaseMainWindow
from pyminer2.globals import get_main_window, get_root_dir, get_application, pythonVersion, openURL
from pyminer2 import globals
log_folder = os.path.join(get_root_dir(), 'log')
if not os.path.exists(log_folder):
os.mkdir(log_folder)
logging.Formatter.default_msec_format = '%s.%03d'
logging_file = os.path.join(log_folder, f'log_{datetime.datetime.now().strftime("%Y-%m-%d")}.log')
logging.basicConfig(
format='[%(asctime)s] %(levelname)-8s %(name)s [%(module)s:%(funcName)s:%(lineno)s] %(message)+8s',
# filename=logging_file,
# filemode='a',
level=logging.DEBUG,
handlers=[logging.FileHandler(logging_file, 'a', encoding='utf8')]
)
logger = logging.getLogger('pmapp')
logger.info('Program starts up')
if "--debug" in sys.argv:
del sys.argv[sys.argv.index("--debug")]
logging.basicConfig(level=logging.DEBUG)
def load_translator(app: QApplication):
"""加载翻译文件
Args:
app: PyQt的Application。
"""
# 注意需要保留trans变量的引用
app.trans = QTranslator()
app.trans.load(os.path.join(os.path.dirname(__file__), 'translations', 'qt_{0}.qm'.format(QLocale.system().name())))
app.installTranslator(app.trans)
def load_fonts(app):
"""
注册字体文件
"""
app.font_dir = path = os.path.join(get_root_dir(), 'ui/source/font')
for name in os.listdir(path):
QFontDatabase.addApplicationFont(os.path.join(path, name))
font_db = QFontDatabase()
def updateSplashMsg(ext_load_status: dict):
splash = get_application().splash
percent = '100%' if ext_load_status.get('ext_count') == 0 \
else round(ext_load_status.get('loaded') / ext_load_status.get('ext_count') * 100)
try:
msg = '正在加载:' + ext_load_status.get('ext_name') + '...' + str(percent) + '%'
splash.showMessage(msg, Qt.AlignHCenter | Qt.AlignBottom, Qt.white)
except TypeError:
return
class PMToolBarHome(PMGToolBar):
"""
定义菜单工具栏按钮。
"""
def __init__(self):
super().__init__()
self.add_tool_button(
'button_new_script', '新建脚本',
create_icon(":/color/source/theme/color/icons/script.svg"))
self.add_tool_button(
'button_new',
'新建',
create_icon(":/color/source/theme/color/icons/new_project.svg"))
self.add_tool_button('button_open', '打开', create_icon(
":/color/source/theme/color/icons/open.svg"))
self.addSeparator()
self.add_tool_button(
'button_import_data', '获取数据',
create_icon(":/color/source/theme/color/icons/import.svg"))
self.add_tool_button(
'button_import_database', '数据库导入',
create_icon(":/color/source/theme/color/icons/import_database.svg"))
self.add_buttons(3, ['button_open_variable', 'button_save_workspace', 'button_clear_workspace'],
['加载变量', '保存变量', '清除变量'],
[":/color/source/theme/color/icons/var_open.svg",
":/color/source/theme/color/icons/save_layout.svg",
":/color/source/theme/color/icons/clear.svg"])
self.addSeparator()
self.add_tool_button(
'button_appstore',
'应用商店',
create_icon(':/color/source/theme/color/icons/appstore.svg'))
self.add_tool_button('button_help', '帮助', create_icon(
':/color/source/theme/color/icons/help.svg'))
self.add_tool_button('button_community', '社区', create_icon(
':/color/source/theme/color/icons/community.svg'))
self.add_tool_button('view_config', '视图', create_icon(
':/color/source/theme/color/icons/save_layout.svg'))
self.add_tool_button('button_settings', '设置', create_icon(
':/color/source/theme/color/icons/setting.svg'))
def process_visibility_actions(self, e: ActionWithMessage):
"""
处理”视图“菜单点击时触发的事件。
"""
main_window = get_main_window()
dws = main_window.dock_widgets
if e.message == 'load_standard_layout':
main_window.load_predefined_layout('standard')
elif e.message in dws.keys():
dws[e.message].setVisible(e.isChecked())
elif e.message == 'lock_layout':
main_window.set_dock_titlebar_visible(not e.isChecked()) # 如果界面锁定(True)则标题栏不可见(False)所以需要取反。
def bind_events(self):
"""
绑定事件。
"""
self.get_control_widget('button_clear_workspace').clicked.connect(lambda: get_main_window().clear_workspace())
self.get_control_widget('button_settings').clicked.connect(lambda: get_main_window().main_option_display())
self.get_control_widget('button_appstore').clicked.connect(lambda: get_main_window().main_appstore_dispaly())
self.get_control_widget('button_help').clicked.connect(lambda: get_main_window().main_help_display())
self.get_control_widget('button_community').clicked.connect(lambda: get_main_window().main_community_display())
self.add_import_data_menus()
self.append_menu('button_new_script', 'Python',
lambda: get_main_window().main_homesite_display(),
create_icon(':/color/source/theme/color/icons/python.svg'))
self.append_menu('button_new_script', 'Notebook',
lambda: get_main_window().main_jupyter_display(),
create_icon(':/color/source/theme/color/icons/Jupyter.svg'))
self.append_menu('button_new_script', 'R',
lambda: get_main_window().main_homesite_display(),
create_icon(':/color/source/theme/color/icons/R.svg'))
self.append_menu('button_new_script', 'Markdown',
lambda: get_main_window().main_markdown_display(),
create_icon(':/logo/source/theme/color/icons/markdown.svg'))
self.append_menu('button_new_script', 'SQL',
lambda: get_main_window().main_homesite_display(),
create_icon(':/logo/source/theme/color/icons/sql.svg'))
self.append_menu('button_new_script', 'HTML',
lambda: get_main_window().main_homesite_display(),
create_icon(':/logo/source/theme/color/icons/html.svg'))
homeSiteIcon = create_icon(':/color/source/theme/color/icons/home_site.svg')
self.append_menu('button_help', '官方网站',
lambda: get_main_window().main_homesite_display(),
homeSiteIcon)
helpDocIcon = create_icon(':/color/source/theme/color/icons/help_doc.svg')
self.append_menu('button_help', '帮助文档',
lambda: get_main_window().main_help_display(),
helpDocIcon)
updateIcon = create_icon(':/color/source/theme/color/icons/check_update.svg')
self.append_menu('button_help', '检查更新',
lambda: get_main_window().main_check_update_display(),
updateIcon)
feedbackIcon = create_icon(':/color/source/theme/color/icons/feedback.svg')
self.append_menu('button_help', '反馈',
lambda: get_main_window().main_feedback_display(),
feedbackIcon)
aboutIcon = create_icon(':/color/source/theme/color/icons/info.svg')
self.append_menu('button_help', '关于',
lambda: get_main_window().main_about_display(),
aboutIcon)
def add_import_data_menus(self):
"""
为主菜单按钮添加子菜单
"""
newProjectIcon = create_icon(':/color/source/theme/color/icons/project.svg')
self.append_menu('button_new', '新建项目', lambda: get_main_window().main_project_wizard_display(),
newProjectIcon)
textImportIcon = create_icon(':/color/source/theme/color/icons/txt.svg')
self.append_menu('button_import_data', '文本文件', lambda: get_main_window().process_file('text'),
textImportIcon)
excelImportIcon = create_icon(':/color/source/theme/color/icons/excel.svg')
self.append_menu('button_import_data', 'Excel', lambda: get_main_window().process_file('excel'),
excelImportIcon)
sasImportIcon = create_icon(':/color/source/theme/color/icons/sas.ico')
self.append_menu('button_import_data', 'SAS', lambda: get_main_window().process_file('sas'),
sasImportIcon)
spssImportIcon = create_icon(':/color/source/theme/color/icons/spss.svg')
self.append_menu('button_import_data', 'SPSS', lambda: get_main_window().process_file('spss'),
spssImportIcon)
matlabImportIcon = create_icon(':/color/source/theme/color/icons/matlab.svg')
self.append_menu('button_import_data', 'MATLAB', lambda: get_main_window().process_file('matlab'),
matlabImportIcon)
mysqlIcon = create_icon(':/color/source/theme/color/icons/MySQL.svg')
self.append_menu('button_import_database', 'MySQL', lambda: get_main_window().import_mysql_display(),
mysqlIcon)
oracleIcon = create_icon(':/color/source/theme/color/icons/oracle.svg')
self.append_menu('button_import_database', 'Oracle', lambda: get_main_window().import_oracle_display(),
oracleIcon)
postgresqlIcon = create_icon(':/color/source/theme/color/icons/postgresql.svg')
self.append_menu('button_import_database', 'PostgreSQL', lambda: get_main_window().import_postgresql_display(),
postgresqlIcon)
# databaseConfigIcon = create_icon(':/color/source/theme/color/icons/database_config.svg')
# self.append_menu('button_import_database', 'Edit Accounts',
# lambda: get_main_window().show_database_account_editor_panel(),
# databaseConfigIcon)
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)
self.main_option_form = base.OptionForm()
import pyminer2.globals
pyminer2.globals._main_window = self
# 主窗体默认大小
# self.resize(1500, 850)
self.setIconSize(QSize(40, 40))
# 设置状态栏
self.statusBar = QStatusBar()
version = pythonVersion()
self.statusBar.showMessage(version, 0)
self.setStatusBar(self.statusBar)
settings = Settings()
root_dir = os.path.dirname(__file__)
pyminer2.globals._root_dir = root_dir
self.init_toolbar_tab()
self.add_toolbar('toolbar_home', PMToolBarHome(), 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='日志',
side='right')
# 初始化日志
self.slot_flush_console('info', 'system', '准备就绪!')
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='插件管理',
side='left')
dw.setMaximumWidth(400)
load_theme(settings['theme']) # 组件都加载后再设置主题,否则可能有些组件不生效
self.load_layout()
self.show()
self.switch_toolbar('toolbar_home') # 启动完成时,将工具栏切换到‘主页’
self.on_main_window_shown()
self.first_form_display()
def clear_workspace(self):
from pyminer2.extensions.extensionlib.extension_lib import extension_lib
extension_lib.get_interface('ipython_console').run_command('Clearing_Variables_ =\'Clear All\'',
hint_text='开始清除...', hidden=False)
extension_lib.get_interface('ipython_console').run_command('__clear_all()', hint_text='清除全部变量', hidden=False)
def add_toolbar(self, name: str, toolbar: QToolBar,
text: str = 'untitled toolbar'):
"""
添加一个工具栏。
"""
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:
"""
窗口大小调节,或者位置改变的信号。
"""
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):
self.settings_changed_signal.emit()
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
"""
super().on_main_window_shown()
self.layouts_ready_signal.emit()
for task in self.setupui_tasks:
task()
self.widgets_ready_signal.emit()
self.set_dock_titlebar_visible(Settings.get_instance()['dock_titlebar_visible'])
self.bind_events()
self.events_ready_signal.emit()
def first_form_display(self):
"""
显示"快速操作"窗口
"""
self.main_first_form = base.FirstForm()
self.main_first_form.show()
def import_mysql_display(self):
"""
显示"从mysql数据库导入表"窗口
"""
self.import_mysql_database = sample.ImportMysql()
self.import_mysql_database.show()
def import_oracle_display(self):
"""
显示"从Oracle数据库导入表"窗口
"""
self.import_oracle_database = sample.ImportOracle()
self.import_oracle_database.show()
def import_postgresql_display(self):
"""
显示"从PostgreSQL数据库导入表"窗口
"""
self.import_postgresql_database = sample.ImportPostgreSQL()
self.import_postgresql_database.show()
def show_database_account_editor_panel(self):
"""
显示账户编辑面板
:return:
"""
from pyminer2.features.io.database import DatabaseConfigPanel
sp2 = DatabaseConfigPanel(self)
sp2.show()
def main_appstore_dispaly(self):
"""
显示"应用商店"窗口
"""
self.appstore = base.AppstoreForm()
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.show()
def process_file(self, type: str):
if type is not None:
if type == 'excel':
utils.importutils.doExcelImport(self)
if type == 'matlab':
utils.importutils.doMATLABImport(self)
elif type == 'sas':
utils.importutils.doSASImport(self)
elif type == 'spss':
utils.importutils.doSPSSImport(self)
elif type == 'text':
utils.importutils.doTextImport(self)
else:
logging.info("type is not supported yet")
else:
logging.info('type is null')
def main_help_display(self):
"""
打开帮助页面
"""
openURL("https://gitee.com/py2cn/pyminer/wikis")
def main_check_update_display(self):
"""
打开'检查更新'页面
"""
reply = QMessageBox.information(self, '检查更新', '前往官方网站查看最新版本', QMessageBox.Yes, QMessageBox.Yes)
if reply == QMessageBox.Yes:
openURL("http://www.pyminer.com")
def main_feedback_display(self):
"""
打开'反馈'页面
"""
reply = QMessageBox.information(self, '问题反馈', '您可以通过issue反馈建议或使用中遇到的问题', QMessageBox.Yes | QMessageBox.No,
QMessageBox.Yes)
if reply == QMessageBox.Yes:
openURL("https://gitee.com/py2cn/pyminer/issues")
def main_homesite_display(self):
"""
打开官方网站页面
"""
openURL("http://www.pyminer.com")
def main_markdown_display(self):
print("TODO 添加markdown编辑器代码")
def main_jupyter_display(self):
print("打开jupyter-notebook")
os.chdir(globals.get_root_dir())
import subprocess
python_path=sys.executable
cmd=python_path+' -m notebook'
subprocess.Popen(cmd)
def main_community_display(self):
"""
打开帮助页面
"""
openURL("https://www.kuxai.com/")
def main_project_wizard_display(self):
"""
打开新建项目向导
"""
self.project_wizard = base.ProjectWizardForm()
self.project_wizard.show()
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, '关闭', '是否关闭!')
reply.addButton('确定', QMessageBox.ActionRole)
reply.addButton('取消', QMessageBox.RejectRole)
if reply.exec_() == QMessageBox.RejectRole:
a0.ignore()
return
else:
a0.accept()
"""
reply = QMessageBox.question(
self,
'注意',
'确认退出吗?',
QMessageBox.Ok | QMessageBox.Cancel,
QMessageBox.Cancel)
if reply == QMessageBox.Ok:
a0.accept()
else:
a0.ignore()
return
"""
self.delete_temporary_dock_windows()
self.save_layout()
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 = "<a style='font-family:verdana;color:red;font-size:11;'>" + msg + "</a>"
else:
html = "<a style='font-family:verdana;color:black;font-size:11;'>" + msg + "</a>"
console = self.log_output_console # 由于代码重构,这里出现了不同。
console.moveCursor(QTextCursor.End)
console.append(html)
def main():
import time
t0 = time.time()
# 异常处理设置
# cgitb.enable(format='text')
app = QApplication(sys.argv)
app.setWindowIcon(QIcon(':/logo/source/icons/logo.png')) # 设置应用logo
app.setAttribute(Qt.AA_EnableHighDpiScaling) # 设置应用支持高分屏
# 设置启动画面
splash_image = QPixmap(':/images/source/images/splash.jpg')
splash_image = splash_image.scaled(700, 400)
splash = QSplashScreen(splash_image)
splash.show() # 显示启动界面
app.splash = splash
globals._application = app
# 设置字体
load_fonts(app)
app.default_font = 'Deng'
f = QFont(app.default_font, 10)
app.setFont(f)
# 设置翻译
load_translator(app)
window = MainWindow()
window.showMaximized()
window.show()
t1 = time.time()
logging.warning('boot time elapsed:%f s' % (t1 - t0))
splash.finish(window) # 启动画面结束
res = app.exec()
logging.debug("Shutting down, result %d", res)
logging.shutdown()
sys.exit(res)
if __name__ == '__main__':
t1 = time.time()
logger.info('preload_module_time %f' % (t1 - t0))
main()
Python
1
https://gitee.com/darlk/pyminer.git
git@gitee.com:darlk/pyminer.git
darlk
pyminer
pyminer
master

搜索帮助