功能实现:
- 日志保存与读取
SQLite3
- 等级筛选
SQL
- 模糊查询
fuzzywuzzy
- 时间范围筛选
time
- 日志内容语法高亮
PyQt5.Qsci
- 日志具体信息弹窗Dialog (表单内容双击事件)
PyQt5
- logging Handler类,此程序可作为模块引入
文章目录
- 1. SQLite3 数据库
- 知识点
- 2. fuzzywuzzy.fuzz 模糊搜索
- 知识点
- 3. logging 日志
- 知识点
- 4. PyQt5.Qsci 语法高亮 与 PyQt5
- 事件
- 5. functions.py
- 使用方法
1. SQLite3 数据库
SQLite 是一个软件库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是在世界上最广泛部署的 SQL 数据库引擎。 RUNOOB | SQLite - Python
知识点
- *sqlite3.connect(database: str [,timeout , args]) ->
connection
打开一个到 SQLite 数据库文件 database ( 如果给定的数据库名称 filename 不存在,则该调用将创建一个数据库 )":memory:"
来在 RAM 中打开一个到 database 的数据库连接。sqlite3.connect(..., check_same_thread=False)
可以在多个线程中获取/提交数据库信息 - connection.cursor([cursorClass]) ->
cursor
- cursor.execute(sql [, __iter: iterable]) -> return value from database.
执行一个 SQL 语句
- 该 SQL 语句可以被参数化
__iter
cursor.execute(“insert into people values (?
,?
)”, ( var1, var2)) - connection.commit() -> None
该方法提交当前的事务。 (中途生成
*.dbjourney
文件)
我专门定义了一个SQliteIO
类管理数据库:
db_filename = "database/database.db"
class SQliteIO(object):
def __init__(self):
self.db = sqlite3.connect(db_filename, check_same_thread=False)
self.cursor = self.db.cursor()
self.init_db()
def __del__(self):
self.db.close()
def reset_db(self): # thread-in
self.db.close()
if os.path.isfile(db_filename):
os.remove(db_filename)
self.db = sqlite3.connect(db_filename, check_same_thread=False)
self.cursor = self.db.cursor()
def init_db(self): # thread-in
try:
self.cursor.execute('create table logging(time FLOAT ,level INTEGER, '
f'data VARCHAR({sys.maxsize}), name VARCHAR(1024))')
# self.cursor.execute("create table user(username VARCHAR(12), password VARCHAR(10), time FLOAT,
# id INTEGER)")
self.db.commit()
except sqlite3.OperationalError:
pass
except sqlite3.DatabaseError:
self.reset_db()
self.init_db()
@staticmethod
def getSize() -> str:
return convert(os.path.getsize(db_filename), True) if os.path.isfile(db_filename) else convert(0)
def commit(self, __sql="", __params: (list, tuple) = ()): # thread-in
try:
data = self.cursor.execute(__sql, __params)
self.db.commit()
return data
except (sqlite3.ProgrammingError, AttributeError):
return None
except sqlite3.DatabaseError:
self.reset_db()
return None
2. fuzzywuzzy.fuzz 模糊搜索
fuzz
主要用于两字符串之间匹配
[ i ] 第三方库
conda install fuzzywuzzy
或pip install fuzzywuzzy
知识点
两个模块:
fuzz, process
fuzz主要用于两字符串之间匹配,process主要用于搜索排序。fuzz.ratio
(s1,s2)直接计算s2和s2之间的相似度,返回值为0-100,100表示完全相同;fuzz.partial_ratio
(S1,S2)部分匹配,如果S1是S2的子串依然返回100;fuzz.token_sort_ratio
(S1,S2)只比较S1,S2单词是否相同,不考虑词语之间的顺序
;fuzz.token_set_ratio
(S1,S2)相比fuzz.token_sort_ratio不考虑词语出现的次数
;process.extract
(S1, ListS,limit=n),表示从列表ListS中找出Top n与S1最相似的句子;process.extractOne
(S1,ListS),返回最相似的一个
- 选自 https://www.cnblogs.com/ly570/p/10935454.html
class SQliteHandler(logging.Handler):
...
@staticmethod
def fuzzyfinder(content, collections):
return [v[1] for v in
sorted([(fuzz.token_set_ratio(content, data), data) for data in collections],
key=lambda x: x[0], reverse=True)] # 按相似度 排序
3. logging 日志
知识点
相较于fuzzywuzzy, logging模块是再熟悉不过了, 我也就不在细讲
- https://blog.csdn.net/pansaky/article/details/90710751
- https://www.cnblogs.com/xianyulouie/p/11041777.html
- 主要是继承logging.Handler类
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
LOGGING_LEVEL = {"NOTSET": logging.NOTSET,
"DEBUG": logging.DEBUG,
"INFO": logging.INFO,
"WARNING": logging.WARNING,
"ERROR": logging.ERROR,
"CRITICAL": logging.CRITICAL}
LOGGING_LEVEL_INDEX = {logging.NOTSET: "NOTSET",
logging.DEBUG: "DEBUG",
logging.INFO: "INFO",
logging.WARNING: "WARNING",
logging.ERROR: "ERROR",
logging.CRITICAL: "CRITICAL"}
class SQliteHandler(logging.Handler):
def __init__(self):
self.connection: callable = None
self.sqlite = SQliteIO()
super(SQliteHandler, self).__init__()
def connect(self, connection: callable):
self.connection = connection
def emit(self, record: logging.LogRecord) -> None:
__stamp = round(time.time(), 2)
self.sqlite.commit(f"INSERT INTO logging(time, level, data, name) VALUES (?, ?, ?, ?)",
(__stamp, record.levelno, record.msg, record.name))
if self.connection is not None:
self.connection()
@staticmethod
def fuzzyfinder(content, collections):
return [v[1] for v in
sorted([(fuzz.token_set_ratio(content, data), data) for data in collections],
key=lambda x: x[0], reverse=True)] # 按相似度 排序
# @timeit("Logging Data", logger)
def getData(self, level: (int, str) = logging.NOTSET, content=str()):
if isinstance(level, str):
level = LOGGING_LEVEL[level]
datas = [x for x in
self.sqlite.commit("SELECT time, level, data, name FROM logging where level >= ?", (level,))]
if isinstance(content, str) and content:
return sum([sorted([data for data in datas if data[2] == element], key=lambda x: x[0], reverse=True)
for element in SQliteHandler.fuzzyfinder(content, set([x[2] for x in datas]))], [])
# 重复元素按时间排序, 时间越近越靠前
else:
return sorted(datas, key=lambda x: x[1], reverse=True)
4. PyQt5.Qsci 语法高亮 与 PyQt5
PythonSci
代码 来自 https://blog.csdn.net/hwd00001/article/details/103049588
QLoggingTableWidget
代码 来自 UI
class QLoggingTableWidget(QtWidgets.QWidget):
class PythonSci(QsciScintilla):
""" Modules: PyQt5, qscintilla
PythonSci代码 来自 https://blog.csdn.net/hwd00001/article/details/103049588"""
class highlight(QsciLexerPython):
def __init__(self, parent):
QsciLexerPython.__init__(self, parent)
font = QtGui.QFont()
font.setFamily('Consolas')
font.setPointSize(12)
font.setFixedPitch(True)
self.setFont(font)
self.setColor(QtGui.QColor(0, 0, 0))
self.setPaper(QtGui.QColor(255, 255, 255))
self.setColor(QtGui.QColor("#00FF00"), QsciLexerPython.ClassName)
self.setColor(QtGui.QColor("#B0171F"), QsciLexerPython.Keyword)
self.setColor(QtGui.QColor("#00FF00"), QsciLexerPython.Comment)
self.setColor(QtGui.QColor("#FF00FF"), QsciLexerPython.Number)
self.setColor(QtGui.QColor("#0000FF"), QsciLexerPython.DoubleQuotedString)
self.setColor(QtGui.QColor("#0000FF"), QsciLexerPython.SingleQuotedString)
self.setColor(QtGui.QColor("#288B22"), QsciLexerPython.TripleSingleQuotedString)
self.setColor(QtGui.QColor("#288B22"), QsciLexerPython.TripleDoubleQuotedString)
self.setColor(QtGui.QColor("#0000FF"), QsciLexerPython.FunctionMethodName)
self.setColor(QtGui.QColor("#191970"), QsciLexerPython.Operator)
self.setColor(QtGui.QColor("#000000"), QsciLexerPython.Identifier)
self.setColor(QtGui.QColor("#00FF00"), QsciLexerPython.CommentBlock)
self.setColor(QtGui.QColor("#0000FF"), QsciLexerPython.UnclosedString)
self.setColor(QtGui.QColor("#FFFF00"), QsciLexerPython.HighlightedIdentifier)
self.setColor(QtGui.QColor("#FF8000"), QsciLexerPython.Decorator)
self.setFont(QtGui.QFont('Courier', 12, weight=QtGui.QFont.Bold), 5)
self.setFont(QtGui.QFont('Courier', 12, italic=True), QsciLexerPython.Comment)
def __init__(self, text, parent=None):
super(QLoggingTableWidget.PythonSci, self).__init__(parent)
font = QtGui.QFont()
font.setFamily('Consolas')
font.setPointSize(12)
font.setFixedPitch(True)
self.setFont(font)
self.setFont(font)
self.setUtf8(True)
self.setMarginsFont(font)
self.setMarginWidth(0, len(str(len(self.text().split('n')))) * 20)
self.setMarginLineNumbers(0, True)
self.setEdgeMode(QsciScintilla.EdgeLine)
self.setEdgeColumn(80)
self.setEdgeColor(QtGui.QColor(0, 0, 0))
self.setBraceMatching(QsciScintilla.StrictBraceMatch)
self.setIndentationsUseTabs(True)
self.setIndentationWidth(4)
self.setTabIndents(True)
self.setAutoIndent(True)
self.setBackspaceUnindents(True)
self.setTabWidth(4)
self.setCaretLineVisible(True)
self.setCaretLineBackgroundColor(QtGui.QColor('#FFFFCD'))
self.setIndentationGuides(True)
self.setFolding(QsciScintilla.PlainFoldStyle)
self.setMarginWidth(2, 12)
self.markerDefine(QsciScintilla.Minus, QsciScintilla.SC_MARKNUM_FOLDEROPEN)
self.markerDefine(QsciScintilla.Plus, QsciScintilla.SC_MARKNUM_FOLDER)
self.markerDefine(QsciScintilla.Minus, QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
self.markerDefine(QsciScintilla.Plus, QsciScintilla.SC_MARKNUM_FOLDEREND)
self.setMarkerBackgroundColor(QtGui.QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEREND)
self.setMarkerForegroundColor(QtGui.QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDEREND)
self.setMarkerBackgroundColor(QtGui.QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
self.setMarkerForegroundColor(QtGui.QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
self.setAutoCompletionSource(QsciScintilla.AcsAll)
self.setAutoCompletionCaseSensitivity(True)
self.setAutoCompletionReplaceWord(False)
self.setAutoCompletionThreshold(1)
self.setAutoCompletionUseSingle(QsciScintilla.AcusExplicit)
self.lexer = QLoggingTableWidget.PythonSci.highlight(self)
self.setLexer(self.lexer)
self.mod = False
self.autoCompleteFromAll()
self.setReadOnly(True)
self.setText(text)
class LoggingInformation(QtWidgets.QDialog):
def __init__(self, str_time, level, content, name, parent=None):
super().__init__(parent)
self.setObjectName("LoggingInformation")
self.resize(640, 800)
font = QtGui.QFont()
font.setFamily("Consolas")
self.setFont(font)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap("images/fileRecord.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.setWindowIcon(icon)
self.gridLayout = QtWidgets.QGridLayout(self)
self.gridLayout.setObjectName("gridLayout")
self.label_4 = QtWidgets.QLabel(self)
self.label_4.setStyleSheet("color: rgb(0, 85, 255);n"
"font: 9pt "Consolas";")
self.label_4.setObjectName("label_4")
self.gridLayout.addWidget(self.label_4, 1, 1, 1, 1)
self.label_6 = QtWidgets.QLabel(self)
self.label_6.setStyleSheet("color: rgb(255, 170, 0);n"
"font: 9pt "Consolas";")
self.label_6.setObjectName("label_6")
self.gridLayout.addWidget(self.label_6, 2, 1, 1, 1)
self.label_3 = QtWidgets.QLabel(self)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1)
self.label_7 = QtWidgets.QLabel(self)
self.label_7.setObjectName("label_7")
self.gridLayout.addWidget(self.label_7, 3, 0, 1, 1)
self.label = QtWidgets.QLabel(self)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.label_2 = QtWidgets.QLabel(self)
self.label_2.setStyleSheet(
"color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(255, 255, 0, 255), "
"stop:1 rgba(0, "
"185, 255, 255));n "
"font: 9pt "Consolas";")
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 0, 1, 1, 1)
self.label_5 = QtWidgets.QLabel(self)
self.label_5.setObjectName("label_5")
self.gridLayout.addWidget(self.label_5, 2, 0, 1, 1)
self.widget = QLoggingTableWidget.PythonSci(content, self)
self.widget.setObjectName("widget")
self.gridLayout.addWidget(self.widget, 3, 1, 1, 1)
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("LoggingInformation", "日志信息"))
self.label_4.setText(_translate("LoggingInformation", f"{level}"))
self.label_6.setText(_translate("LoggingInformation", f"{name}"))
self.label_3.setText(_translate("LoggingInformation", "等级:"))
self.label_7.setText(_translate("LoggingInformation", "日志信息:"))
self.label.setText(_translate("LoggingInformation", "时间:"))
self.label_2.setText(_translate("LoggingInformation", f"{str_time}"))
self.label_5.setText(_translate("LoggingInformation", "执行文件地址:"))
QtCore.QMetaObject.connectSlotsByName(self)
self.exec()
def __init__(self, parent=None):
super().__init__(parent)
self.datas = []
self.setObjectName("QLoggingTableWidget")
self.resize(480, 840)
font = QtGui.QFont()
font.setFamily("Consolas")
self.setFont(font)
self.verticalLayout = QtWidgets.QVBoxLayout(self)
self.verticalLayout.setObjectName("verticalLayout")
self.formLayout = QtWidgets.QFormLayout()
self.formLayout.setHorizontalSpacing(0)
self.formLayout.setObjectName("formLayout")
self.searchLabel = QtWidgets.QLabel(self)
self.searchLabel.setMaximumSize(QtCore.QSize(30, 30))
self.searchLabel.setPixmap(QtGui.QPixmap("images/search.png"))
self.searchLabel.setScaledContents(True)
self.searchLabel.setObjectName("searchLabel")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.searchLabel)
self.searchInputBox = QtWidgets.QLineEdit(self)
self.searchInputBox.setClearButtonEnabled(True)
self.searchInputBox.setObjectName("searchInput-box")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.searchInputBox)
self.filterLabel = QtWidgets.QLabel(self)
self.filterLabel.setMaximumSize(QtCore.QSize(30, 30))
self.filterLabel.setPixmap(QtGui.QPixmap("images/filter.png"))
self.filterLabel.setScaledContents(True)
self.filterLabel.setObjectName("filterLabel")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.filterLabel)
self.comboBox = QtWidgets.QComboBox(self)
self.comboBox.setObjectName("comboBox")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.comboBox)
self.timeRadioButton = QtWidgets.QRadioButton(self)
self.timeRadioButton.setObjectName("radioButton")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.timeRadioButton)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.startDateTimeEdit = QtWidgets.QDateTimeEdit(self)
self.startDateTimeEdit.setObjectName("dateTimeEdit")
self.horizontalLayout.addWidget(self.startDateTimeEdit)
self.label = QtWidgets.QLabel(self)
self.label.setObjectName("label")
self.horizontalLayout.addWidget(self.label)
self.endDateTimeEdit = QtWidgets.QDateTimeEdit(self)
self.endDateTimeEdit.setObjectName("dateTimeEdit_2")
self.horizontalLayout.addWidget(self.endDateTimeEdit)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.formLayout.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout)
self.verticalLayout.addLayout(self.formLayout)
self.loggingTableWidget = QtWidgets.QTableWidget(self)
self.loggingTableWidget.setObjectName("loggingTableWidget")
self.loggingTableWidget.setColumnCount(0)
self.loggingTableWidget.setRowCount(0)
self.verticalLayout.addWidget(self.loggingTableWidget)
QtCore.QMetaObject.connectSlotsByName(self)
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("QLoggingTableWidget", "Form"))
self.searchLabel.setWhatsThis(_translate("QLoggingTableWidget", "<html><head/><body><p>模糊搜索</p></body></html>"))
self.searchInputBox.setToolTip(
_translate("QLoggingTableWidget", "<html><head/><body><p>模糊搜索</p></body></html>"))
self.filterLabel.setWhatsThis(_translate("QLoggingTableWidget", "<html><head/><body><p>等级筛选</p></body></html>"))
self.comboBox.setWhatsThis(_translate("QLoggingTableWidget", "<html><head/><body><p>等级筛选</p></body></html>"))
self.timeRadioButton.setText(_translate("QLoggingTableWidget", "起始时间"))
self.label.setText(_translate("QLoggingTableWidget", "-"))
self.loggingTableWidget.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
self.comboBox.addItems(list(LOGGING_LEVEL.keys())[1:])
self.loggingTableWidget.setColumnCount(4)
self.loggingTableWidget.setHorizontalHeaderLabels(["时间", "等级", "数据", "执行地址"])
self.loggingTableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) # 禁止编辑
self.loggingTableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) # 设置表格整行选中
self.setDateTimeEditEnabled(False)
self.timeRadioButton.clicked.connect(self.timeRadio)
self.loggingTableWidget.doubleClicked.connect(self.tableClicked)
self.comboBox.currentIndexChanged.connect(self.updateLoggingTable)
self.searchInputBox.textChanged.connect(self.updateLoggingTable)
self.timeRadioButton.clicked.connect(self.updateLoggingTable)
self.startDateTimeEdit.timeChanged.connect(self.updateLoggingTable)
self.endDateTimeEdit.timeChanged.connect(self.updateLoggingTable)
SQliteLoggingHandler.connect(self.updateLoggingTable)
self.startDateTimeEdit.setDate(QtCore.QDate.currentDate())
self.endDateTimeEdit.setDate(QtCore.QDate.currentDate())
self.endDateTimeEdit.setTime(QtCore.QTime.currentTime())
self.updateLoggingTable()
def timeRadio(self, *args): # 这些代码一会发
def tableClicked(self, index: QtCore.QModelIndex, *args):
def setDateTimeEditEnabled(self, a0: bool) -> None:
def getFilter(self):
def updateLoggingTable(self, *args):
@staticmethod
def colorful(level) -> QtGui.QColor:
事件
一共绑定了8个事件
timeRadioButton.clicked
.connect(self.timeRadio)
单选框点击事件绑定是否开启时间范围筛选
def timeRadio(self, *args):
self.setDateTimeEditEnabled(self.timeRadioButton.isChecked())
self.loggingTableWidget.doubleClicked
.connect(self.tableClicked)
表格左键双击绑定 具体日志信息Dialog 的展示
def tableClicked(self, index: QtCore.QModelIndex, *args):
self.LoggingInformation(*self.datas[index.row()], self)
self.comboBox.currentIndexChanged
.connect(self.updateLoggingTable)
self.searchInputBox.textChanged
.connect(self.updateLoggingTable)
self.timeRadioButton.clicked
.connect(self.updateLoggingTable)
self.startDateTimeEdit.timeChanged
.connect(self.updateLoggingTable)
self.endDateTimeEdit.timeChanged
.connect(self.updateLoggingTable)
SQliteLoggingHandler
.connect(self.updateLoggingTable)
下拉框(等级)改变
, 搜索框文字改变
, 起始时间框改变
, 是否启用时间范围筛选
, 日志更新
6个事件绑定更新表格
def getFilter(self):
search = self.searchInputBox.text().strip()
level = LOGGING_LEVEL[self.comboBox.currentText()]
if self.timeRadioButton.isChecked():
startTime = time.mktime(time.strptime(self.startDateTimeEdit.text(), "%Y/%m/%d %H:%M"))
endTime = time.mktime(time.strptime(self.endDateTimeEdit.text(), "%Y/%m/%d %H:%M"))
return [(time.strftime("%m-%d %H:%M:%S",
time.localtime(stamp)),
LOGGING_LEVEL_INDEX[levelno],
data,
name) for stamp, levelno, data, name in SQliteLoggingHandler.getData(level, search)
if startTime <= stamp <= endTime]
else:
return [(time.strftime("%m-%d %H:%M:%S",
time.localtime(stamp)),
LOGGING_LEVEL_INDEX[levelno],
data,
name) for stamp, levelno, data, name in SQliteLoggingHandler.getData(level, search)]
def updateLoggingTable(self, *args):
datas = self.getFilter()
self.datas = datas
self.loggingTableWidget.clear()
self.loggingTableWidget.setHorizontalHeaderLabels(["时间", "等级", "数据", "执行地址"])
self.loggingTableWidget.setRowCount(len(datas))
for _row in range(len(datas)):
row = datas[_row]
for _col in range(len(row)):
col: str = row[_col]
item = QtWidgets.QTableWidgetItem(col)
if _col == 0: # time
item.setForeground(QtGui.QColor(50, 50, 225))
if _col == 1: # level
item.setForeground(self.colorful(col))
self.loggingTableWidget.setItem(_row, _col, item)
@staticmethod
def colorful(level) -> QtGui.QColor:
return QtGui.QColor(*{"NOTSET": (195, 195, 195),
"DEBUG": (128, 128, 128),
"INFO": (0, 0, 255),
"WARNING": (255, 128, 64),
"ERROR": (255, 0, 0),
"CRITICAL": (255, 0, 128)}.get(level))
5. functions.py
此文章隶属于ServerProject项目, 大部分依赖文件于此.
代码语言:javascript复制import time
base = 1024
def _conv(value: (float, int)) -> str:
value = float(value)
if value.is_integer():
return str(int(value))
else:
return str(round(value, 1))
def ignore(function):
def _exec_func(*args, **kwargs):
try:
return function(*args, **kwargs)
except:
pass
return _exec_func
def convert(byte, fine=False):
"""
位 bit (比特)(Binary Digits):存放一位二进制数,即 0 或 1,最小的存储单位。
字节 byte:8个二进制位为一个字节(B),最常用的单位。
其中1024=2^10 ( 2 的10次方),
1KB (Kilo byte 千字节)=1024B,
1MB (Mega byte 兆字节 简称“兆”)=1024KB,
1GB (Giga byte 吉字节 又称“千兆”)=1024MB,
1TB (Trillion byte 万亿字节 太字节)=1024GB,
1PB(Peta byte 千万亿字节 拍字节)=1024TB,
1EB(Exa byte 百亿亿字节 艾字节)=1024PB"""
if not isinstance(byte, (int, float)):
byte = len(byte)
DEI = f"{byte} bytes"
units = ["b",
"Kb",
"Mb",
"Gb",
"Tb",
"Pb",
"Eb"]
index = 0
while True:
if byte < 1024 or index 1 >= len(units):
break
byte /= base
index = 1
if fine:
return f"{_conv(byte)}{units[index]}({DEI})"
else:
return f"{_conv(byte)}{units[index]}"
def timeit(objname: str, logger, ign=True, _show_detail=True):
def setup_function(func_name):
def _exec_function(*args, **kwargs):
start_time = time.time()
_resp = func_name(*args, **kwargs)
if _show_detail:
logger.debug("Execute the function %s%s, timeit %0.3f" % (
objname.title(), "" if ign else f" (at {str(func_name)})", time.time() - start_time))
return _resp
return _exec_function
return setup_function
def to_logging(logger):
def log(command):
def _exec_func(*args, **kwargs):
try:
_result = command(*args, **kwargs)
if _result is None:
return True
return _result
except:
logger.exception(str())
return _exec_func
return log
使用方法
QLoggingTableWidget
继承于QWidget
, 因此, 直接显示或添加父类至窗口上都可.
from sqlite_handler import SQliteLoggingHandler, QLoggingTableWidget
logger = logging.getLogger(...)
logger.addHandler(SQliteLoggingHandler)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
app.setStyle("fusion")
...
Qtable = QLoggingTableWidget()
Qtable.show()
sys.exit(app.exec_())