Windows path fixes (#129)

* Change uses of os.path to use Pathlib

* Add return types and type hints

* Add more docstrings

* Add missing import to api_server
This commit is contained in:
2026-01-18 00:18:43 -06:00
committed by GitHub
parent ee9f44e4c4
commit 74dce5cc3d
15 changed files with 536 additions and 262 deletions

View File

@@ -1,5 +1,5 @@
import os.path
import socket
from pathlib import Path
import psutil
from PyQt6.QtCore import QThread, pyqtSignal, Qt, pyqtSlot
@@ -12,8 +12,8 @@ from PyQt6.QtWidgets import (
from src.api.server_proxy import RenderServerProxy
from src.engines.engine_manager import EngineManager
from src.ui.engine_help_window import EngineHelpViewer
from src.utilities.zeroconf_server import ZeroconfServer
from src.utilities.misc_helper import COMMON_RESOLUTIONS, COMMON_FRAME_RATES
from src.utilities.zeroconf_server import ZeroconfServer
class NewRenderJobForm(QWidget):
@@ -305,13 +305,15 @@ class NewRenderJobForm(QWidget):
self.tabs.setCurrentIndex(0)
def update_job_count(self, changed_item=None):
checked = 0
total = self.cameras_list.count()
checked = 1
if self.cameras_group.enabled:
checked = 0
total = self.cameras_list.count()
for i in range(total):
item = self.cameras_list.item(i)
if item.checkState() == Qt.CheckState.Checked:
checked += 1
for i in range(total):
item = self.cameras_list.item(i)
if item.checkState() == Qt.CheckState.Checked:
checked += 1
message = f"Submit {checked} Jobs" if checked > 1 else "Submit Job"
self.submit_button.setText(message)
@@ -365,8 +367,7 @@ class NewRenderJobForm(QWidget):
self.process_label.setHidden(False)
self.toggle_engine_enablement(False)
output_name, _ = os.path.splitext(os.path.basename(self.scene_file_input.text()))
output_name = output_name.replace(' ', '_')
output_name = Path(self.scene_file_input.text()).stem.replace(' ', '_')
self.job_name_input.setText(output_name)
file_name = self.scene_file_input.text()
@@ -601,13 +602,13 @@ class SubmitWorker(QThread):
# presubmission tasks - use local installs
engine_class = EngineManager.engine_class_with_name(self.window.engine_type.currentText().lower())
latest_engine = EngineManager.get_latest_engine_instance(engine_class)
input_path = latest_engine.perform_presubmission_tasks(input_path)
input_path = Path(latest_engine.perform_presubmission_tasks(input_path))
# submit
err_msg = ""
result = self.window.server_proxy.post_job_to_server(file_path=input_path, job_data=job_json,
callback=create_callback)
if not (result and result.ok):
err_msg = f"Error posting job to server: {result.message}"
err_msg = f"Error posting job to server: {result.text}"
self.message_signal.emit(err_msg)

View File

@@ -7,6 +7,7 @@ import os
import sys
import threading
import time
from typing import List, Dict, Any, Optional
import PIL
import humanize
@@ -52,12 +53,12 @@ class MainWindow(QMainWindow):
super().__init__()
# Load the queue
self.job_list_view = None
self.server_info_ram = None
self.server_info_cpu = None
self.server_info_os = None
self.server_info_gpu = None
self.server_info_hostname = None
self.job_list_view: Optional[QTableWidget] = None
self.server_info_ram: Optional[str] = None
self.server_info_cpu: Optional[str] = None
self.server_info_os: Optional[str] = None
self.server_info_gpu: Optional[List[Dict[str, Any]]] = None
self.server_info_hostname: Optional[str] = None
self.engine_browser_window = None
self.server_info_group = None
self.current_hostname = None
@@ -113,7 +114,12 @@ class MainWindow(QMainWindow):
# Pick default job
self.job_picked()
def setup_ui(self, main_layout):
def setup_ui(self, main_layout: QVBoxLayout) -> None:
"""Setup the main user interface layout.
Args:
main_layout: The main layout container for the UI widgets.
"""
# Servers
server_list_group = QGroupBox("Available Servers")
@@ -193,6 +199,11 @@ class MainWindow(QMainWindow):
main_layout.addLayout(right_layout)
def closeEvent(self, event):
"""Handle window close event with job running confirmation.
Args:
event: The close event triggered by user.
"""
running_jobs = len(RenderQueue.running_jobs())
if running_jobs:
reply = QMessageBox.question(self, "Running Jobs",
@@ -205,9 +216,10 @@ class MainWindow(QMainWindow):
else:
event.ignore()
# -- Server Code -- #
# -- Server Code -- #
def refresh_job_list(self):
"""Refresh the job list display."""
self.job_list_view.clearContents()
self.bg_update_thread.needs_update = True
@@ -279,7 +291,7 @@ class MainWindow(QMainWindow):
self.server_info_gpu.setText(gpu_info)
def update_ui_data(self):
"""Update UI data with current server and job information."""
self.update_servers()
if not self.current_server_proxy:
@@ -315,7 +327,7 @@ class MainWindow(QMainWindow):
for col, item in enumerate(items):
self.job_list_view.setItem(row, col, item)
# -- Job Code -- #
# -- Job Code -- #
def job_picked(self):
def fetch_preview(job_id):
@@ -381,6 +393,11 @@ class MainWindow(QMainWindow):
self.topbar.actions_call['Open Files'].setVisible(False)
def selected_job_ids(self):
"""Get list of selected job IDs from the job list.
Returns:
List[str]: List of selected job ID strings.
"""
try:
selected_rows = self.job_list_view.selectionModel().selectedRows()
job_ids = []
@@ -392,10 +409,15 @@ class MainWindow(QMainWindow):
return []
# -- Image Code -- #
# -- Image Code -- #
def load_image_path(self, image_path):
# Load and set the image using QPixmap
"""Load and display an image from file path.
Args:
image_path: Path to the image file to load.
"""
# Load and set image using QPixmap
try:
pixmap = QPixmap(image_path)
if not pixmap:
@@ -504,7 +526,7 @@ class MainWindow(QMainWindow):
"New Job", f"{resources_directory}/AddProduct.png", self.new_job)
self.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.topbar)
# -- Toolbar Buttons -- #
# -- Toolbar Buttons -- #
def open_console_window(self) -> None:
"""
@@ -519,8 +541,9 @@ class MainWindow(QMainWindow):
self.engine_browser_window.show()
def job_logs(self) -> None:
"""
Event handler for the "Logs" button.
"""Open log viewer for selected job.
Opens a log viewer window showing the logs for the currently selected job.
"""
selected_job_ids = self.selected_job_ids()
if selected_job_ids:
@@ -529,8 +552,10 @@ class MainWindow(QMainWindow):
self.log_viewer_window.show()
def stop_job(self, event):
"""
Event handler for the Stop Job button
"""Stop selected render jobs with user confirmation.
Args:
event: The button click event.
"""
job_ids = self.selected_job_ids()
if not job_ids:
@@ -540,7 +565,7 @@ class MainWindow(QMainWindow):
job = next((job for job in self.current_server_proxy.get_all_jobs() if job.get('id') == job_ids[0]), None)
if job:
display_name = job.get('name', os.path.basename(job.get('input_path', '')))
message = f"Are you sure you want to stop the job:\n{display_name}?"
message = f"Are you sure you want to stop job: {display_name}?"
else:
return # Job not found, handle this case as needed
else:
@@ -556,8 +581,10 @@ class MainWindow(QMainWindow):
self.refresh_job_list()
def delete_job(self, event):
"""
Event handler for the Delete Job button
"""Delete selected render jobs with user confirmation.
Args:
event: The button click event.
"""
job_ids = self.selected_job_ids()
if not job_ids:
@@ -623,6 +650,11 @@ class BackgroundUpdater(QThread):
self.needs_update = True
def run(self):
"""Main background thread execution loop.
Continuously fetches server and job data, updating the main UI
every second or when updates are needed.
"""
try:
last_run = 0
while True:
@@ -630,9 +662,9 @@ class BackgroundUpdater(QThread):
if now - last_run >= 1.0 or self.needs_update:
self.window.found_servers = list(set(ZeroconfServer.found_hostnames() + self.window.added_hostnames))
self.window.found_servers = [x for x in self.window.found_servers if
ZeroconfServer.get_hostname_properties(x)['api_version'] == API_VERSION]
ZeroconfServer.get_hostname_properties(x)['api_version'] == API_VERSION]
if self.window.current_server_proxy:
self.window.job_data[self.window.current_server_proxy.hostname] =\
self.window.job_data[self.window.current_server_proxy.hostname] = \
self.window.current_server_proxy.get_all_jobs(ignore_token=False)
self.needs_update = False
self.updated_signal.emit()

View File

@@ -15,7 +15,7 @@ from PyQt6.QtWidgets import QApplication, QMainWindow, QListWidget, QListWidgetI
from src.api.server_proxy import RenderServerProxy
from src.engines.engine_manager import EngineManager
from src.utilities.config import Config
from src.utilities.misc_helper import launch_url, system_safe_path
from src.utilities.misc_helper import launch_url
from src.version import APP_AUTHOR, APP_NAME
settings = QSettings(APP_AUTHOR, APP_NAME)
@@ -59,9 +59,7 @@ class SettingsWindow(QMainWindow):
self.check_for_new_engines_button = None
if not EngineManager.engines_path: # fix issue where sometimes path was not set
EngineManager.engines_path = system_safe_path(
os.path.join(os.path.join(os.path.expanduser(Config.upload_folder),
'engines')))
EngineManager.engines_path = Path(Config.upload_folder).expanduser() / "engines"
self.installed_engines_table = None