1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-22 18:26:39 +00:00

Fix crashes related to tqdm.

Use our own child window with strings generated by tqdm.format_meter() instead of relying on tqdm_tk.
This commit is contained in:
Pablo Curiel 2021-03-15 23:28:06 -04:00
parent 651e5d5f87
commit e70979248a
2 changed files with 96 additions and 29 deletions

10
.gitignore vendored
View file

@ -1,4 +1,6 @@
build build
__pycache__
dist
*.elf *.elf
*.nacp *.nacp
*.nro *.nro
@ -7,11 +9,7 @@ build
*.pfs0 *.pfs0
*.lst *.lst
*.tar.bz2 *.tar.bz2
*.log
*.spec
/code_templates/tmp/* /code_templates/tmp/*
/source/main.c /source/main.c
*.log
# Clion files
.idea
cmake-build-debug
CMakeLists.txt

View file

@ -40,11 +40,13 @@ import time
import struct import struct
import usb.core import usb.core
import usb.util import usb.util
import warnings
import tkinter as tk import tkinter as tk
import tkinter.ttk as ttk
from tkinter import filedialog, messagebox, font, scrolledtext from tkinter import filedialog, messagebox, font, scrolledtext
from tqdm.tk import trange, tqdm_tk from tqdm import tqdm
import base64 import base64
import io import io
@ -249,6 +251,76 @@ class LogConsole:
self.frame.after(100, self.poll_log_queue) self.frame.after(100, self.poll_log_queue)
# Loosely based on tk.py from tqdm.
class ProgressBar:
def __init__(self, total, prefix='', unit='B', bar_format=None, tk_parent=None, window_title='', window_resize=False, window_protocol=None):
if (tk_parent is None) or (total <= 0):
raise Exception('Invalid arguments!')
self.n = 0
self.total = total
self.prefix = prefix
self.unit = unit
self.bar_format = bar_format
self.tk_parent = tk_parent
self.tk_window = tk.Toplevel(self.tk_parent)
if window_title:
self.tk_window.title(window_title)
self.tk_window.resizable(window_resize, window_resize)
if window_protocol:
self.tk_window.protocol('WM_DELETE_WINDOW', window_protocol)
self.tk_window.attributes('-topmost', True)
self.tk_window.after(0, lambda: self.tk_window.attributes('-topmost', False))
pbar_frame = ttk.Frame(self.tk_window, padding=5)
pbar_frame.pack()
self.tk_text_var = tk.StringVar(self.tk_window)
tk_label = ttk.Label(pbar_frame, textvariable=self.tk_text_var, wraplength=600, anchor='center', justify='center')
tk_label.pack()
self.tk_n_var = tk.DoubleVar(self.tk_window, value=0)
self.tk_pbar = ttk.Progressbar(pbar_frame, variable=self.tk_n_var, length=450)
self.tk_pbar.configure(maximum=self.total, mode='determinate')
self.tk_pbar.pack()
self.start = time.time()
self.update(0)
def close(self):
self.tk_parent.after(0, self.tk_window.destroy)
def update(self, n):
if (self.n + n) > self.total:
return
self.n += n
elapsed = (time.time() - self.start)
msg = tqdm.format_meter(n=self.n, total=self.total, elapsed=elapsed, prefix=self.prefix, unit=self.unit, bar_format=self.bar_format)
self.tk_text_var.set(msg)
self.tk_n_var.set(self.n)
def reset(self, total):
if (total <= 0):
raise Exception('Invalid total value!')
self.n = 0
self.total = total
self.tk_pbar.configure(maximum=self.total, mode='determinate')
self.start = time.time()
self.update(0)
def utilsIsValueAlignedToEndpointPacketSize(value): def utilsIsValueAlignedToEndpointPacketSize(value):
return bool((value & (g_usbEpMaxPacketSize - 1)) == 0) return bool((value & (g_usbEpMaxPacketSize - 1)) == 0)
@ -496,20 +568,17 @@ def usbHandleSendFileProperties(cmd_block):
# Initialize progress bar. # Initialize progress bar.
(unit, unit_divisor) = utilsGetSizeUnitAndDivisor(file_size) (unit, unit_divisor) = utilsGetSizeUnitAndDivisor(file_size)
total = (float(file_size) / unit_divisor)
idx = filename.rfind(os.path.sep) idx = filename.rfind(os.path.sep)
bar_format_filename = (filename[idx+1:] if (idx >= 0) else filename) prefix_filename = (filename[idx+1:] if (idx >= 0) else filename)
bar_format = ('Current file: "%s".\n' % (bar_format_filename)) prefix = ('Current file: "%s".\n' % (prefix_filename))
bar_format += 'Use your console to cancel the file transfer if you wish to do so.\n\n' prefix += 'Use your console to cancel the file transfer if you wish to do so.\n\n'
bar_format += '{percentage:.2f}% - {n:.2f} / {total:.2f} {unit}\nElapsed time: {elapsed}. Remaining time: {remaining}.\nSpeed: {rate_fmt}.'
pbar = tqdm_tk(total=(float(file_size) / unit_divisor), unit=unit, bar_format=bar_format, grab=False, tk_parent=g_tkRoot) bar_format = '{desc}{percentage:.2f}% - {n:.2f} / {total:.2f} {unit}\nElapsed time: {elapsed}. Remaining time: {remaining}.\nSpeed: {rate_fmt}.'
pbar._tk_window.title('File transfer')
pbar._tk_window.resizable(False, False)
pbar._tk_window.protocol('WM_DELETE_WINDOW', uiHandleExitProtocolStub)
start_time = time.time() pbar = ProgressBar(total, prefix, unit, bar_format, g_tkRoot, 'File transfer', False, uiHandleExitProtocolStub)
def cancelTransfer(): def cancelTransfer():
# Cancel file transfer. # Cancel file transfer.
@ -517,7 +586,6 @@ def usbHandleSendFileProperties(cmd_block):
os.remove(fullpath) os.remove(fullpath)
utilsResetNspInfo() utilsResetNspInfo()
pbar.close() pbar.close()
pbar._tk_window.destroy()
while offset < file_size: while offset < file_size:
# Update block size (if needed). # Update block size (if needed).
@ -569,20 +637,18 @@ def usbHandleSendFileProperties(cmd_block):
# Update progress bar once per second. # Update progress bar once per second.
pbar.update(float(chunk_size) / unit_divisor) pbar.update(float(chunk_size) / unit_divisor)
pbar.refresh() #pbar.refresh()
elapsed_time = round(time.time() - pbar.start)
g_Logger.info('File transfer successfully completed in %s!\n' % (tqdm.format_interval(elapsed_time)))
# Close progress bar # Close progress bar
pbar.close() pbar.close()
pbar._tk_window.destroy()
# Close file handle (if needed). # Close file handle (if needed).
if g_nspTransferMode == False: if g_nspTransferMode == False:
file.close() file.close()
# I'd like to get this info from tqdm but it's not possible.
elapsed_time = round(time.time() - start_time)
g_Logger.info('File transfer successfully completed in %us!\n' % (elapsed_time))
return USB_STATUS_SUCCESS return USB_STATUS_SUCCESS
def usbHandleSendNspHeader(cmd_block): def usbHandleSendNspHeader(cmd_block):
@ -610,7 +676,7 @@ def usbHandleSendNspHeader(cmd_block):
g_nspFile.write(cmd_block) g_nspFile.write(cmd_block)
g_nspFile.close() g_nspFile.close()
g_Logger.debug('Successfully wrote 0x%X byte-long NSP header to "%s".' % (nsp_header_size, g_nspFilePath)) g_Logger.debug('Successfully wrote 0x%X byte-long NSP header to "%s".\n' % (nsp_header_size, g_nspFilePath))
# Disable NSP transfer mode. # Disable NSP transfer mode.
utilsResetNspInfo() utilsResetNspInfo()
@ -778,11 +844,8 @@ def uiScaleMeasure(measure):
def main(): def main():
global SCALE, g_tkRoot, g_tkCanvas, g_tkDirText, g_tkChooseDirButton, g_tkServerButton, g_tkTipMessage, g_tkScrolledTextLog global SCALE, g_tkRoot, g_tkCanvas, g_tkDirText, g_tkChooseDirButton, g_tkServerButton, g_tkTipMessage, g_tkScrolledTextLog
# Configure logging mechanism. # Disable warnings.
logging.basicConfig(level=logging.DEBUG) warnings.filterwarnings("ignore")
"""if len(g_Logger.handlers) > 0:
log_stderr = g_Logger.handlers[0]
g_Logger.removeHandler(log_stderr)"""
# Get OS information. # Get OS information.
os_type = platform.system() os_type = platform.system()
@ -874,6 +937,12 @@ def main():
g_tkCanvas.create_text(uiScaleMeasure(5), uiScaleMeasure(WINDOW_HEIGHT - 10), text="Copyright (c) {}, {}".format(COPYRIGHT_YEAR, USB_DEV_MANUFACTURER), anchor=tk.W) g_tkCanvas.create_text(uiScaleMeasure(5), uiScaleMeasure(WINDOW_HEIGHT - 10), text="Copyright (c) {}, {}".format(COPYRIGHT_YEAR, USB_DEV_MANUFACTURER), anchor=tk.W)
# Configure logging mechanism.
logging.basicConfig(level=logging.DEBUG)
if len(g_Logger.handlers) > 0:
log_stderr = g_Logger.handlers[0]
g_Logger.removeHandler(log_stderr)
# Initialize console g_Logger. # Initialize console g_Logger.
console = LogConsole(g_tkScrolledTextLog) console = LogConsole(g_tkScrolledTextLog)