From 0786dd73596df65681e7d0b9eddc9ef2f346727e Mon Sep 17 00:00:00 2001 From: Shaurya Date: Fri, 8 May 2026 15:53:23 +0530 Subject: [PATCH 1/6] Enhance build workflow with Ruby and FPM support Added Ruby setup and FPM package build steps to the workflow. --- .github/workflows/build.yml | 61 ++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 428eeffb..52ad600b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,11 +34,18 @@ jobs: libgl1 \ libegl1 \ libdbus-1-3 \ + ruby-dev\ + build-essential\ + rpm\ libxcb-cursor0 - - name: Build AppImage + - name: Prepare Scripts run: | - chmod +x scripts/build-appimage.sh - bash scripts/build-appimage.sh + chmod +x appimage-setup.sh + chmod +x appimage-installer-config.sh + - name: Run Installer Config + run: ./appimage-installer-config.sh + - name: Build AppImage + run: bash appimage-setup.sh - name: Verify AppImage run: | @@ -77,7 +84,7 @@ jobs: - name: Install dependencies run: | - pip install pyinstaller PyQt6 psutil pyudev packaging platformdirs + pip install pyinstaller PyQt6 psutil pyudev requests packaging platformdirs - name: Build with PyInstaller run: | @@ -105,4 +112,48 @@ jobs: files: | Lufus-x86_64-${{ github.ref_name }}.tar.gz Lufus-x86_64-${{ github.ref_name }}.tar.gz.sha256 - append_body: true \ No newline at end of file + append_body: true + + # for fpm packages + build-fpm: + needs: build-tarball + runs-on: ubuntu-latest + permissions: + contents: write + strategy: + matrix: + pkg_type: [deb, rpm] + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: actions/setup-ruby@v1 + with: + ruby-version: '3.2' + + - name: Install FPM + run: gem install fpm + + - name: Download tarball from release + run: | + wget https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/Lufus-x86_64-${{ github.ref_name }}.tar.gz + + - name: Build ${{ matrix.pkg_type }} Package + run: | + mkdir tmp_source && tar -xzf Lufus-x86_64-${{ github.ref_name }}.tar.gz -C tmp_source + fpm -s dir -t ${{ matrix.pkg_type }} \ + -n "Lufus" \ + -v "${{ github.ref_name }}" \ + --iteration 1 \ + --prefix /opt/lufus \ + --description "Physical drive imaging and formatting utility" \ + -C tmp_source/Lufus-x86_64-${{ github.ref_name }} . + + - name: Upload to Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.ref_name }} + files: | + *.deb + *.rpm + append_body: true From 363e89f9dc09eddfbb3704f61f99dd0a3d26de6d Mon Sep 17 00:00:00 2001 From: Shaurya Date: Fri, 8 May 2026 16:18:05 +0530 Subject: [PATCH 2/6] Update build.yml to fix appimage issue --- .github/workflows/build.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 52ad600b..58331d67 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Build & Release AppImage +name: Build & Release Packages on: push: @@ -34,18 +34,15 @@ jobs: libgl1 \ libegl1 \ libdbus-1-3 \ - ruby-dev\ - build-essential\ - rpm\ libxcb-cursor0 - name: Prepare Scripts run: | - chmod +x appimage-setup.sh - chmod +x appimage-installer-config.sh + chmod +x scripts/appimage-setup.sh + chmod +x scripts/appimage-installer-config.sh - name: Run Installer Config - run: ./appimage-installer-config.sh + run: ./scripts/appimage-installer-config.sh - name: Build AppImage - run: bash appimage-setup.sh + run: bash scripts/appimage-setup.sh - name: Verify AppImage run: | @@ -84,7 +81,7 @@ jobs: - name: Install dependencies run: | - pip install pyinstaller PyQt6 psutil pyudev requests packaging platformdirs + pip install pyinstaller PyQt6 psutil pyudev requests packaging platformdirs requests - name: Build with PyInstaller run: | From 12005f5a616b6e902efa24564ca10a140f36d039 Mon Sep 17 00:00:00 2001 From: Shaurya Date: Fri, 8 May 2026 16:55:50 +0530 Subject: [PATCH 3/6] Refactor AppImage build process in workflow Removed unnecessary preparation steps for scripts and integrated them into the Build AppImage step. --- .github/workflows/build.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 58331d67..bec93acf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,14 +35,10 @@ jobs: libegl1 \ libdbus-1-3 \ libxcb-cursor0 - - name: Prepare Scripts - run: | - chmod +x scripts/appimage-setup.sh - chmod +x scripts/appimage-installer-config.sh - - name: Run Installer Config - run: ./scripts/appimage-installer-config.sh - name: Build AppImage - run: bash scripts/appimage-setup.sh + run: | + chmod +x scripts/build-appimage.sh + bash scripts/appimage-setup.sh - name: Verify AppImage run: | From b9aa755e9a999f5cf14779361e823762ba89cb92 Mon Sep 17 00:00:00 2001 From: Shaurya Date: Fri, 8 May 2026 17:00:41 +0530 Subject: [PATCH 4/6] Fix build script call in GitHub Actions workflow --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bec93acf..9fdcbac2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,7 +38,7 @@ jobs: - name: Build AppImage run: | chmod +x scripts/build-appimage.sh - bash scripts/appimage-setup.sh + bash scripts/build-appimage.sh - name: Verify AppImage run: | From ec30799e070fe248b0dd5503052aca0e063f8484 Mon Sep 17 00:00:00 2001 From: Shaurya Singh Date: Sat, 9 May 2026 12:07:15 +0530 Subject: [PATCH 5/6] shifted codebase from pyqt6 to pyside6 --- pyproject.toml | 8 +- requirements-python.txt | 1 + src/lufus/drives/autodetect_usb.py | 27 +- src/lufus/gui/dialogs.py | 30 +- src/lufus/gui/gui.py | 429 ++++++++++++++++++++++------- src/lufus/gui/scale.py | 2 +- src/lufus/gui/start_gui.py | 8 +- src/lufus/gui/themes/icon_utils.py | 6 +- src/lufus/gui/workers.py | 68 +++-- 9 files changed, 423 insertions(+), 156 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c943990a..72d532d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,8 @@ license = "MIT" requires-python = ">=3.10" dependencies = [ "psutil>=7.2", - "pyqt6>=6.8.0", + "pyside6", + # "pyqt6>=6.8.0", "pyudev>=0.24.4", "packaging", "platformdirs>=4.2", @@ -48,10 +49,11 @@ test_sources = [ ] requires = [ "psutil>=7.2", - "pyqt6>=6.8.0", + "pyside6", + # "pyqt6>=6.8.0", "pyudev>=0.24.4", "packaging", - "platformdirs>=4.2" + "platformdirs>=4.2", ] test_requires = [ "pytest", diff --git a/requirements-python.txt b/requirements-python.txt index 0e3dcd4e..ecfb9e12 100644 --- a/requirements-python.txt +++ b/requirements-python.txt @@ -1,4 +1,5 @@ pyinstaller +pyside6 pyqt6 psutil pyudev diff --git a/src/lufus/drives/autodetect_usb.py b/src/lufus/drives/autodetect_usb.py index 7716ad06..a7beecf8 100644 --- a/src/lufus/drives/autodetect_usb.py +++ b/src/lufus/drives/autodetect_usb.py @@ -1,4 +1,4 @@ -from PyQt6.QtCore import QObject, pyqtSignal, QSocketNotifier +from PySide6.QtCore import QObject, Signal, QSocketNotifier import pyudev from lufus.lufus_logging import get_logger @@ -6,9 +6,9 @@ class UsbMonitor(QObject): - device_added = pyqtSignal(str) - device_removed = pyqtSignal(str) - device_list_updated = pyqtSignal(dict) + device_added = Signal(str) + device_removed = Signal(str) + device_list_updated = Signal(dict) def __init__(self): super().__init__() @@ -50,7 +50,9 @@ def _load_existing(self): serial, ) found += 1 - log.info("UsbMonitor: initial scan complete, %d USB block device(s) found", found) + log.info( + "UsbMonitor: initial scan complete, %d USB block device(s) found", found + ) def _on_socket_ready(self): while True: @@ -67,7 +69,10 @@ def _handle_event(self, device): node = device.device_node if not node: - log.warning("UsbMonitor: ignoring event with no device_node (action=%s)", device.action) + log.warning( + "UsbMonitor: ignoring event with no device_node (action=%s)", + device.action, + ) return action = device.action @@ -93,11 +98,17 @@ def _handle_event(self, device): elif action == "remove": if node in self.devices: removed_label = self.devices.pop(node) - log.info("UsbMonitor: device removed: %s (was labeled %r)", node, removed_label) + log.info( + "UsbMonitor: device removed: %s (was labeled %r)", + node, + removed_label, + ) self.device_removed.emit(node) changed = True else: - log.warning("UsbMonitor: remove event for unknown node %s, ignoring", node) + log.warning( + "UsbMonitor: remove event for unknown node %s, ignoring", node + ) if changed: self.device_list_updated.emit(self.devices) diff --git a/src/lufus/gui/dialogs.py b/src/lufus/gui/dialogs.py index 2b8cf89a..898f205c 100644 --- a/src/lufus/gui/dialogs.py +++ b/src/lufus/gui/dialogs.py @@ -1,6 +1,6 @@ from pathlib import Path from platformdirs import user_config_dir -from PyQt6.QtWidgets import ( +from PySide6.QtWidgets import ( QApplication, QComboBox, QCheckBox, @@ -15,8 +15,8 @@ QTextEdit, QVBoxLayout, ) -from PyQt6.QtCore import Qt, pyqtSignal, QRegularExpression, QUrl -from PyQt6.QtGui import QFont, QRegularExpressionValidator, QDesktopServices +from PySide6.QtCore import Qt, Signal, QRegularExpression, QUrl +from PySide6.QtGui import QFont, QRegularExpressionValidator, QDesktopServices import sys from lufus import state as states @@ -153,7 +153,9 @@ def __init__(self, parent=None): self.about_text.setReadOnly(True) self.about_text.setObjectName("aboutContent") self.about_text.setFrameShape(QFrame.Shape.NoFrame) - self.about_text.setStyleSheet(f"font-family: {font_family}; font-size: {tool_pt}pt;") + self.about_text.setStyleSheet( + f"font-family: {font_family}; font-size: {tool_pt}pt;" + ) layout.addWidget(self.about_text, 1) btn_row0 = QHBoxLayout() btn_discord = QPushButton(self._T.get("btn_discord", "Join Discord Server")) @@ -189,8 +191,8 @@ def github_open(self): class SettingsDialog(QDialog): # signals for when settings change :D - language_changed = pyqtSignal(str) - theme_changed = pyqtSignal(str) + language_changed = Signal(str) + theme_changed = Signal(str) def __init__(self, parent=None): super().__init__(parent) @@ -220,7 +222,9 @@ def __init__(self, parent=None): if current_lang in languages: self.combo_language.setCurrentText(current_lang) else: - self.combo_language.addItem(self._T.get("settings_no_languages", "No languages found")) + self.combo_language.addItem( + self._T.get("settings_no_languages", "No languages found") + ) self.combo_language.setEnabled(False) layout.addWidget(lbl_lang) layout.addWidget(self.combo_language) @@ -294,9 +298,13 @@ def __init__(self, parent=None): self.setWindowTitle("Windows Tweaks (MAY BREAK! USE CAUTION)") self.setFixedSize(600, 300) self.ask_label = QLabel("Do you want to customize your windows installation?") - self.hardware_checkbox = QCheckBox("Remove requirement for 4GB+ RAM, Secure Boot and TPM 2.0") + self.hardware_checkbox = QCheckBox( + "Remove requirement for 4GB+ RAM, Secure Boot and TPM 2.0" + ) self.hardware_checkbox.stateChanged.connect(self.update_winhardware) - self.microsoft_checkbox = QCheckBox("Remove requirement for an online Microsoft Account") + self.microsoft_checkbox = QCheckBox( + "Remove requirement for an online Microsoft Account" + ) self.microsoft_checkbox.stateChanged.connect(self.update_winmicrosoftacc) self.localacc_checkbox = QCheckBox("Create a local account with username:") self.localacc_checkbox.stateChanged.connect(self.update_winlocalaccchk) @@ -308,7 +316,9 @@ def __init__(self, parent=None): self.localacc_checkbox.toggled.connect(self.username_input.setEnabled) self.username_input.setEnabled(self.localacc_checkbox.isChecked()) self.username_input.textChanged.connect(self.sync_username) - self.data_checkbox = QCheckBox("Disable data collection (skip privacy questions)") + self.data_checkbox = QCheckBox( + "Disable data collection (skip privacy questions)" + ) self.data_checkbox.stateChanged.connect(self.update_winprivacy) self.applytweaks_btn = QPushButton("Apply") self.applytweaks_btn.clicked.connect(self.applywintweaks) diff --git a/src/lufus/gui/gui.py b/src/lufus/gui/gui.py index af4cd738..754c5114 100644 --- a/src/lufus/gui/gui.py +++ b/src/lufus/gui/gui.py @@ -15,7 +15,7 @@ from platformdirs import user_config_dir from datetime import datetime from pathlib import Path -from PyQt6.QtWidgets import ( +from PySide6.QtWidgets import ( QApplication, QMainWindow, QWidget, @@ -35,12 +35,12 @@ QToolButton, QScrollArea, ) -from PyQt6.QtCore import ( +from PySide6.QtCore import ( Qt, QTimer, QPropertyAnimation, ) -from PyQt6.QtGui import QIcon +from PySide6.QtGui import QIcon from lufus import state from lufus import state as states @@ -74,7 +74,7 @@ def __init__(self, parent=None): def set_background(self, image_path): # load and cache bg pixmap :3 if image_path and Path(image_path).is_file(): - from PyQt6.QtGui import QPixmap + from PySide6.QtGui import QPixmap self._bg_pixmap = QPixmap(str(image_path)) else: @@ -83,7 +83,7 @@ def set_background(self, image_path): def paintEvent(self, event): if self._bg_pixmap and not self._bg_pixmap.isNull(): - from PyQt6.QtGui import QPainter + from PySide6.QtGui import QPainter painter = QPainter(self) # scale to fill widget keeping aspect ratio, centre-cropped :D @@ -190,7 +190,9 @@ def __init__(self, usb_devices=None, scale: Scale = None): f"Python {sys.version.split()[0]} | {platform.system()} {platform.release()} {platform.machine()}" ) self.log_message(f"Running as user: {getpass.getuser()} (uid={os.getuid()})") - self.log_message(f"Startup USB devices passed in: {list((usb_devices or {}).keys()) or 'none'}") + self.log_message( + f"Startup USB devices passed in: {list((usb_devices or {}).keys()) or 'none'}" + ) self.flash_worker = None self.log_message(f"UI scale factor: {self._S.f():.3f} (base 96 DPI)") self._check_latest_download() @@ -202,7 +204,9 @@ def _check_latest_download(self): if state.iso_path: return try: - result = subprocess.run(["xdg-user-dir", "DOWNLOAD"], capture_output=True, text=True, timeout=2) + result = subprocess.run( + ["xdg-user-dir", "DOWNLOAD"], capture_output=True, text=True, timeout=2 + ) downloads = ( Path(result.stdout.strip()) if result.returncode == 0 and result.stdout.strip() @@ -213,7 +217,9 @@ def _check_latest_download(self): if not downloads.is_dir(): return try: - isos = sorted(downloads.glob("*.iso"), key=lambda p: p.stat().st_mtime, reverse=True) + isos = sorted( + downloads.glob("*.iso"), key=lambda p: p.stat().st_mtime, reverse=True + ) except Exception: return if not isos: @@ -228,7 +234,9 @@ def _check_latest_download(self): self.combo_boot.setItemText(0, clean_name) self.input_label.setText(clean_name.rsplit(".", 1)[0].upper()) self.log_message(f"Latest download auto-loaded: {latest}") - self.log_message(f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)") + self.log_message( + f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)" + ) self._detect_iso_and_update_ui(str(latest)) def _apply_styles(self) -> None: @@ -258,7 +266,9 @@ def _apply_styles(self) -> None: with open(theme_json_path, "r", encoding="utf-8") as fr: theme = json.load(fr) except FileNotFoundError: - print("WARNING: no theme applied, json didn't load up in _apply_styles, gui.py.") + print( + "WARNING: no theme applied, json didn't load up in _apply_styles, gui.py." + ) return # check if gradients are enabled :3 @@ -321,7 +331,9 @@ def _apply_styles(self) -> None: # scale dimensions :3 for key, value in theme["dimensions"].items(): - scaled_theme["dimensions"][key] = value if key in NO_SCALE_KEYS else S.px(value) + scaled_theme["dimensions"][key] = ( + value if key in NO_SCALE_KEYS else S.px(value) + ) # flatten theme dict for template substitution flat_theme: Dict[str, Any] = {} @@ -443,7 +455,9 @@ def create_header(self, text): line = QFrame() line.setFrameShape(QFrame.Shape.HLine) line.setFrameShadow(QFrame.Shadow.Sunken) - line.setStyleSheet("background-color: palette(mid); min-height: 1px; max-height: 1px;") + line.setStyleSheet( + "background-color: palette(mid); min-height: 1px; max-height: 1px;" + ) layout.addWidget(label) layout.addWidget(line, 1) return layout, label @@ -455,7 +469,9 @@ def update_usb_list(self, devices: dict): if not devices: # show no devices message - self.combo_device.addItem(self._T.get("no_usb_found", "No USB devices found"), None) + self.combo_device.addItem( + self._T.get("no_usb_found", "No USB devices found"), None + ) return # add each device to combo @@ -524,7 +540,9 @@ def init_ui(self): # boot selection with file browser :D self.lbl_boot = QLabel(self._T.get("lbl_boot_selection", "Boot Selection")) self.combo_boot = QComboBox() - self.combo_boot.addItem(self._T.get("combo_boot_default", "installation_media.iso")) + self.combo_boot.addItem( + self._T.get("combo_boot_default", "installation_media.iso") + ) self.btn_select = QPushButton(self._T.get("btn_select", "Select")) self.btn_select.clicked.connect(self.browse_file) @@ -547,7 +565,9 @@ def init_ui(self): self.combo_image_option.addItem(self._T.get("combo_image_windows", "Windows")) self.combo_image_option.addItem(self._T.get("combo_image_linux", "Linux")) self.combo_image_option.addItem(self._T.get("combo_image_other", "Other")) - self.combo_image_option.addItem(self._T.get("combo_image_format", "Format Only")) + self.combo_image_option.addItem( + self._T.get("combo_image_format", "Format Only") + ) # self.combo_image_option.addItem(self._T.get("combo_image_ventoy", "Ventoy")) self.combo_image_option.currentTextChanged.connect(self.update_image_option) @@ -585,14 +605,18 @@ def init_ui(self): main_layout.addSpacing(S.px(6)) # format options section :3 - _hdr_fmt, self.lbl_header_format = self.create_header(self._T.get("header_format_options", "Format Options")) + _hdr_fmt, self.lbl_header_format = self.create_header( + self._T.get("header_format_options", "Format Options") + ) main_layout.addLayout(_hdr_fmt) main_layout.addSpacing(S.px(4)) # volume label input field self.lbl_vol = QLabel(self._T.get("lbl_volume_label", "Volume Label")) self.input_label = QLineEdit() - self.input_label.setPlaceholderText(self._T.get("lbl_volume_label", "Volume Label")) + self.input_label.setPlaceholderText( + self._T.get("lbl_volume_label", "Volume Label") + ) self.input_label.textChanged.connect(self.update_new_label) vol_layout = QVBoxLayout() @@ -658,12 +682,16 @@ def init_ui(self): self.chk_quick.setChecked(True) self.chk_quick.stateChanged.connect(self.update_QF) - self.chk_extended = QCheckBox(self._T.get("chk_extended_label", "Create Extended Label")) + self.chk_extended = QCheckBox( + self._T.get("chk_extended_label", "Create Extended Label") + ) self.chk_extended.setChecked(True) self.chk_extended.stateChanged.connect(self.update_create_extended) # bad blocks check with pass selector :3 - self.chk_badblocks = QCheckBox(self._T.get("chk_bad_blocks", "Check for Bad Blocks")) + self.chk_badblocks = QCheckBox( + self._T.get("chk_bad_blocks", "Check for Bad Blocks") + ) self.combo_badblocks = QComboBox() self.combo_badblocks.addItem(self._T.get("combo_badblocks_1pass", "1 Pass")) self.combo_badblocks.addItem(self._T.get("combo_badblocks_2pass", "2 Pass")) @@ -674,12 +702,18 @@ def init_ui(self): self.update_check_bad() # sha256 verification checkbox and input :D - self.chk_verify = QCheckBox(self._T.get("chk_verify_hash", "Verify SHA256 Checksum")) + self.chk_verify = QCheckBox( + self._T.get("chk_verify_hash", "Verify SHA256 Checksum") + ) self.chk_verify.stateChanged.connect(self.update_verify_hash) - self.lbl_expected_hash = QLabel(self._T.get("lbl_expected_hash", "Expected SHA256:")) + self.lbl_expected_hash = QLabel( + self._T.get("lbl_expected_hash", "Expected SHA256:") + ) self.lbl_expected_hash.setVisible(False) self.input_hash = QLineEdit() - self.input_hash.setPlaceholderText(self._T.get("input_hash_placeholder", "Enter expected SHA256 hash here...")) + self.input_hash.setPlaceholderText( + self._T.get("input_hash_placeholder", "Enter expected SHA256 hash here...") + ) self.input_hash.setEnabled(False) self.input_hash.setMaximumHeight(0) self.input_hash.textChanged.connect(self.update_expected_hash) @@ -701,7 +735,9 @@ def init_ui(self): main_layout.addSpacing(S.px(6)) # status section with progress bar :D - _hdr_status, self.lbl_header_status = self.create_header(self._T.get("header_status", "Status")) + _hdr_status, self.lbl_header_status = self.create_header( + self._T.get("header_status", "Status") + ) main_layout.addLayout(_hdr_status) main_layout.addSpacing(S.px(4)) @@ -773,7 +809,9 @@ def init_ui(self): self._lbl_speed_eta = QLabel("") self._lbl_speed_eta.setObjectName("speedEtaLabel") self._lbl_speed_eta.setMinimumWidth(S.px(220)) - self._lbl_speed_eta.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) + self._lbl_speed_eta.setAlignment( + Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter + ) self.statusBar.addPermanentWidget(self._lbl_speed_eta) self.update_image_option() @@ -802,7 +840,9 @@ def _populate_device_combo(self): self.combo_device.addItem(display, node) else: # show no devices found message :3 - self.combo_device.addItem(self._T.get("no_usb_found", "No USB devices found"), None) + self.combo_device.addItem( + self._T.get("no_usb_found", "No USB devices found"), None + ) self.combo_device.blockSignals(False) @@ -812,13 +852,17 @@ def refresh_usb_devices(self): self.log_message("USB device scan initiated") try: new_devices = self.monitor.devices - self.log_message(f"USB scan result: {len(new_devices)} device(s) found: {list(new_devices.keys())}") + self.log_message( + f"USB scan result: {len(new_devices)} device(s) found: {list(new_devices.keys())}" + ) if new_devices: # update device list with new devices :3 self.usb_devices = new_devices self._populate_device_combo() - self.log_message(f"Device list updated: {[f'{k} ({v})' for k, v in new_devices.items()]}") + self.log_message( + f"Device list updated: {[f'{k} ({v})' for k, v in new_devices.items()]}" + ) QMessageBox.information( self, self._T.get("msgbox_usb_found_title", "USB Found"), @@ -836,7 +880,9 @@ def refresh_usb_devices(self): ) except Exception as e: # handle scan errors :3 - self.statusBar.showMessage(self._T.get("status_scan_failed", "Scan Failed"), 3000) + self.statusBar.showMessage( + self._T.get("status_scan_failed", "Scan Failed"), 3000 + ) self.log_message( f"USB scan raised exception: {type(e).__name__}: {str(e)}", level="ERROR", @@ -850,12 +896,16 @@ def refresh_usb_devices(self): def updateFS(self): # update filesystem selection in states :D state.filesystem_index = self.combo_fs.currentIndex() - self.log_message(f"File system changed to: {self.combo_fs.currentText()} (index={state.filesystem_index})") + self.log_message( + f"File system changed to: {self.combo_fs.currentText()} (index={state.filesystem_index})" + ) def updateflash(self): # update flash mode selection in states :3 state.flash_mode = self.combo_flash.currentIndex() - self.log_message(f"Flash option changed to: {self.combo_flash.currentText()} (index={state.flash_mode})") + self.log_message( + f"Flash option changed to: {self.combo_flash.currentText()} (index={state.flash_mode})" + ) def update_image_option(self): # update image option and refresh available filesystems and flash modes :D @@ -955,12 +1005,16 @@ def update_new_label(self, current_text): def update_cluster_size(self): # update cluster size selection :D state.cluster_size = self.combo_cluster.currentIndex() - self.log_message(f"Cluster size changed to: {self.combo_cluster.currentText()} (index={state.cluster_size})") + self.log_message( + f"Cluster size changed to: {self.combo_cluster.currentText()} (index={state.cluster_size})" + ) def update_QF(self): # update quick format setting :3 state.quick_format = 0 if self.chk_quick.isChecked() else 1 - self.log_message(f"Quick format: {'enabled' if self.chk_quick.isChecked() else 'disabled'}") + self.log_message( + f"Quick format: {'enabled' if self.chk_quick.isChecked() else 'disabled'}" + ) def update_create_extended(self): # update extended label creation setting :D @@ -992,7 +1046,9 @@ def update_check_bad(self): show = self.chk_badblocks.isChecked() self.combo_badblocks.setEnabled(show) self._animate_widget(self.combo_badblocks, show, "_anim_badblocks") - self.log_message(f"Bad block check: {'enabled' if self.chk_badblocks.isChecked() else 'disabled'}") + self.log_message( + f"Bad block check: {'enabled' if self.chk_badblocks.isChecked() else 'disabled'}" + ) def update_verify_hash(self): # update sha256 verification setting :D @@ -1001,7 +1057,9 @@ def update_verify_hash(self): if hasattr(self, "lbl_expected_hash"): self.lbl_expected_hash.setVisible(state.verify_hash) self._animate_widget(self.input_hash, state.verify_hash, "_anim_hash") - self.log_message(f"SHA256 verification: {'enabled' if state.verify_hash else 'disabled'}") + self.log_message( + f"SHA256 verification: {'enabled' if state.verify_hash else 'disabled'}" + ) def update_expected_hash(self, text): # store expected hash for verification :3 @@ -1012,7 +1070,9 @@ def _load_latest_download_iso(self): downloads_dir = Path.home() / "Downloads" if not downloads_dir.is_dir(): return - isos = sorted(downloads_dir.glob("*.iso"), key=lambda p: p.stat().st_mtime, reverse=True) + isos = sorted( + downloads_dir.glob("*.iso"), key=lambda p: p.stat().st_mtime, reverse=True + ) if not isos: return latest = isos[0] @@ -1022,7 +1082,9 @@ def _load_latest_download_iso(self): self.combo_boot.setItemText(0, clean_name) self.input_label.setText(latest.stem.upper()) self.log_message(f"Latest download ISO loaded: {latest}") - self.log_message(f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)") + self.log_message( + f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)" + ) def _check_clipboard(self): # monitor clipboard for iso file paths :D @@ -1031,7 +1093,11 @@ def _check_clipboard(self): if mime.hasUrls(): for url in mime.urls(): local_file = url.toLocalFile() - if local_file and local_file.lower().endswith(".iso") and Path(local_file).is_file(): + if ( + local_file + and local_file.lower().endswith(".iso") + and Path(local_file).is_file() + ): if local_file == self._last_clipboard: return self._last_clipboard = local_file @@ -1041,7 +1107,9 @@ def _check_clipboard(self): self.combo_boot.setItemText(0, clean_name) self.input_label.setText(clean_name.split(".")[0].upper()) self.log_message(f"Image loaded from clipboard: {local_file}") - self.log_message(f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)") + self.log_message( + f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)" + ) return text = clipboard.text().strip() if text == self._last_clipboard: @@ -1056,13 +1124,18 @@ def _check_clipboard(self): self.combo_boot.setItemText(0, clean_name) self.input_label.setText(clean_name.split(".")[0].upper()) self.log_message(f"Image loaded from clipboard: {path}") - self.log_message(f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)") + self.log_message( + f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)" + ) def dragEnterEvent(self, event): # accept drag of supported image files :D if event.mimeData().hasUrls(): supported = [".iso", ".dmg", ".img", ".bin", ".raw"] - if any(url.toLocalFile().lower().endswith(tuple(supported)) for url in event.mimeData().urls()): + if any( + url.toLocalFile().lower().endswith(tuple(supported)) + for url in event.mimeData().urls() + ): event.acceptProposedAction() return event.ignore() @@ -1071,7 +1144,10 @@ def dragMoveEvent(self, event): # accept drag move of supported image files :3 if event.mimeData().hasUrls(): supported = [".iso", ".dmg", ".img", ".bin", ".raw"] - if any(url.toLocalFile().lower().endswith(tuple(supported)) for url in event.mimeData().urls()): + if any( + url.toLocalFile().lower().endswith(tuple(supported)) + for url in event.mimeData().urls() + ): event.acceptProposedAction() return event.ignore() @@ -1080,7 +1156,9 @@ def dropEvent(self, event): # handle dropped image files :D supported = [".iso", ".dmg", ".img", ".bin", ".raw"] img_files = [ - url.toLocalFile() for url in event.mimeData().urls() if url.toLocalFile().lower().endswith(tuple(supported)) + url.toLocalFile() + for url in event.mimeData().urls() + if url.toLocalFile().lower().endswith(tuple(supported)) ] if img_files: # load first dropped image file :3 @@ -1091,7 +1169,9 @@ def dropEvent(self, event): self.combo_boot.setItemText(0, clean_name) self.input_label.setText(clean_name.split(".")[0].upper()) self.log_message(f"Image selected via drag-and-drop: {file_name}") - self.log_message(f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)") + self.log_message( + f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)" + ) self._detect_iso_and_update_ui(file_name) event.acceptProposedAction() else: @@ -1116,7 +1196,9 @@ def browse_file(self): self.combo_boot.setItemText(0, clean_name) self.input_label.setText(clean_name.split(".")[0].upper()) self.log_message(f"Image selected: {file_name}") - self.log_message(f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)") + self.log_message( + f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)" + ) self._detect_iso_and_update_ui(file_name) def _detect_iso_and_update_ui(self, iso_path: str): @@ -1125,7 +1207,9 @@ def _detect_iso_and_update_ui(self, iso_path: str): # Non-ISO raw images (.img, .bin, .raw, .dmg) are always "Other / DD mode" if not iso_path.lower().endswith(".iso"): - self.log_message(f"Non-ISO image ({Path(iso_path).suffix or 'no ext'}), defaulting to Other/DD mode") + self.log_message( + f"Non-ISO image ({Path(iso_path).suffix or 'no ext'}), defaulting to Other/DD mode" + ) self.combo_image_option.setCurrentIndex(2) # Other return @@ -1155,8 +1239,14 @@ def show_log(self): level = lvl break _, colour = _LOG_LEVELS.get(level, ("info", None)) - escaped = entry.replace("&", "&").replace("<", "<").replace(">", ">") - html = f'{escaped}' if colour else f"{escaped}" + escaped = ( + entry.replace("&", "&").replace("<", "<").replace(">", ">") + ) + html = ( + f'{escaped}' + if colour + else f"{escaped}" + ) self.log_window.log_text.append(html) self.log_window.show() self.log_window.raise_() @@ -1174,8 +1264,14 @@ def log_message(self, msg, level="INFO"): getattr(self._logger, log_method_name)(msg) if self.log_window is not None: # update log window if open :D - escaped = entry.replace("&", "&").replace("<", "<").replace(">", ">") - html = f'{escaped}' if colour else f"{escaped}" + escaped = ( + entry.replace("&", "&").replace("<", "<").replace(">", ">") + ) + html = ( + f'{escaped}' + if colour + else f"{escaped}" + ) self.log_window.log_text.append(html) scrollbar = self.log_window.log_text.verticalScrollBar() scrollbar.setValue(scrollbar.maximum()) @@ -1215,7 +1311,9 @@ def apply_theme(self, theme_name): # set active theme by name and re-apply styles :D user_config_dir_path = Path(user_config_dir("Lufus")) builtin_json = THEME_DIR / theme_name / f"{theme_name}_theme.json" - user_json = user_config_dir_path / "themes" / theme_name / f"{theme_name}_theme.json" + user_json = ( + user_config_dir_path / "themes" / theme_name / f"{theme_name}_theme.json" + ) if builtin_json.exists() or user_json.exists(): state.theme = theme_name # persist so it survives restarts without needing the env var :3 @@ -1241,8 +1339,12 @@ def apply_language(self, language): def _update_ui_text(self): # update all text labels with new translations :3 self.setWindowTitle(self._T.get("window_title", "lufus")) - self.lbl_header_drive.setText(self._T.get("header_drive_properties", "Drive Properties")) - self.lbl_header_format.setText(self._T.get("header_format_options", "Format Options")) + self.lbl_header_drive.setText( + self._T.get("header_drive_properties", "Drive Properties") + ) + self.lbl_header_format.setText( + self._T.get("header_format_options", "Format Options") + ) self.lbl_header_status.setText(self._T.get("header_status", "Status")) self.lbl_device.setText(self._T.get("lbl_device", "Device")) self.lbl_boot.setText(self._T.get("lbl_boot_selection", "Boot Selection")) @@ -1255,14 +1357,20 @@ def _update_ui_text(self): self.lbl_flash.setText(self._T.get("lbl_flash_option", "Flash Option")) self.lbl_cluster.setText(self._T.get("lbl_cluster_size", "Cluster Size")) self.chk_quick.setText(self._T.get("chk_quick_format", "Quick Format")) - self.chk_extended.setText(self._T.get("chk_extended_label", "Create Extended Label")) - self.chk_badblocks.setText(self._T.get("chk_bad_blocks", "Check for Bad Blocks")) + self.chk_extended.setText( + self._T.get("chk_extended_label", "Create Extended Label") + ) + self.chk_badblocks.setText( + self._T.get("chk_bad_blocks", "Check for Bad Blocks") + ) self.btn_start.setText(self._T.get("btn_start", "Start")) self.btn_cancel.setText(self._T.get("btn_cancel", "Cancel")) self.statusBar.showMessage(self._T.get("status_ready", "Ready"), 0) # update toolbar button tooltips :3 - self.btn_refresh.setToolTip(self._T.get("tooltip_refresh", "Refresh USB devices (Ctrl+R)")) + self.btn_refresh.setToolTip( + self._T.get("tooltip_refresh", "Refresh USB devices (Ctrl+R)") + ) self.btn_icon1.setToolTip(self._T.get("tooltip_website", "Website")) self.btn_icon2.setToolTip(self._T.get("tooltip_about", "About")) self.btn_icon3.setToolTip(self._T.get("tooltip_settings", "Settings")) @@ -1275,7 +1383,9 @@ def _update_ui_text(self): self.combo_image_option.addItem(self._T.get("combo_image_windows", "Windows")) self.combo_image_option.addItem(self._T.get("combo_image_linux", "Linux")) self.combo_image_option.addItem(self._T.get("combo_image_other", "Other")) - self.combo_image_option.addItem(self._T.get("combo_image_format", "Format Only")) + self.combo_image_option.addItem( + self._T.get("combo_image_format", "Format Only") + ) # self.combo_image_option.addItem(self._T.get("combo_image_ventoy", "Ventoy")) self.combo_image_option.setCurrentIndex(current_img_idx) self.combo_image_option.blockSignals(False) @@ -1300,21 +1410,35 @@ def _update_ui_text(self): self.combo_badblocks.blockSignals(False) # update verification controls :D - self.chk_verify.setText(self._T.get("chk_verify_hash", "Verify SHA256 Checksum")) - self.lbl_expected_hash.setText(self._T.get("lbl_expected_hash", "Expected SHA256:")) - self.input_hash.setPlaceholderText(self._T.get("input_hash_placeholder", "Enter expected SHA256 hash here...")) - self.input_label.setPlaceholderText(self._T.get("lbl_volume_label", "Volume Label")) + self.chk_verify.setText( + self._T.get("chk_verify_hash", "Verify SHA256 Checksum") + ) + self.lbl_expected_hash.setText( + self._T.get("lbl_expected_hash", "Expected SHA256:") + ) + self.input_hash.setPlaceholderText( + self._T.get("input_hash_placeholder", "Enter expected SHA256 hash here...") + ) + self.input_label.setPlaceholderText( + self._T.get("lbl_volume_label", "Volume Label") + ) # update boot combo default text :3 - if self.combo_boot.itemText(0) == "installation_media.iso" or self.combo_boot.itemText(0) == self._T.get( + if self.combo_boot.itemText( + 0 + ) == "installation_media.iso" or self.combo_boot.itemText(0) == self._T.get( "combo_boot_default", "installation_media.iso" ): - self.combo_boot.setItemText(0, self._T.get("combo_boot_default", "installation_media.iso")) + self.combo_boot.setItemText( + 0, self._T.get("combo_boot_default", "installation_media.iso") + ) if not self.usb_devices: # update no devices message :D self.combo_device.clear() - self.combo_device.addItem(self._T.get("no_usb_found", "No USB devices found"), None) + self.combo_device.addItem( + self._T.get("no_usb_found", "No USB devices found"), None + ) self._update_flashing_options() self._apply_accessible_names() @@ -1333,13 +1457,19 @@ def cancel_process(self): ) if reply == QMessageBox.StandardButton.Yes: device_node = self.get_selected_mount_path() - self.log_message(f"Cancellation requested for device {device_node}", level="WARN") + self.log_message( + f"Cancellation requested for device {device_node}", level="WARN" + ) try: # check what processes are using device :3 - lsof = subprocess.run(["lsof", device_node], capture_output=True, text=True) + lsof = subprocess.run( + ["lsof", device_node], capture_output=True, text=True + ) if lsof.returncode == 0: - self.log_message(f"Processes using {device_node} before kill:\n{lsof.stdout}") + self.log_message( + f"Processes using {device_node} before kill:\n{lsof.stdout}" + ) except Exception as e: self.log_message(f"Could not run lsof: {e}") @@ -1348,7 +1478,9 @@ def cancel_process(self): self.log_message("Terminating flash worker", level="WARN") self.flash_worker.terminate() if not self.flash_worker.wait(3000): - self.log_message("Flash worker did not stop, forcing quit", level="WARN") + self.log_message( + "Flash worker did not stop, forcing quit", level="WARN" + ) self.flash_worker.quit() self.flash_worker.wait(2000) @@ -1359,7 +1491,11 @@ def cancel_process(self): except Exception as e: self.log_message(f"fuser fallback failed: {e}") - if hasattr(self, "verify_worker") and self.verify_worker and self.verify_worker.isRunning(): + if ( + hasattr(self, "verify_worker") + and self.verify_worker + and self.verify_worker.isRunning() + ): # terminate verify worker :D self.log_message("Terminating verify worker", level="WARN") self.verify_worker.terminate() @@ -1417,7 +1553,9 @@ def start_process(self): # validate sha256 hash format h = state.expected_hash.strip().lower() if len(h) != 64 or not all(c in "0123456789abcdef" for c in h): - self.log_message("Start aborted: invalid SHA256 hash format", level="WARN") + self.log_message( + "Start aborted: invalid SHA256 hash format", level="WARN" + ) QMessageBox.warning( self, self._T.get("msgbox_invalid_hash_title", "Invalid Hash"), @@ -1433,13 +1571,19 @@ def start_process(self): self.btn_cancel.setEnabled(True) self.progress_bar.setRange(0, 0) self.progress_bar.setValue(0) - self.progress_bar.setFormat(self._T.get("progress_verifying", "Verifying...")) + self.progress_bar.setFormat( + self._T.get("progress_verifying", "Verifying...") + ) self._flash_start_time = time.monotonic() - self._flash_total_bytes = os.path.getsize(state.iso_path) if Path(state.iso_path).exists() else 0 + self._flash_total_bytes = ( + os.path.getsize(state.iso_path) if Path(state.iso_path).exists() else 0 + ) # if you are reading this, fuck you self.verify_worker = VerifyWorker(state.iso_path, state.expected_hash) self.verify_worker.progress.connect(self.log_message) - self.verify_worker.int_progress.connect(self._on_progress, Qt.ConnectionType.QueuedConnection) + self.verify_worker.int_progress.connect( + self._on_progress, Qt.ConnectionType.QueuedConnection + ) self.verify_worker.flash_done.connect(self.on_verify_finished) self._speed_timer.start() self.verify_worker.start() @@ -1504,15 +1648,25 @@ def perform_flash(self): # already root start flash worker :D iso_path = options.get("iso_path", "") self._flash_start_time = time.monotonic() - self._flash_total_bytes = os.path.getsize(iso_path) if iso_path and Path(iso_path).exists() else 0 + self._flash_total_bytes = ( + os.path.getsize(iso_path) if iso_path and Path(iso_path).exists() else 0 + ) self.log_message( f"Starting flash thread: image_option={options['image_option']}, flash_mode={options['flash_mode']}, device={options['device']}" ) self.flash_worker = FlashWorker(options, self._T) - self.flash_worker.progress.connect(self._on_progress, Qt.ConnectionType.QueuedConnection) - self.flash_worker.status.connect(self._on_flash_status, Qt.ConnectionType.QueuedConnection) - self.flash_worker.flash_done.connect(self.on_flash_finished, Qt.ConnectionType.QueuedConnection) - self.flash_worker.request_tweaks.connect(self.show_tweak_dialog, Qt.ConnectionType.QueuedConnection) + self.flash_worker.progress.connect( + self._on_progress, Qt.ConnectionType.QueuedConnection + ) + self.flash_worker.status.connect( + self._on_flash_status, Qt.ConnectionType.QueuedConnection + ) + self.flash_worker.flash_done.connect( + self.on_flash_finished, Qt.ConnectionType.QueuedConnection + ) + self.flash_worker.request_tweaks.connect( + self.show_tweak_dialog, Qt.ConnectionType.QueuedConnection + ) self.flash_worker.start() self.btn_start.setEnabled(False) self.btn_cancel.setEnabled(True) @@ -1544,15 +1698,25 @@ def _start_flash_with_options(self, options: dict) -> None: # start flashworker directly with prebuilt options dict :3 iso_path = options.get("iso_path", "") self._flash_start_time = time.monotonic() - self._flash_total_bytes = os.path.getsize(iso_path) if iso_path and Path(iso_path).exists() else 0 + self._flash_total_bytes = ( + os.path.getsize(iso_path) if iso_path and Path(iso_path).exists() else 0 + ) self.log_message( f"Starting flash: image_option={options['image_option']}, flash_mode={options['flash_mode']}, device={options['device']}" ) self.flash_worker = FlashWorker(options, self._T) - self.flash_worker.progress.connect(self._on_progress, Qt.ConnectionType.QueuedConnection) - self.flash_worker.status.connect(self._on_flash_status, Qt.ConnectionType.QueuedConnection) - self.flash_worker.flash_done.connect(self.on_flash_finished, Qt.ConnectionType.QueuedConnection) - self.flash_worker.request_tweaks.connect(self.show_tweak_dialog, Qt.ConnectionType.QueuedConnection) + self.flash_worker.progress.connect( + self._on_progress, Qt.ConnectionType.QueuedConnection + ) + self.flash_worker.status.connect( + self._on_flash_status, Qt.ConnectionType.QueuedConnection + ) + self.flash_worker.flash_done.connect( + self.on_flash_finished, Qt.ConnectionType.QueuedConnection + ) + self.flash_worker.request_tweaks.connect( + self.show_tweak_dialog, Qt.ConnectionType.QueuedConnection + ) self.flash_worker.start() self.btn_start.setEnabled(False) self.btn_cancel.setEnabled(True) @@ -1596,7 +1760,9 @@ def on_flash_finished(self, success: bool): else: # flash failed :3 self.progress_bar.setFormat(self._T.get("progress_failed", "Failed")) - self.log_message("Flash operation finished with result: FAILED", level="ERROR") + self.log_message( + "Flash operation finished with result: FAILED", level="ERROR" + ) QMessageBox.critical( self, self._T.get("msgbox_error_title", "Error"), @@ -1633,7 +1799,9 @@ def _update_speed_eta(self, pct: int) -> None: # rolling 8-second window for stable speed estimation self._speed_samples.append((now, bytes_done)) cutoff = now - 8.0 - self._speed_samples = [(t, b) for t, b in self._speed_samples if t >= cutoff] + self._speed_samples = [ + (t, b) for t, b in self._speed_samples if t >= cutoff + ] if len(self._speed_samples) >= 2: dt = self._speed_samples[-1][0] - self._speed_samples[0][0] db = self._speed_samples[-1][1] - self._speed_samples[0][1] @@ -1648,7 +1816,9 @@ def _update_speed_eta(self, pct: int) -> None: else: speed_str = f"{speed:.0f} B/s" if eta_sec >= 3600: - eta_str = f"{int(eta_sec // 3600)}h {int((eta_sec % 3600) // 60)}m" + eta_str = ( + f"{int(eta_sec // 3600)}h {int((eta_sec % 3600) // 60)}m" + ) elif eta_sec >= 60: eta_str = f"{int(eta_sec // 60)}m {int(eta_sec % 60)}s" else: @@ -1664,52 +1834,93 @@ def _clear_speed_eta(self) -> None: self._lbl_speed_eta.setText("") def _apply_accessible_names(self) -> None: - self.combo_device.setAccessibleName(self._T.get("acc_device", "Device selector")) - self.combo_device.setAccessibleDescription(self._T.get("acc_device_desc", "Select the USB device to flash")) - self.btn_refresh.setAccessibleName(self._T.get("acc_refresh", "Refresh devices")) - self.btn_refresh.setAccessibleDescription(self._T.get("acc_refresh_desc", "Scan for connected USB devices")) - self.combo_boot.setAccessibleName(self._T.get("acc_boot", "Boot image selector")) + self.combo_device.setAccessibleName( + self._T.get("acc_device", "Device selector") + ) + self.combo_device.setAccessibleDescription( + self._T.get("acc_device_desc", "Select the USB device to flash") + ) + self.btn_refresh.setAccessibleName( + self._T.get("acc_refresh", "Refresh devices") + ) + self.btn_refresh.setAccessibleDescription( + self._T.get("acc_refresh_desc", "Scan for connected USB devices") + ) + self.combo_boot.setAccessibleName( + self._T.get("acc_boot", "Boot image selector") + ) self.combo_boot.setAccessibleDescription( self._T.get("acc_boot_desc", "Shows the currently selected boot image file") ) - self.btn_select.setAccessibleName(self._T.get("acc_select", "Browse for image file")) - self.combo_image_option.setAccessibleName(self._T.get("acc_image_option", "Image option selector")) + self.btn_select.setAccessibleName( + self._T.get("acc_select", "Browse for image file") + ) + self.combo_image_option.setAccessibleName( + self._T.get("acc_image_option", "Image option selector") + ) self.combo_image_option.setAccessibleDescription( self._T.get( "acc_image_option_desc", "Choose the type of image to write: Windows, Linux, Other, or Format Only", ) ) - self.input_label.setAccessibleName(self._T.get("acc_volume_label", "Volume label input")) + self.input_label.setAccessibleName( + self._T.get("acc_volume_label", "Volume label input") + ) self.input_label.setAccessibleDescription( self._T.get("acc_volume_label_desc", "Enter a name for the USB volume") ) - self.combo_fs.setAccessibleName(self._T.get("acc_filesystem", "File system selector")) - self.combo_cluster.setAccessibleName(self._T.get("acc_cluster", "Cluster size selector")) - self.combo_flash.setAccessibleName(self._T.get("acc_flash_option", "Flash method selector")) - self.chk_quick.setAccessibleName(self._T.get("acc_quick_format", "Quick format checkbox")) - self.chk_extended.setAccessibleName(self._T.get("acc_extended_label", "Create extended label checkbox")) - self.chk_badblocks.setAccessibleName(self._T.get("acc_bad_blocks", "Check for bad blocks checkbox")) - self.combo_badblocks.setAccessibleName(self._T.get("acc_bad_blocks_passes", "Bad block check passes selector")) - self.chk_verify.setAccessibleName(self._T.get("acc_verify_hash", "Verify SHA256 checksum checkbox")) - self.input_hash.setAccessibleName(self._T.get("acc_hash_input", "Expected SHA256 hash input")) + self.combo_fs.setAccessibleName( + self._T.get("acc_filesystem", "File system selector") + ) + self.combo_cluster.setAccessibleName( + self._T.get("acc_cluster", "Cluster size selector") + ) + self.combo_flash.setAccessibleName( + self._T.get("acc_flash_option", "Flash method selector") + ) + self.chk_quick.setAccessibleName( + self._T.get("acc_quick_format", "Quick format checkbox") + ) + self.chk_extended.setAccessibleName( + self._T.get("acc_extended_label", "Create extended label checkbox") + ) + self.chk_badblocks.setAccessibleName( + self._T.get("acc_bad_blocks", "Check for bad blocks checkbox") + ) + self.combo_badblocks.setAccessibleName( + self._T.get("acc_bad_blocks_passes", "Bad block check passes selector") + ) + self.chk_verify.setAccessibleName( + self._T.get("acc_verify_hash", "Verify SHA256 checksum checkbox") + ) + self.input_hash.setAccessibleName( + self._T.get("acc_hash_input", "Expected SHA256 hash input") + ) self.input_hash.setAccessibleDescription( self._T.get( "acc_hash_input_desc", "Paste the expected 64-character SHA256 hash here", ) ) - self.progress_bar.setAccessibleName(self._T.get("acc_progress", "Operation progress bar")) + self.progress_bar.setAccessibleName( + self._T.get("acc_progress", "Operation progress bar") + ) self.btn_start.setAccessibleName(self._T.get("acc_start", "Start operation")) self.btn_cancel.setAccessibleName(self._T.get("acc_cancel", "Cancel operation")) - self.btn_icon1.setAccessibleName(self._T.get("acc_website", "Open Lufus website")) + self.btn_icon1.setAccessibleName( + self._T.get("acc_website", "Open Lufus website") + ) self.btn_icon2.setAccessibleName(self._T.get("acc_about", "About Lufus")) self.btn_icon3.setAccessibleName(self._T.get("acc_settings", "Open settings")) self.btn_icon4.setAccessibleName(self._T.get("acc_log", "Open log window")) def keyPressEvent(self, event): # handle keyboard shortcuts :3 - if event.key() == Qt.Key.Key_R and event.modifiers() == Qt.KeyboardModifier.ControlModifier: + if ( + event.key() == Qt.Key.Key_R + and event.modifiers() == Qt.KeyboardModifier.ControlModifier + ): self.refresh_usb_devices() elif event.key() == Qt.Key.Key_F5: # f5 also refreshes device list :D @@ -1786,7 +1997,9 @@ def get_latest_release(self): newupdate = QMessageBox(self) newupdate.setWindowTitle("New Update Available!") newupdate.setText(f"A new version ({data.get('tag_name', '?')}) is available!") - newupdate.setInformativeText(f"Would you like to download {data.get('name', 'it')} now?") + newupdate.setInformativeText( + f"Would you like to download {data.get('name', 'it')} now?" + ) download_btn = newupdate.addButton(QMessageBox.StandardButton.Apply) download_btn.setText("Download Now") later_btn = newupdate.addButton(QMessageBox.StandardButton.Discard) @@ -1807,7 +2020,9 @@ def show_tweak_dialog(self): if __name__ == "__main__": # setup high dpi scaling :3 - QApplication.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough) + QApplication.setHighDpiScaleFactorRoundingPolicy( + Qt.HighDpiScaleFactorRoundingPolicy.PassThrough + ) app = QApplication(sys.argv) diff --git a/src/lufus/gui/scale.py b/src/lufus/gui/scale.py index 55ece95d..5337ba6a 100644 --- a/src/lufus/gui/scale.py +++ b/src/lufus/gui/scale.py @@ -1,4 +1,4 @@ -from PyQt6.QtWidgets import QApplication +from PySide6.QtWidgets import QApplication class Scale: diff --git a/src/lufus/gui/start_gui.py b/src/lufus/gui/start_gui.py index f6111d0b..0d2bdeb2 100644 --- a/src/lufus/gui/start_gui.py +++ b/src/lufus/gui/start_gui.py @@ -24,8 +24,8 @@ def _load_initial_theme(): def _show_root_warning() -> None: - from PyQt6.QtWidgets import QApplication, QMessageBox - from PyQt6.QtCore import QTimer + from PySide6.QtWidgets import QApplication, QMessageBox + from PySide6.QtCore import QTimer import sys app = QApplication(sys.argv) @@ -62,8 +62,8 @@ def launch_gui_with_usb_data() -> None: usb_devices = find_usb() log.info("Launching GUI with USB devices: %s", usb_devices) - from PyQt6.QtWidgets import QApplication - from PyQt6.QtCore import QTimer + from PySide6.QtWidgets import QApplication + from PySide6.QtCore import QTimer from lufus.gui.gui import LufusWindow app = QApplication(sys.argv) diff --git a/src/lufus/gui/themes/icon_utils.py b/src/lufus/gui/themes/icon_utils.py index 6cde6af8..c60d17cd 100644 --- a/src/lufus/gui/themes/icon_utils.py +++ b/src/lufus/gui/themes/icon_utils.py @@ -1,7 +1,7 @@ from pathlib import Path -from PyQt6.QtCore import Qt, QByteArray -from PyQt6.QtGui import QIcon, QPixmap, QPainter -from PyQt6.QtSvg import QSvgRenderer +from PySide6.QtCore import Qt, QByteArray +from PySide6.QtGui import QIcon, QPixmap, QPainter +from PySide6.QtSvg import QSvgRenderer def svg_icon(svg_path: Path | str, color: str, size: int = 24) -> QIcon: diff --git a/src/lufus/gui/workers.py b/src/lufus/gui/workers.py index 8b3158d7..2e5b4562 100644 --- a/src/lufus/gui/workers.py +++ b/src/lufus/gui/workers.py @@ -1,14 +1,14 @@ import sys from pathlib import Path -from PyQt6.QtCore import QThread, pyqtSignal +from PySide6.QtCore import QThread, Signal from lufus.writing.partition_scheme import PartitionScheme class VerifyWorker(QThread): # worker thread for sha256 verification >:D - progress = pyqtSignal(str) - int_progress = pyqtSignal(int) - flash_done = pyqtSignal(bool) + progress = Signal(str) + int_progress = Signal(int) + flash_done = Signal(bool) def __init__(self, iso_path: str, expected_hash: str): super().__init__() @@ -23,7 +23,9 @@ def run(self): p = Path(self.iso_path) if not p.is_file(): - self.progress.emit(f"Verification error: file not found: {self.iso_path}") + self.progress.emit( + f"Verification error: file not found: {self.iso_path}" + ) self.flash_done.emit(False) return file_size = p.stat().st_size @@ -35,11 +37,17 @@ def run(self): for chunk in iter(lambda: f.read(1024 * 1024), b""): sha256.update(chunk) bytes_read += len(chunk) - pct = min(int(bytes_read * 100 / file_size), 99) if file_size > 0 else 0 + pct = ( + min(int(bytes_read * 100 / file_size), 99) + if file_size > 0 + else 0 + ) self.int_progress.emit(pct) calculated = sha256.hexdigest() if calculated != normalized: - self.progress.emit(f"SHA256 mismatch: expected {normalized}, got {calculated}") + self.progress.emit( + f"SHA256 mismatch: expected {normalized}, got {calculated}" + ) self.flash_done.emit(calculated == normalized) except Exception as e: self.progress.emit(f"Verification error: {str(e)}") @@ -48,10 +56,10 @@ def run(self): class FlashWorker(QThread): # worker thread for usb flashing operation meow - progress = pyqtSignal(int) - status = pyqtSignal(str) - flash_done = pyqtSignal(bool) - request_tweaks = pyqtSignal() + progress = Signal(int) + status = Signal(str) + flash_done = Signal(bool) + request_tweaks = Signal() def __init__(self, options: dict, t: dict): super().__init__() @@ -82,32 +90,48 @@ def run(self): # unmount all partitions before flashing :D self.status.emit( - self._T.get("status_unmounting_all", "Unmounting all partitions on {device}...").format( - device=device_node - ) + self._T.get( + "status_unmounting_all", "Unmounting all partitions on {device}..." + ).format(device=device_node) ) partitions = glob.glob(f"{device_node}*") unmounted_parts = [] for part in partitions: if part != device_node: # don't unmount the device itself - self.status.emit(self._T.get("status_unmounting", "Unmounting {part}...").format(part=part)) + self.status.emit( + self._T.get("status_unmounting", "Unmounting {part}...").format( + part=part + ) + ) fo.unmount(part) unmounted_parts.append(part) # perform operation based on image option if image_option == 3: # Format Only - self.status.emit(self._T.get("status_format_starting", "Starting format operation...")) + self.status.emit( + self._T.get( + "status_format_starting", "Starting format operation..." + ) + ) self.progress.emit(10) - self.status.emit(self._T.get("status_format_in_progress", "Formatting drive...")) + self.status.emit( + self._T.get("status_format_in_progress", "Formatting drive...") + ) self.progress.emit(50) success = fo.disk_format(status_cb=self.status.emit) if success: self.progress.emit(80) for part in unmounted_parts: - self.status.emit(self._T.get("status_remounting", "Remounting {part}...").format(part=part)) + self.status.emit( + self._T.get( + "status_remounting", "Remounting {part}..." + ).format(part=part) + ) fo.remount(part) self.progress.emit(100) - self.status.emit(self._T.get("status_format_complete", "Format complete!")) + self.status.emit( + self._T.get("status_format_complete", "Format complete!") + ) else: self.status.emit( self._T.get( @@ -148,7 +172,11 @@ def run(self): self.flash_done.emit(bool(success)) except Exception as e: - self.status.emit(self._T.get("status_flash_error", "Flash error: {error}").format(error=e)) + self.status.emit( + self._T.get("status_flash_error", "Flash error: {error}").format( + error=e + ) + ) self.flash_done.emit(False) finally: # restore stdout :D From fd30af8b922813b6a61b7b7171b2dbdce14a1d83 Mon Sep 17 00:00:00 2001 From: Shaurya Singh Date: Sat, 9 May 2026 12:15:43 +0530 Subject: [PATCH 6/6] ruff format fix --- src/lufus/drives/autodetect_usb.py | 8 +- src/lufus/gui/dialogs.py | 20 +- src/lufus/gui/gui.py | 419 +++++++---------------------- src/lufus/gui/workers.py | 52 +--- 4 files changed, 121 insertions(+), 378 deletions(-) diff --git a/src/lufus/drives/autodetect_usb.py b/src/lufus/drives/autodetect_usb.py index a7beecf8..e559bd51 100644 --- a/src/lufus/drives/autodetect_usb.py +++ b/src/lufus/drives/autodetect_usb.py @@ -50,9 +50,7 @@ def _load_existing(self): serial, ) found += 1 - log.info( - "UsbMonitor: initial scan complete, %d USB block device(s) found", found - ) + log.info("UsbMonitor: initial scan complete, %d USB block device(s) found", found) def _on_socket_ready(self): while True: @@ -106,9 +104,7 @@ def _handle_event(self, device): self.device_removed.emit(node) changed = True else: - log.warning( - "UsbMonitor: remove event for unknown node %s, ignoring", node - ) + log.warning("UsbMonitor: remove event for unknown node %s, ignoring", node) if changed: self.device_list_updated.emit(self.devices) diff --git a/src/lufus/gui/dialogs.py b/src/lufus/gui/dialogs.py index 898f205c..412fa0c1 100644 --- a/src/lufus/gui/dialogs.py +++ b/src/lufus/gui/dialogs.py @@ -153,9 +153,7 @@ def __init__(self, parent=None): self.about_text.setReadOnly(True) self.about_text.setObjectName("aboutContent") self.about_text.setFrameShape(QFrame.Shape.NoFrame) - self.about_text.setStyleSheet( - f"font-family: {font_family}; font-size: {tool_pt}pt;" - ) + self.about_text.setStyleSheet(f"font-family: {font_family}; font-size: {tool_pt}pt;") layout.addWidget(self.about_text, 1) btn_row0 = QHBoxLayout() btn_discord = QPushButton(self._T.get("btn_discord", "Join Discord Server")) @@ -222,9 +220,7 @@ def __init__(self, parent=None): if current_lang in languages: self.combo_language.setCurrentText(current_lang) else: - self.combo_language.addItem( - self._T.get("settings_no_languages", "No languages found") - ) + self.combo_language.addItem(self._T.get("settings_no_languages", "No languages found")) self.combo_language.setEnabled(False) layout.addWidget(lbl_lang) layout.addWidget(self.combo_language) @@ -298,13 +294,9 @@ def __init__(self, parent=None): self.setWindowTitle("Windows Tweaks (MAY BREAK! USE CAUTION)") self.setFixedSize(600, 300) self.ask_label = QLabel("Do you want to customize your windows installation?") - self.hardware_checkbox = QCheckBox( - "Remove requirement for 4GB+ RAM, Secure Boot and TPM 2.0" - ) + self.hardware_checkbox = QCheckBox("Remove requirement for 4GB+ RAM, Secure Boot and TPM 2.0") self.hardware_checkbox.stateChanged.connect(self.update_winhardware) - self.microsoft_checkbox = QCheckBox( - "Remove requirement for an online Microsoft Account" - ) + self.microsoft_checkbox = QCheckBox("Remove requirement for an online Microsoft Account") self.microsoft_checkbox.stateChanged.connect(self.update_winmicrosoftacc) self.localacc_checkbox = QCheckBox("Create a local account with username:") self.localacc_checkbox.stateChanged.connect(self.update_winlocalaccchk) @@ -316,9 +308,7 @@ def __init__(self, parent=None): self.localacc_checkbox.toggled.connect(self.username_input.setEnabled) self.username_input.setEnabled(self.localacc_checkbox.isChecked()) self.username_input.textChanged.connect(self.sync_username) - self.data_checkbox = QCheckBox( - "Disable data collection (skip privacy questions)" - ) + self.data_checkbox = QCheckBox("Disable data collection (skip privacy questions)") self.data_checkbox.stateChanged.connect(self.update_winprivacy) self.applytweaks_btn = QPushButton("Apply") self.applytweaks_btn.clicked.connect(self.applywintweaks) diff --git a/src/lufus/gui/gui.py b/src/lufus/gui/gui.py index 754c5114..4f384e99 100644 --- a/src/lufus/gui/gui.py +++ b/src/lufus/gui/gui.py @@ -190,9 +190,7 @@ def __init__(self, usb_devices=None, scale: Scale = None): f"Python {sys.version.split()[0]} | {platform.system()} {platform.release()} {platform.machine()}" ) self.log_message(f"Running as user: {getpass.getuser()} (uid={os.getuid()})") - self.log_message( - f"Startup USB devices passed in: {list((usb_devices or {}).keys()) or 'none'}" - ) + self.log_message(f"Startup USB devices passed in: {list((usb_devices or {}).keys()) or 'none'}") self.flash_worker = None self.log_message(f"UI scale factor: {self._S.f():.3f} (base 96 DPI)") self._check_latest_download() @@ -204,9 +202,7 @@ def _check_latest_download(self): if state.iso_path: return try: - result = subprocess.run( - ["xdg-user-dir", "DOWNLOAD"], capture_output=True, text=True, timeout=2 - ) + result = subprocess.run(["xdg-user-dir", "DOWNLOAD"], capture_output=True, text=True, timeout=2) downloads = ( Path(result.stdout.strip()) if result.returncode == 0 and result.stdout.strip() @@ -217,9 +213,7 @@ def _check_latest_download(self): if not downloads.is_dir(): return try: - isos = sorted( - downloads.glob("*.iso"), key=lambda p: p.stat().st_mtime, reverse=True - ) + isos = sorted(downloads.glob("*.iso"), key=lambda p: p.stat().st_mtime, reverse=True) except Exception: return if not isos: @@ -234,9 +228,7 @@ def _check_latest_download(self): self.combo_boot.setItemText(0, clean_name) self.input_label.setText(clean_name.rsplit(".", 1)[0].upper()) self.log_message(f"Latest download auto-loaded: {latest}") - self.log_message( - f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)" - ) + self.log_message(f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)") self._detect_iso_and_update_ui(str(latest)) def _apply_styles(self) -> None: @@ -266,9 +258,7 @@ def _apply_styles(self) -> None: with open(theme_json_path, "r", encoding="utf-8") as fr: theme = json.load(fr) except FileNotFoundError: - print( - "WARNING: no theme applied, json didn't load up in _apply_styles, gui.py." - ) + print("WARNING: no theme applied, json didn't load up in _apply_styles, gui.py.") return # check if gradients are enabled :3 @@ -331,9 +321,7 @@ def _apply_styles(self) -> None: # scale dimensions :3 for key, value in theme["dimensions"].items(): - scaled_theme["dimensions"][key] = ( - value if key in NO_SCALE_KEYS else S.px(value) - ) + scaled_theme["dimensions"][key] = value if key in NO_SCALE_KEYS else S.px(value) # flatten theme dict for template substitution flat_theme: Dict[str, Any] = {} @@ -455,9 +443,7 @@ def create_header(self, text): line = QFrame() line.setFrameShape(QFrame.Shape.HLine) line.setFrameShadow(QFrame.Shadow.Sunken) - line.setStyleSheet( - "background-color: palette(mid); min-height: 1px; max-height: 1px;" - ) + line.setStyleSheet("background-color: palette(mid); min-height: 1px; max-height: 1px;") layout.addWidget(label) layout.addWidget(line, 1) return layout, label @@ -469,9 +455,7 @@ def update_usb_list(self, devices: dict): if not devices: # show no devices message - self.combo_device.addItem( - self._T.get("no_usb_found", "No USB devices found"), None - ) + self.combo_device.addItem(self._T.get("no_usb_found", "No USB devices found"), None) return # add each device to combo @@ -540,9 +524,7 @@ def init_ui(self): # boot selection with file browser :D self.lbl_boot = QLabel(self._T.get("lbl_boot_selection", "Boot Selection")) self.combo_boot = QComboBox() - self.combo_boot.addItem( - self._T.get("combo_boot_default", "installation_media.iso") - ) + self.combo_boot.addItem(self._T.get("combo_boot_default", "installation_media.iso")) self.btn_select = QPushButton(self._T.get("btn_select", "Select")) self.btn_select.clicked.connect(self.browse_file) @@ -565,9 +547,7 @@ def init_ui(self): self.combo_image_option.addItem(self._T.get("combo_image_windows", "Windows")) self.combo_image_option.addItem(self._T.get("combo_image_linux", "Linux")) self.combo_image_option.addItem(self._T.get("combo_image_other", "Other")) - self.combo_image_option.addItem( - self._T.get("combo_image_format", "Format Only") - ) + self.combo_image_option.addItem(self._T.get("combo_image_format", "Format Only")) # self.combo_image_option.addItem(self._T.get("combo_image_ventoy", "Ventoy")) self.combo_image_option.currentTextChanged.connect(self.update_image_option) @@ -605,18 +585,14 @@ def init_ui(self): main_layout.addSpacing(S.px(6)) # format options section :3 - _hdr_fmt, self.lbl_header_format = self.create_header( - self._T.get("header_format_options", "Format Options") - ) + _hdr_fmt, self.lbl_header_format = self.create_header(self._T.get("header_format_options", "Format Options")) main_layout.addLayout(_hdr_fmt) main_layout.addSpacing(S.px(4)) # volume label input field self.lbl_vol = QLabel(self._T.get("lbl_volume_label", "Volume Label")) self.input_label = QLineEdit() - self.input_label.setPlaceholderText( - self._T.get("lbl_volume_label", "Volume Label") - ) + self.input_label.setPlaceholderText(self._T.get("lbl_volume_label", "Volume Label")) self.input_label.textChanged.connect(self.update_new_label) vol_layout = QVBoxLayout() @@ -682,16 +658,12 @@ def init_ui(self): self.chk_quick.setChecked(True) self.chk_quick.stateChanged.connect(self.update_QF) - self.chk_extended = QCheckBox( - self._T.get("chk_extended_label", "Create Extended Label") - ) + self.chk_extended = QCheckBox(self._T.get("chk_extended_label", "Create Extended Label")) self.chk_extended.setChecked(True) self.chk_extended.stateChanged.connect(self.update_create_extended) # bad blocks check with pass selector :3 - self.chk_badblocks = QCheckBox( - self._T.get("chk_bad_blocks", "Check for Bad Blocks") - ) + self.chk_badblocks = QCheckBox(self._T.get("chk_bad_blocks", "Check for Bad Blocks")) self.combo_badblocks = QComboBox() self.combo_badblocks.addItem(self._T.get("combo_badblocks_1pass", "1 Pass")) self.combo_badblocks.addItem(self._T.get("combo_badblocks_2pass", "2 Pass")) @@ -702,18 +674,12 @@ def init_ui(self): self.update_check_bad() # sha256 verification checkbox and input :D - self.chk_verify = QCheckBox( - self._T.get("chk_verify_hash", "Verify SHA256 Checksum") - ) + self.chk_verify = QCheckBox(self._T.get("chk_verify_hash", "Verify SHA256 Checksum")) self.chk_verify.stateChanged.connect(self.update_verify_hash) - self.lbl_expected_hash = QLabel( - self._T.get("lbl_expected_hash", "Expected SHA256:") - ) + self.lbl_expected_hash = QLabel(self._T.get("lbl_expected_hash", "Expected SHA256:")) self.lbl_expected_hash.setVisible(False) self.input_hash = QLineEdit() - self.input_hash.setPlaceholderText( - self._T.get("input_hash_placeholder", "Enter expected SHA256 hash here...") - ) + self.input_hash.setPlaceholderText(self._T.get("input_hash_placeholder", "Enter expected SHA256 hash here...")) self.input_hash.setEnabled(False) self.input_hash.setMaximumHeight(0) self.input_hash.textChanged.connect(self.update_expected_hash) @@ -735,9 +701,7 @@ def init_ui(self): main_layout.addSpacing(S.px(6)) # status section with progress bar :D - _hdr_status, self.lbl_header_status = self.create_header( - self._T.get("header_status", "Status") - ) + _hdr_status, self.lbl_header_status = self.create_header(self._T.get("header_status", "Status")) main_layout.addLayout(_hdr_status) main_layout.addSpacing(S.px(4)) @@ -809,9 +773,7 @@ def init_ui(self): self._lbl_speed_eta = QLabel("") self._lbl_speed_eta.setObjectName("speedEtaLabel") self._lbl_speed_eta.setMinimumWidth(S.px(220)) - self._lbl_speed_eta.setAlignment( - Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter - ) + self._lbl_speed_eta.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) self.statusBar.addPermanentWidget(self._lbl_speed_eta) self.update_image_option() @@ -840,9 +802,7 @@ def _populate_device_combo(self): self.combo_device.addItem(display, node) else: # show no devices found message :3 - self.combo_device.addItem( - self._T.get("no_usb_found", "No USB devices found"), None - ) + self.combo_device.addItem(self._T.get("no_usb_found", "No USB devices found"), None) self.combo_device.blockSignals(False) @@ -852,17 +812,13 @@ def refresh_usb_devices(self): self.log_message("USB device scan initiated") try: new_devices = self.monitor.devices - self.log_message( - f"USB scan result: {len(new_devices)} device(s) found: {list(new_devices.keys())}" - ) + self.log_message(f"USB scan result: {len(new_devices)} device(s) found: {list(new_devices.keys())}") if new_devices: # update device list with new devices :3 self.usb_devices = new_devices self._populate_device_combo() - self.log_message( - f"Device list updated: {[f'{k} ({v})' for k, v in new_devices.items()]}" - ) + self.log_message(f"Device list updated: {[f'{k} ({v})' for k, v in new_devices.items()]}") QMessageBox.information( self, self._T.get("msgbox_usb_found_title", "USB Found"), @@ -880,9 +836,7 @@ def refresh_usb_devices(self): ) except Exception as e: # handle scan errors :3 - self.statusBar.showMessage( - self._T.get("status_scan_failed", "Scan Failed"), 3000 - ) + self.statusBar.showMessage(self._T.get("status_scan_failed", "Scan Failed"), 3000) self.log_message( f"USB scan raised exception: {type(e).__name__}: {str(e)}", level="ERROR", @@ -896,16 +850,12 @@ def refresh_usb_devices(self): def updateFS(self): # update filesystem selection in states :D state.filesystem_index = self.combo_fs.currentIndex() - self.log_message( - f"File system changed to: {self.combo_fs.currentText()} (index={state.filesystem_index})" - ) + self.log_message(f"File system changed to: {self.combo_fs.currentText()} (index={state.filesystem_index})") def updateflash(self): # update flash mode selection in states :3 state.flash_mode = self.combo_flash.currentIndex() - self.log_message( - f"Flash option changed to: {self.combo_flash.currentText()} (index={state.flash_mode})" - ) + self.log_message(f"Flash option changed to: {self.combo_flash.currentText()} (index={state.flash_mode})") def update_image_option(self): # update image option and refresh available filesystems and flash modes :D @@ -1005,16 +955,12 @@ def update_new_label(self, current_text): def update_cluster_size(self): # update cluster size selection :D state.cluster_size = self.combo_cluster.currentIndex() - self.log_message( - f"Cluster size changed to: {self.combo_cluster.currentText()} (index={state.cluster_size})" - ) + self.log_message(f"Cluster size changed to: {self.combo_cluster.currentText()} (index={state.cluster_size})") def update_QF(self): # update quick format setting :3 state.quick_format = 0 if self.chk_quick.isChecked() else 1 - self.log_message( - f"Quick format: {'enabled' if self.chk_quick.isChecked() else 'disabled'}" - ) + self.log_message(f"Quick format: {'enabled' if self.chk_quick.isChecked() else 'disabled'}") def update_create_extended(self): # update extended label creation setting :D @@ -1046,9 +992,7 @@ def update_check_bad(self): show = self.chk_badblocks.isChecked() self.combo_badblocks.setEnabled(show) self._animate_widget(self.combo_badblocks, show, "_anim_badblocks") - self.log_message( - f"Bad block check: {'enabled' if self.chk_badblocks.isChecked() else 'disabled'}" - ) + self.log_message(f"Bad block check: {'enabled' if self.chk_badblocks.isChecked() else 'disabled'}") def update_verify_hash(self): # update sha256 verification setting :D @@ -1057,9 +1001,7 @@ def update_verify_hash(self): if hasattr(self, "lbl_expected_hash"): self.lbl_expected_hash.setVisible(state.verify_hash) self._animate_widget(self.input_hash, state.verify_hash, "_anim_hash") - self.log_message( - f"SHA256 verification: {'enabled' if state.verify_hash else 'disabled'}" - ) + self.log_message(f"SHA256 verification: {'enabled' if state.verify_hash else 'disabled'}") def update_expected_hash(self, text): # store expected hash for verification :3 @@ -1070,9 +1012,7 @@ def _load_latest_download_iso(self): downloads_dir = Path.home() / "Downloads" if not downloads_dir.is_dir(): return - isos = sorted( - downloads_dir.glob("*.iso"), key=lambda p: p.stat().st_mtime, reverse=True - ) + isos = sorted(downloads_dir.glob("*.iso"), key=lambda p: p.stat().st_mtime, reverse=True) if not isos: return latest = isos[0] @@ -1082,9 +1022,7 @@ def _load_latest_download_iso(self): self.combo_boot.setItemText(0, clean_name) self.input_label.setText(latest.stem.upper()) self.log_message(f"Latest download ISO loaded: {latest}") - self.log_message( - f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)" - ) + self.log_message(f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)") def _check_clipboard(self): # monitor clipboard for iso file paths :D @@ -1093,11 +1031,7 @@ def _check_clipboard(self): if mime.hasUrls(): for url in mime.urls(): local_file = url.toLocalFile() - if ( - local_file - and local_file.lower().endswith(".iso") - and Path(local_file).is_file() - ): + if local_file and local_file.lower().endswith(".iso") and Path(local_file).is_file(): if local_file == self._last_clipboard: return self._last_clipboard = local_file @@ -1107,9 +1041,7 @@ def _check_clipboard(self): self.combo_boot.setItemText(0, clean_name) self.input_label.setText(clean_name.split(".")[0].upper()) self.log_message(f"Image loaded from clipboard: {local_file}") - self.log_message( - f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)" - ) + self.log_message(f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)") return text = clipboard.text().strip() if text == self._last_clipboard: @@ -1124,18 +1056,13 @@ def _check_clipboard(self): self.combo_boot.setItemText(0, clean_name) self.input_label.setText(clean_name.split(".")[0].upper()) self.log_message(f"Image loaded from clipboard: {path}") - self.log_message( - f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)" - ) + self.log_message(f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)") def dragEnterEvent(self, event): # accept drag of supported image files :D if event.mimeData().hasUrls(): supported = [".iso", ".dmg", ".img", ".bin", ".raw"] - if any( - url.toLocalFile().lower().endswith(tuple(supported)) - for url in event.mimeData().urls() - ): + if any(url.toLocalFile().lower().endswith(tuple(supported)) for url in event.mimeData().urls()): event.acceptProposedAction() return event.ignore() @@ -1144,10 +1071,7 @@ def dragMoveEvent(self, event): # accept drag move of supported image files :3 if event.mimeData().hasUrls(): supported = [".iso", ".dmg", ".img", ".bin", ".raw"] - if any( - url.toLocalFile().lower().endswith(tuple(supported)) - for url in event.mimeData().urls() - ): + if any(url.toLocalFile().lower().endswith(tuple(supported)) for url in event.mimeData().urls()): event.acceptProposedAction() return event.ignore() @@ -1156,9 +1080,7 @@ def dropEvent(self, event): # handle dropped image files :D supported = [".iso", ".dmg", ".img", ".bin", ".raw"] img_files = [ - url.toLocalFile() - for url in event.mimeData().urls() - if url.toLocalFile().lower().endswith(tuple(supported)) + url.toLocalFile() for url in event.mimeData().urls() if url.toLocalFile().lower().endswith(tuple(supported)) ] if img_files: # load first dropped image file :3 @@ -1169,9 +1091,7 @@ def dropEvent(self, event): self.combo_boot.setItemText(0, clean_name) self.input_label.setText(clean_name.split(".")[0].upper()) self.log_message(f"Image selected via drag-and-drop: {file_name}") - self.log_message( - f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)" - ) + self.log_message(f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)") self._detect_iso_and_update_ui(file_name) event.acceptProposedAction() else: @@ -1196,9 +1116,7 @@ def browse_file(self): self.combo_boot.setItemText(0, clean_name) self.input_label.setText(clean_name.split(".")[0].upper()) self.log_message(f"Image selected: {file_name}") - self.log_message( - f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)" - ) + self.log_message(f"Image size: {file_size:,} bytes ({file_size / (1024**3):.2f} GiB)") self._detect_iso_and_update_ui(file_name) def _detect_iso_and_update_ui(self, iso_path: str): @@ -1207,9 +1125,7 @@ def _detect_iso_and_update_ui(self, iso_path: str): # Non-ISO raw images (.img, .bin, .raw, .dmg) are always "Other / DD mode" if not iso_path.lower().endswith(".iso"): - self.log_message( - f"Non-ISO image ({Path(iso_path).suffix or 'no ext'}), defaulting to Other/DD mode" - ) + self.log_message(f"Non-ISO image ({Path(iso_path).suffix or 'no ext'}), defaulting to Other/DD mode") self.combo_image_option.setCurrentIndex(2) # Other return @@ -1239,14 +1155,8 @@ def show_log(self): level = lvl break _, colour = _LOG_LEVELS.get(level, ("info", None)) - escaped = ( - entry.replace("&", "&").replace("<", "<").replace(">", ">") - ) - html = ( - f'{escaped}' - if colour - else f"{escaped}" - ) + escaped = entry.replace("&", "&").replace("<", "<").replace(">", ">") + html = f'{escaped}' if colour else f"{escaped}" self.log_window.log_text.append(html) self.log_window.show() self.log_window.raise_() @@ -1264,14 +1174,8 @@ def log_message(self, msg, level="INFO"): getattr(self._logger, log_method_name)(msg) if self.log_window is not None: # update log window if open :D - escaped = ( - entry.replace("&", "&").replace("<", "<").replace(">", ">") - ) - html = ( - f'{escaped}' - if colour - else f"{escaped}" - ) + escaped = entry.replace("&", "&").replace("<", "<").replace(">", ">") + html = f'{escaped}' if colour else f"{escaped}" self.log_window.log_text.append(html) scrollbar = self.log_window.log_text.verticalScrollBar() scrollbar.setValue(scrollbar.maximum()) @@ -1311,9 +1215,7 @@ def apply_theme(self, theme_name): # set active theme by name and re-apply styles :D user_config_dir_path = Path(user_config_dir("Lufus")) builtin_json = THEME_DIR / theme_name / f"{theme_name}_theme.json" - user_json = ( - user_config_dir_path / "themes" / theme_name / f"{theme_name}_theme.json" - ) + user_json = user_config_dir_path / "themes" / theme_name / f"{theme_name}_theme.json" if builtin_json.exists() or user_json.exists(): state.theme = theme_name # persist so it survives restarts without needing the env var :3 @@ -1339,12 +1241,8 @@ def apply_language(self, language): def _update_ui_text(self): # update all text labels with new translations :3 self.setWindowTitle(self._T.get("window_title", "lufus")) - self.lbl_header_drive.setText( - self._T.get("header_drive_properties", "Drive Properties") - ) - self.lbl_header_format.setText( - self._T.get("header_format_options", "Format Options") - ) + self.lbl_header_drive.setText(self._T.get("header_drive_properties", "Drive Properties")) + self.lbl_header_format.setText(self._T.get("header_format_options", "Format Options")) self.lbl_header_status.setText(self._T.get("header_status", "Status")) self.lbl_device.setText(self._T.get("lbl_device", "Device")) self.lbl_boot.setText(self._T.get("lbl_boot_selection", "Boot Selection")) @@ -1357,20 +1255,14 @@ def _update_ui_text(self): self.lbl_flash.setText(self._T.get("lbl_flash_option", "Flash Option")) self.lbl_cluster.setText(self._T.get("lbl_cluster_size", "Cluster Size")) self.chk_quick.setText(self._T.get("chk_quick_format", "Quick Format")) - self.chk_extended.setText( - self._T.get("chk_extended_label", "Create Extended Label") - ) - self.chk_badblocks.setText( - self._T.get("chk_bad_blocks", "Check for Bad Blocks") - ) + self.chk_extended.setText(self._T.get("chk_extended_label", "Create Extended Label")) + self.chk_badblocks.setText(self._T.get("chk_bad_blocks", "Check for Bad Blocks")) self.btn_start.setText(self._T.get("btn_start", "Start")) self.btn_cancel.setText(self._T.get("btn_cancel", "Cancel")) self.statusBar.showMessage(self._T.get("status_ready", "Ready"), 0) # update toolbar button tooltips :3 - self.btn_refresh.setToolTip( - self._T.get("tooltip_refresh", "Refresh USB devices (Ctrl+R)") - ) + self.btn_refresh.setToolTip(self._T.get("tooltip_refresh", "Refresh USB devices (Ctrl+R)")) self.btn_icon1.setToolTip(self._T.get("tooltip_website", "Website")) self.btn_icon2.setToolTip(self._T.get("tooltip_about", "About")) self.btn_icon3.setToolTip(self._T.get("tooltip_settings", "Settings")) @@ -1383,9 +1275,7 @@ def _update_ui_text(self): self.combo_image_option.addItem(self._T.get("combo_image_windows", "Windows")) self.combo_image_option.addItem(self._T.get("combo_image_linux", "Linux")) self.combo_image_option.addItem(self._T.get("combo_image_other", "Other")) - self.combo_image_option.addItem( - self._T.get("combo_image_format", "Format Only") - ) + self.combo_image_option.addItem(self._T.get("combo_image_format", "Format Only")) # self.combo_image_option.addItem(self._T.get("combo_image_ventoy", "Ventoy")) self.combo_image_option.setCurrentIndex(current_img_idx) self.combo_image_option.blockSignals(False) @@ -1410,35 +1300,21 @@ def _update_ui_text(self): self.combo_badblocks.blockSignals(False) # update verification controls :D - self.chk_verify.setText( - self._T.get("chk_verify_hash", "Verify SHA256 Checksum") - ) - self.lbl_expected_hash.setText( - self._T.get("lbl_expected_hash", "Expected SHA256:") - ) - self.input_hash.setPlaceholderText( - self._T.get("input_hash_placeholder", "Enter expected SHA256 hash here...") - ) - self.input_label.setPlaceholderText( - self._T.get("lbl_volume_label", "Volume Label") - ) + self.chk_verify.setText(self._T.get("chk_verify_hash", "Verify SHA256 Checksum")) + self.lbl_expected_hash.setText(self._T.get("lbl_expected_hash", "Expected SHA256:")) + self.input_hash.setPlaceholderText(self._T.get("input_hash_placeholder", "Enter expected SHA256 hash here...")) + self.input_label.setPlaceholderText(self._T.get("lbl_volume_label", "Volume Label")) # update boot combo default text :3 - if self.combo_boot.itemText( - 0 - ) == "installation_media.iso" or self.combo_boot.itemText(0) == self._T.get( + if self.combo_boot.itemText(0) == "installation_media.iso" or self.combo_boot.itemText(0) == self._T.get( "combo_boot_default", "installation_media.iso" ): - self.combo_boot.setItemText( - 0, self._T.get("combo_boot_default", "installation_media.iso") - ) + self.combo_boot.setItemText(0, self._T.get("combo_boot_default", "installation_media.iso")) if not self.usb_devices: # update no devices message :D self.combo_device.clear() - self.combo_device.addItem( - self._T.get("no_usb_found", "No USB devices found"), None - ) + self.combo_device.addItem(self._T.get("no_usb_found", "No USB devices found"), None) self._update_flashing_options() self._apply_accessible_names() @@ -1457,19 +1333,13 @@ def cancel_process(self): ) if reply == QMessageBox.StandardButton.Yes: device_node = self.get_selected_mount_path() - self.log_message( - f"Cancellation requested for device {device_node}", level="WARN" - ) + self.log_message(f"Cancellation requested for device {device_node}", level="WARN") try: # check what processes are using device :3 - lsof = subprocess.run( - ["lsof", device_node], capture_output=True, text=True - ) + lsof = subprocess.run(["lsof", device_node], capture_output=True, text=True) if lsof.returncode == 0: - self.log_message( - f"Processes using {device_node} before kill:\n{lsof.stdout}" - ) + self.log_message(f"Processes using {device_node} before kill:\n{lsof.stdout}") except Exception as e: self.log_message(f"Could not run lsof: {e}") @@ -1478,9 +1348,7 @@ def cancel_process(self): self.log_message("Terminating flash worker", level="WARN") self.flash_worker.terminate() if not self.flash_worker.wait(3000): - self.log_message( - "Flash worker did not stop, forcing quit", level="WARN" - ) + self.log_message("Flash worker did not stop, forcing quit", level="WARN") self.flash_worker.quit() self.flash_worker.wait(2000) @@ -1491,11 +1359,7 @@ def cancel_process(self): except Exception as e: self.log_message(f"fuser fallback failed: {e}") - if ( - hasattr(self, "verify_worker") - and self.verify_worker - and self.verify_worker.isRunning() - ): + if hasattr(self, "verify_worker") and self.verify_worker and self.verify_worker.isRunning(): # terminate verify worker :D self.log_message("Terminating verify worker", level="WARN") self.verify_worker.terminate() @@ -1553,9 +1417,7 @@ def start_process(self): # validate sha256 hash format h = state.expected_hash.strip().lower() if len(h) != 64 or not all(c in "0123456789abcdef" for c in h): - self.log_message( - "Start aborted: invalid SHA256 hash format", level="WARN" - ) + self.log_message("Start aborted: invalid SHA256 hash format", level="WARN") QMessageBox.warning( self, self._T.get("msgbox_invalid_hash_title", "Invalid Hash"), @@ -1571,19 +1433,13 @@ def start_process(self): self.btn_cancel.setEnabled(True) self.progress_bar.setRange(0, 0) self.progress_bar.setValue(0) - self.progress_bar.setFormat( - self._T.get("progress_verifying", "Verifying...") - ) + self.progress_bar.setFormat(self._T.get("progress_verifying", "Verifying...")) self._flash_start_time = time.monotonic() - self._flash_total_bytes = ( - os.path.getsize(state.iso_path) if Path(state.iso_path).exists() else 0 - ) + self._flash_total_bytes = os.path.getsize(state.iso_path) if Path(state.iso_path).exists() else 0 # if you are reading this, fuck you self.verify_worker = VerifyWorker(state.iso_path, state.expected_hash) self.verify_worker.progress.connect(self.log_message) - self.verify_worker.int_progress.connect( - self._on_progress, Qt.ConnectionType.QueuedConnection - ) + self.verify_worker.int_progress.connect(self._on_progress, Qt.ConnectionType.QueuedConnection) self.verify_worker.flash_done.connect(self.on_verify_finished) self._speed_timer.start() self.verify_worker.start() @@ -1648,25 +1504,15 @@ def perform_flash(self): # already root start flash worker :D iso_path = options.get("iso_path", "") self._flash_start_time = time.monotonic() - self._flash_total_bytes = ( - os.path.getsize(iso_path) if iso_path and Path(iso_path).exists() else 0 - ) + self._flash_total_bytes = os.path.getsize(iso_path) if iso_path and Path(iso_path).exists() else 0 self.log_message( f"Starting flash thread: image_option={options['image_option']}, flash_mode={options['flash_mode']}, device={options['device']}" ) self.flash_worker = FlashWorker(options, self._T) - self.flash_worker.progress.connect( - self._on_progress, Qt.ConnectionType.QueuedConnection - ) - self.flash_worker.status.connect( - self._on_flash_status, Qt.ConnectionType.QueuedConnection - ) - self.flash_worker.flash_done.connect( - self.on_flash_finished, Qt.ConnectionType.QueuedConnection - ) - self.flash_worker.request_tweaks.connect( - self.show_tweak_dialog, Qt.ConnectionType.QueuedConnection - ) + self.flash_worker.progress.connect(self._on_progress, Qt.ConnectionType.QueuedConnection) + self.flash_worker.status.connect(self._on_flash_status, Qt.ConnectionType.QueuedConnection) + self.flash_worker.flash_done.connect(self.on_flash_finished, Qt.ConnectionType.QueuedConnection) + self.flash_worker.request_tweaks.connect(self.show_tweak_dialog, Qt.ConnectionType.QueuedConnection) self.flash_worker.start() self.btn_start.setEnabled(False) self.btn_cancel.setEnabled(True) @@ -1698,25 +1544,15 @@ def _start_flash_with_options(self, options: dict) -> None: # start flashworker directly with prebuilt options dict :3 iso_path = options.get("iso_path", "") self._flash_start_time = time.monotonic() - self._flash_total_bytes = ( - os.path.getsize(iso_path) if iso_path and Path(iso_path).exists() else 0 - ) + self._flash_total_bytes = os.path.getsize(iso_path) if iso_path and Path(iso_path).exists() else 0 self.log_message( f"Starting flash: image_option={options['image_option']}, flash_mode={options['flash_mode']}, device={options['device']}" ) self.flash_worker = FlashWorker(options, self._T) - self.flash_worker.progress.connect( - self._on_progress, Qt.ConnectionType.QueuedConnection - ) - self.flash_worker.status.connect( - self._on_flash_status, Qt.ConnectionType.QueuedConnection - ) - self.flash_worker.flash_done.connect( - self.on_flash_finished, Qt.ConnectionType.QueuedConnection - ) - self.flash_worker.request_tweaks.connect( - self.show_tweak_dialog, Qt.ConnectionType.QueuedConnection - ) + self.flash_worker.progress.connect(self._on_progress, Qt.ConnectionType.QueuedConnection) + self.flash_worker.status.connect(self._on_flash_status, Qt.ConnectionType.QueuedConnection) + self.flash_worker.flash_done.connect(self.on_flash_finished, Qt.ConnectionType.QueuedConnection) + self.flash_worker.request_tweaks.connect(self.show_tweak_dialog, Qt.ConnectionType.QueuedConnection) self.flash_worker.start() self.btn_start.setEnabled(False) self.btn_cancel.setEnabled(True) @@ -1760,9 +1596,7 @@ def on_flash_finished(self, success: bool): else: # flash failed :3 self.progress_bar.setFormat(self._T.get("progress_failed", "Failed")) - self.log_message( - "Flash operation finished with result: FAILED", level="ERROR" - ) + self.log_message("Flash operation finished with result: FAILED", level="ERROR") QMessageBox.critical( self, self._T.get("msgbox_error_title", "Error"), @@ -1799,9 +1633,7 @@ def _update_speed_eta(self, pct: int) -> None: # rolling 8-second window for stable speed estimation self._speed_samples.append((now, bytes_done)) cutoff = now - 8.0 - self._speed_samples = [ - (t, b) for t, b in self._speed_samples if t >= cutoff - ] + self._speed_samples = [(t, b) for t, b in self._speed_samples if t >= cutoff] if len(self._speed_samples) >= 2: dt = self._speed_samples[-1][0] - self._speed_samples[0][0] db = self._speed_samples[-1][1] - self._speed_samples[0][1] @@ -1816,9 +1648,7 @@ def _update_speed_eta(self, pct: int) -> None: else: speed_str = f"{speed:.0f} B/s" if eta_sec >= 3600: - eta_str = ( - f"{int(eta_sec // 3600)}h {int((eta_sec % 3600) // 60)}m" - ) + eta_str = f"{int(eta_sec // 3600)}h {int((eta_sec % 3600) // 60)}m" elif eta_sec >= 60: eta_str = f"{int(eta_sec // 60)}m {int(eta_sec % 60)}s" else: @@ -1834,93 +1664,52 @@ def _clear_speed_eta(self) -> None: self._lbl_speed_eta.setText("") def _apply_accessible_names(self) -> None: - self.combo_device.setAccessibleName( - self._T.get("acc_device", "Device selector") - ) - self.combo_device.setAccessibleDescription( - self._T.get("acc_device_desc", "Select the USB device to flash") - ) - self.btn_refresh.setAccessibleName( - self._T.get("acc_refresh", "Refresh devices") - ) - self.btn_refresh.setAccessibleDescription( - self._T.get("acc_refresh_desc", "Scan for connected USB devices") - ) - self.combo_boot.setAccessibleName( - self._T.get("acc_boot", "Boot image selector") - ) + self.combo_device.setAccessibleName(self._T.get("acc_device", "Device selector")) + self.combo_device.setAccessibleDescription(self._T.get("acc_device_desc", "Select the USB device to flash")) + self.btn_refresh.setAccessibleName(self._T.get("acc_refresh", "Refresh devices")) + self.btn_refresh.setAccessibleDescription(self._T.get("acc_refresh_desc", "Scan for connected USB devices")) + self.combo_boot.setAccessibleName(self._T.get("acc_boot", "Boot image selector")) self.combo_boot.setAccessibleDescription( self._T.get("acc_boot_desc", "Shows the currently selected boot image file") ) - self.btn_select.setAccessibleName( - self._T.get("acc_select", "Browse for image file") - ) - self.combo_image_option.setAccessibleName( - self._T.get("acc_image_option", "Image option selector") - ) + self.btn_select.setAccessibleName(self._T.get("acc_select", "Browse for image file")) + self.combo_image_option.setAccessibleName(self._T.get("acc_image_option", "Image option selector")) self.combo_image_option.setAccessibleDescription( self._T.get( "acc_image_option_desc", "Choose the type of image to write: Windows, Linux, Other, or Format Only", ) ) - self.input_label.setAccessibleName( - self._T.get("acc_volume_label", "Volume label input") - ) + self.input_label.setAccessibleName(self._T.get("acc_volume_label", "Volume label input")) self.input_label.setAccessibleDescription( self._T.get("acc_volume_label_desc", "Enter a name for the USB volume") ) - self.combo_fs.setAccessibleName( - self._T.get("acc_filesystem", "File system selector") - ) - self.combo_cluster.setAccessibleName( - self._T.get("acc_cluster", "Cluster size selector") - ) - self.combo_flash.setAccessibleName( - self._T.get("acc_flash_option", "Flash method selector") - ) - self.chk_quick.setAccessibleName( - self._T.get("acc_quick_format", "Quick format checkbox") - ) - self.chk_extended.setAccessibleName( - self._T.get("acc_extended_label", "Create extended label checkbox") - ) - self.chk_badblocks.setAccessibleName( - self._T.get("acc_bad_blocks", "Check for bad blocks checkbox") - ) - self.combo_badblocks.setAccessibleName( - self._T.get("acc_bad_blocks_passes", "Bad block check passes selector") - ) - self.chk_verify.setAccessibleName( - self._T.get("acc_verify_hash", "Verify SHA256 checksum checkbox") - ) - self.input_hash.setAccessibleName( - self._T.get("acc_hash_input", "Expected SHA256 hash input") - ) + self.combo_fs.setAccessibleName(self._T.get("acc_filesystem", "File system selector")) + self.combo_cluster.setAccessibleName(self._T.get("acc_cluster", "Cluster size selector")) + self.combo_flash.setAccessibleName(self._T.get("acc_flash_option", "Flash method selector")) + self.chk_quick.setAccessibleName(self._T.get("acc_quick_format", "Quick format checkbox")) + self.chk_extended.setAccessibleName(self._T.get("acc_extended_label", "Create extended label checkbox")) + self.chk_badblocks.setAccessibleName(self._T.get("acc_bad_blocks", "Check for bad blocks checkbox")) + self.combo_badblocks.setAccessibleName(self._T.get("acc_bad_blocks_passes", "Bad block check passes selector")) + self.chk_verify.setAccessibleName(self._T.get("acc_verify_hash", "Verify SHA256 checksum checkbox")) + self.input_hash.setAccessibleName(self._T.get("acc_hash_input", "Expected SHA256 hash input")) self.input_hash.setAccessibleDescription( self._T.get( "acc_hash_input_desc", "Paste the expected 64-character SHA256 hash here", ) ) - self.progress_bar.setAccessibleName( - self._T.get("acc_progress", "Operation progress bar") - ) + self.progress_bar.setAccessibleName(self._T.get("acc_progress", "Operation progress bar")) self.btn_start.setAccessibleName(self._T.get("acc_start", "Start operation")) self.btn_cancel.setAccessibleName(self._T.get("acc_cancel", "Cancel operation")) - self.btn_icon1.setAccessibleName( - self._T.get("acc_website", "Open Lufus website") - ) + self.btn_icon1.setAccessibleName(self._T.get("acc_website", "Open Lufus website")) self.btn_icon2.setAccessibleName(self._T.get("acc_about", "About Lufus")) self.btn_icon3.setAccessibleName(self._T.get("acc_settings", "Open settings")) self.btn_icon4.setAccessibleName(self._T.get("acc_log", "Open log window")) def keyPressEvent(self, event): # handle keyboard shortcuts :3 - if ( - event.key() == Qt.Key.Key_R - and event.modifiers() == Qt.KeyboardModifier.ControlModifier - ): + if event.key() == Qt.Key.Key_R and event.modifiers() == Qt.KeyboardModifier.ControlModifier: self.refresh_usb_devices() elif event.key() == Qt.Key.Key_F5: # f5 also refreshes device list :D @@ -1997,9 +1786,7 @@ def get_latest_release(self): newupdate = QMessageBox(self) newupdate.setWindowTitle("New Update Available!") newupdate.setText(f"A new version ({data.get('tag_name', '?')}) is available!") - newupdate.setInformativeText( - f"Would you like to download {data.get('name', 'it')} now?" - ) + newupdate.setInformativeText(f"Would you like to download {data.get('name', 'it')} now?") download_btn = newupdate.addButton(QMessageBox.StandardButton.Apply) download_btn.setText("Download Now") later_btn = newupdate.addButton(QMessageBox.StandardButton.Discard) @@ -2020,9 +1807,7 @@ def show_tweak_dialog(self): if __name__ == "__main__": # setup high dpi scaling :3 - QApplication.setHighDpiScaleFactorRoundingPolicy( - Qt.HighDpiScaleFactorRoundingPolicy.PassThrough - ) + QApplication.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough) app = QApplication(sys.argv) diff --git a/src/lufus/gui/workers.py b/src/lufus/gui/workers.py index 2e5b4562..09f21bda 100644 --- a/src/lufus/gui/workers.py +++ b/src/lufus/gui/workers.py @@ -23,9 +23,7 @@ def run(self): p = Path(self.iso_path) if not p.is_file(): - self.progress.emit( - f"Verification error: file not found: {self.iso_path}" - ) + self.progress.emit(f"Verification error: file not found: {self.iso_path}") self.flash_done.emit(False) return file_size = p.stat().st_size @@ -37,17 +35,11 @@ def run(self): for chunk in iter(lambda: f.read(1024 * 1024), b""): sha256.update(chunk) bytes_read += len(chunk) - pct = ( - min(int(bytes_read * 100 / file_size), 99) - if file_size > 0 - else 0 - ) + pct = min(int(bytes_read * 100 / file_size), 99) if file_size > 0 else 0 self.int_progress.emit(pct) calculated = sha256.hexdigest() if calculated != normalized: - self.progress.emit( - f"SHA256 mismatch: expected {normalized}, got {calculated}" - ) + self.progress.emit(f"SHA256 mismatch: expected {normalized}, got {calculated}") self.flash_done.emit(calculated == normalized) except Exception as e: self.progress.emit(f"Verification error: {str(e)}") @@ -90,48 +82,32 @@ def run(self): # unmount all partitions before flashing :D self.status.emit( - self._T.get( - "status_unmounting_all", "Unmounting all partitions on {device}..." - ).format(device=device_node) + self._T.get("status_unmounting_all", "Unmounting all partitions on {device}...").format( + device=device_node + ) ) partitions = glob.glob(f"{device_node}*") unmounted_parts = [] for part in partitions: if part != device_node: # don't unmount the device itself - self.status.emit( - self._T.get("status_unmounting", "Unmounting {part}...").format( - part=part - ) - ) + self.status.emit(self._T.get("status_unmounting", "Unmounting {part}...").format(part=part)) fo.unmount(part) unmounted_parts.append(part) # perform operation based on image option if image_option == 3: # Format Only - self.status.emit( - self._T.get( - "status_format_starting", "Starting format operation..." - ) - ) + self.status.emit(self._T.get("status_format_starting", "Starting format operation...")) self.progress.emit(10) - self.status.emit( - self._T.get("status_format_in_progress", "Formatting drive...") - ) + self.status.emit(self._T.get("status_format_in_progress", "Formatting drive...")) self.progress.emit(50) success = fo.disk_format(status_cb=self.status.emit) if success: self.progress.emit(80) for part in unmounted_parts: - self.status.emit( - self._T.get( - "status_remounting", "Remounting {part}..." - ).format(part=part) - ) + self.status.emit(self._T.get("status_remounting", "Remounting {part}...").format(part=part)) fo.remount(part) self.progress.emit(100) - self.status.emit( - self._T.get("status_format_complete", "Format complete!") - ) + self.status.emit(self._T.get("status_format_complete", "Format complete!")) else: self.status.emit( self._T.get( @@ -172,11 +148,7 @@ def run(self): self.flash_done.emit(bool(success)) except Exception as e: - self.status.emit( - self._T.get("status_flash_error", "Flash error: {error}").format( - error=e - ) - ) + self.status.emit(self._T.get("status_flash_error", "Flash error: {error}").format(error=e)) self.flash_done.emit(False) finally: # restore stdout :D