Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions qtapputils/managers/capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,23 @@ class StandardStreamEmitter(QObject):
"""
sig_new_text = Signal(str)

def __init__(self, stream='stdout'):
super().__init__()
self._stream = sys.__stderr__ if stream == 'stderr' else sys.__stdout__

def write(self, text):
try:
sys.__stdout__.write(text)
self._stream.write(text)
except Exception:
pass
self.sig_new_text.emit(str(text))

def flush(self):
try:
self._stream.flush()
except Exception:
pass


class SysCaptureManager(QObject):
"""
Expand Down Expand Up @@ -76,10 +86,10 @@ def __init__(self, start_capture=False):
self.except_hook.sig_except_caught.connect(self._handle_except)

# Setup the standard stream emitter.
self.stdout_emitter = StandardStreamEmitter()
self.stdout_emitter = StandardStreamEmitter('stdout')
self.stdout_emitter.sig_new_text.connect(self.__handle_stdout)

self.stderr_emitter = StandardStreamEmitter()
self.stderr_emitter = StandardStreamEmitter('stderr')
self.stderr_emitter.sig_new_text.connect(self.handle_stderr)

if start_capture:
Expand Down
34 changes: 21 additions & 13 deletions qtapputils/widgets/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,24 @@
# Licensed under the terms of the GNU General Public License.
# -----------------------------------------------------------------------------
from __future__ import annotations
from typing import TYPE_CHECKING, Callable

# ---- Standard library imports
import os
import os.path as osp
import sys
import datetime
import tempfile
from pathlib import Path


# ---- Third party imports
from qtapputils.icons import get_standard_icon, get_standard_iconsize
from qtpy.QtCore import Qt
from qtpy.QtGui import QIcon
from qtpy.QtCore import Qt, QUrl
from qtpy.QtGui import QIcon, QDesktopServices
from qtpy.QtWidgets import (
QApplication, QDialog, QDialogButtonBox, QGridLayout, QLabel, QPushButton,
QTextEdit, QWidget)


# ---- Local imports
from hydrogeolab.config.main import TEMP_DIR


class ExceptDialog(QDialog):
"""
A dialog to report internal errors encountered by the application during
Expand All @@ -38,14 +33,24 @@ class ExceptDialog(QDialog):

def __init__(self, appname: str, appver: str, system_info: str = None,
icon: QIcon = None, issue_tracker: str = None,
issue_email: str = None, parent: QWidget = None):
issue_email: str = None, parent: QWidget = None,
temp_dir: str | Path = None):
super().__init__(parent)
self.setWindowTitle(f"{appname} Internal Error")
self.setWindowFlags(
self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
if icon is not None:
self.setWindowIcon(icon)

self.temp_dir = None
if temp_dir is not None:
temp_dir = Path(temp_dir)
if temp_dir.is_dir() and os.access(temp_dir, os.W_OK):
self.temp_dir = temp_dir
else:
print(f"Provided temp_dir {temp_dir} is not a valid or "
"writable directory. Falling back to system default.")

self.log_msg = None
self.detailed_log = None

Expand Down Expand Up @@ -176,11 +181,14 @@ def show_detailed_log(self):
chosen by the OS.
"""
name = '{}Log_{}.txt'.format(self.appname, self.log_datetime)
temp_path = tempfile.mkdtemp(dir=TEMP_DIR)
temp_filename = osp.join(temp_path, name)
with open(temp_filename, 'w') as txtfile:

temp_path = Path(tempfile.mkdtemp(dir=self.temp_dir))
temp_filename = temp_path / name
with open(temp_filename, 'w', encoding='utf-8') as txtfile:
txtfile.write(self.detailed_log)
os.startfile(temp_filename)

# Cross-platform file opening (Windows, macOS, Linux) via Qt
QDesktopServices.openUrl(QUrl.fromLocalFile(str(temp_filename)))

def copy(self):
"""
Expand Down
Loading