diff --git a/dangerzone/cli.py b/dangerzone/cli.py
index 4840740..c7b6320 100644
--- a/dangerzone/cli.py
+++ b/dangerzone/cli.py
@@ -2,6 +2,7 @@ import json
import logging
import os
import sys
+from typing import Optional
import click
from colorama import Fore, Style
@@ -11,7 +12,7 @@ from .container import convert
from .global_common import GlobalCommon
-def print_header(s):
+def print_header(s: str) -> None:
click.echo("")
click.echo(Style.BRIGHT + s)
@@ -20,7 +21,9 @@ def print_header(s):
@click.option("--output-filename", help="Default is filename ending with -safe.pdf")
@click.option("--ocr-lang", help="Language to OCR, defaults to none")
@click.argument("filename", required=True)
-def cli_main(output_filename, ocr_lang, filename):
+def cli_main(
+ output_filename: Optional[str], ocr_lang: Optional[str], filename: str
+) -> None:
setup_logging()
global_common = GlobalCommon()
common = Common()
@@ -92,7 +95,7 @@ def cli_main(output_filename, ocr_lang, filename):
# Convert the document
print_header("Converting document to safe PDF")
- def stdout_callback(line):
+ def stdout_callback(line: str) -> None:
try:
status = json.loads(line)
s = Style.BRIGHT + Fore.CYAN + f"{status['percentage']}% "
diff --git a/dangerzone/common.py b/dangerzone/common.py
index 8f376cf..8f48018 100644
--- a/dangerzone/common.py
+++ b/dangerzone/common.py
@@ -2,6 +2,7 @@ import os
import platform
import stat
import tempfile
+from typing import Optional
import appdirs
@@ -11,7 +12,7 @@ class Common(object):
The Common class is a singleton of shared functionality throughout an open dangerzone window
"""
- def __init__(self):
+ def __init__(self) -> None:
# Name of input and out files
- self.input_filename = None
- self.output_filename = None
+ self.input_filename: Optional[str] = None
+ self.output_filename: Optional[str] = None
diff --git a/dangerzone/global_common.py b/dangerzone/global_common.py
index 05f1dbf..35f4da9 100644
--- a/dangerzone/global_common.py
+++ b/dangerzone/global_common.py
@@ -8,6 +8,7 @@ import platform
import shutil
import subprocess
import sys
+from typing import Optional
import appdirs
import colorama
@@ -24,7 +25,7 @@ class GlobalCommon(object):
The GlobalCommon class is a singleton of shared functionality throughout the app
"""
- def __init__(self):
+ def __init__(self) -> None:
# Version
try:
with open(self.get_resource_path("version.txt")) as f:
@@ -210,7 +211,7 @@ class GlobalCommon(object):
# Load settings
self.settings = Settings(self)
- def display_banner(self):
+ def display_banner(self) -> None:
"""
Raw ASCII art example:
╭──────────────────────────╮
@@ -391,7 +392,7 @@ class GlobalCommon(object):
else:
return shutil.which("docker")
- def get_resource_path(self, filename):
+ def get_resource_path(self, filename: str) -> str:
if getattr(sys, "dangerzone_dev", False):
# Look for resources directory relative to python file
project_root = pathlib.Path(__file__).parent.parent
@@ -420,12 +421,12 @@ class GlobalCommon(object):
else:
return None
- def install_container(self):
+ def install_container(self) -> Optional[bool]:
"""
Make sure the podman container is installed. Linux only.
"""
if self.is_container_installed():
- return
+ return None
# Load the container into podman
log.info("Installing Dangerzone container image...")
@@ -454,7 +455,7 @@ class GlobalCommon(object):
log.info("Container image installed")
return True
- def is_container_installed(self):
+ def is_container_installed(self) -> bool:
"""
See if the podman container is installed. Linux only.
"""
diff --git a/dangerzone/gui/__init__.py b/dangerzone/gui/__init__.py
index c7be4f8..89241bd 100644
--- a/dangerzone/gui/__init__.py
+++ b/dangerzone/gui/__init__.py
@@ -4,6 +4,7 @@ import platform
import signal
import sys
import uuid
+from typing import Dict, NoReturn, Optional, TextIO
import click
from PySide2 import QtCore, QtWidgets
@@ -21,14 +22,14 @@ class ApplicationWrapper(QtCore.QObject):
new_window = QtCore.Signal()
application_activated = QtCore.Signal()
- def __init__(self):
+ def __init__(self) -> None:
super(ApplicationWrapper, self).__init__()
self.app = QtWidgets.QApplication()
self.app.setQuitOnLastWindowClosed(False)
self.original_event = self.app.event
- def monkeypatch_event(event):
+ def monkeypatch_event(event: QtCore.QEvent) -> bool:
# In macOS, handle the file open event
if event.type() == QtCore.QEvent.FileOpen:
# Skip file open events in dev mode
@@ -46,7 +47,7 @@ class ApplicationWrapper(QtCore.QObject):
@click.command()
@click.argument("filename", required=False)
-def gui_main(filename):
+def gui_main(filename: str) -> bool:
setup_logging()
if platform.system() == "Darwin":
@@ -61,16 +62,16 @@ def gui_main(filename):
from strip_ansi import strip_ansi
class StdoutFilter:
- def __init__(self, stream):
+ def __init__(self, stream: TextIO) -> None:
self.stream = stream
- def __getattr__(self, attr_name):
+ def __getattr__(self, attr_name): # type: ignore [no-untyped-def]
return getattr(self.stream, attr_name)
- def write(self, data):
+ def write(self, data: str) -> None:
self.stream.write(strip_ansi(data))
- def flush(self):
+ def flush(self) -> None:
self.stream.flush()
sys.stdout = StdoutFilter(sys.stdout)
@@ -90,15 +91,15 @@ def gui_main(filename):
# Create the system tray
systray = SysTray(global_common, gui_common, app, app_wrapper)
- closed_windows = {}
- windows = {}
+ closed_windows: Dict[str, MainWindow] = {}
+ windows: Dict[str, MainWindow] = {}
- def delete_window(window_id):
+ def delete_window(window_id: str) -> None:
closed_windows[window_id] = windows[window_id]
del windows[window_id]
# Open a document in a window
- def select_document(filename=None):
+ def select_document(filename: Optional[str] = None) -> bool:
if (
len(windows) == 1
and windows[list(windows.keys())[0]].common.input_filename == None
@@ -112,16 +113,16 @@ def gui_main(filename):
if filename:
# Validate filename
- filename = os.path.abspath(os.path.expanduser(filename))
+ file_path: str = os.path.abspath(os.path.expanduser(filename))
try:
- open(filename, "rb")
+ open(file_path, "rb")
except FileNotFoundError:
click.echo("File not found")
return False
except PermissionError:
click.echo("Permission denied")
return False
- window.common.input_filename = filename
+ window.common.input_filename = file_path
window.content_widget.doc_selection_widget.document_selected.emit()
return True
@@ -135,7 +136,7 @@ def gui_main(filename):
return True
# Open a new window, if all windows are closed
- def application_activated():
+ def application_activated() -> None:
if len(windows) == 0:
select_document()
diff --git a/dangerzone/gui/common.py b/dangerzone/gui/common.py
index 97df9a7..358f939 100644
--- a/dangerzone/gui/common.py
+++ b/dangerzone/gui/common.py
@@ -16,6 +16,7 @@ elif platform.system() == "Linux":
import getpass
from xdg.DesktopEntry import DesktopEntry
+from ..global_common import GlobalCommon
from ..settings import Settings
log = logging.getLogger(__name__)
@@ -26,7 +27,7 @@ class GuiCommon(object):
The GuiCommon class is a singleton of shared functionality for the GUI
"""
- def __init__(self, app, global_common):
+ def __init__(self, app, global_common: GlobalCommon) -> None:
# Qt app
self.app = app
@@ -42,14 +43,14 @@ class GuiCommon(object):
# Are we done waiting (for Docker Desktop to be installed, or for container to install)
self.is_waiting_finished = False
- def get_window_icon(self):
+ def get_window_icon(self) -> QtGui.QIcon:
if platform.system() == "Windows":
path = self.global_common.get_resource_path("dangerzone.ico")
else:
path = self.global_common.get_resource_path("icon.png")
return QtGui.QIcon(path)
- def open_pdf_viewer(self, filename):
+ def open_pdf_viewer(self, filename: str) -> None:
if platform.system() == "Darwin":
# Open in Preview
args = ["open", "-a", "Preview.app", filename]
@@ -79,8 +80,8 @@ class GuiCommon(object):
log.info(Fore.YELLOW + "> " + Fore.CYAN + args_str)
subprocess.Popen(args)
- def _find_pdf_viewers(self):
- pdf_viewers = {}
+ def _find_pdf_viewers(self) -> dict[str, str]:
+ pdf_viewers: dict[str, str] = {}
if platform.system() == "Linux":
# Find all .desktop files
for search_path in [
@@ -111,8 +112,13 @@ class GuiCommon(object):
class Alert(QtWidgets.QDialog):
def __init__(
- self, gui_common, global_common, message, ok_text="Ok", extra_button_text=None
- ):
+ self,
+ gui_common: GuiCommon,
+ global_common: GlobalCommon,
+ message: str,
+ ok_text: str = "Ok",
+ extra_button_text: str = None,
+ ) -> None:
super(Alert, self).__init__()
self.global_common = global_common
self.gui_common = gui_common
@@ -167,14 +173,14 @@ class Alert(QtWidgets.QDialog):
layout.addLayout(buttons_layout)
self.setLayout(layout)
- def clicked_ok(self):
+ def clicked_ok(self) -> None:
self.done(QtWidgets.QDialog.Accepted)
- def clicked_extra(self):
+ def clicked_extra(self) -> None:
self.done(2)
- def clicked_cancel(self):
+ def clicked_cancel(self) -> None:
self.done(QtWidgets.QDialog.Rejected)
- def launch(self):
+ def launch(self) -> int:
return self.exec_()
diff --git a/dangerzone/gui/main_window.py b/dangerzone/gui/main_window.py
index 1b0de69..f15e901 100644
--- a/dangerzone/gui/main_window.py
+++ b/dangerzone/gui/main_window.py
@@ -5,12 +5,15 @@ import platform
import shutil
import subprocess
import tempfile
+from typing import Optional
from colorama import Fore, Style
from PySide2 import QtCore, QtGui, QtWidgets
from ..common import Common
from ..container import convert
+from ..global_common import GlobalCommon
+from .common import GuiCommon
log = logging.getLogger(__name__)
@@ -18,7 +21,9 @@ log = logging.getLogger(__name__)
class MainWindow(QtWidgets.QMainWindow):
delete_window = QtCore.Signal(str)
- def __init__(self, global_common, gui_common, window_id):
+ def __init__(
+ self, global_common: GlobalCommon, gui_common: GuiCommon, window_id: str
+ ) -> None:
super(MainWindow, self).__init__()
self.global_common = global_common
self.gui_common = gui_common
@@ -78,12 +83,12 @@ class MainWindow(QtWidgets.QMainWindow):
self.show()
- def waiting_finished(self):
+ def waiting_finished(self) -> None:
self.gui_common.is_waiting_finished = True
self.waiting_widget.hide()
self.content_widget.show()
- def closeEvent(self, e):
+ def closeEvent(self, e: QtGui.QCloseEvent) -> None:
e.accept()
self.delete_window.emit(self.window_id)
@@ -94,11 +99,11 @@ class MainWindow(QtWidgets.QMainWindow):
class InstallContainerThread(QtCore.QThread):
finished = QtCore.Signal()
- def __init__(self, global_common):
+ def __init__(self, global_common: GlobalCommon) -> None:
super(InstallContainerThread, self).__init__()
self.global_common = global_common
- def run(self):
+ def run(self) -> None:
self.global_common.install_container()
self.finished.emit()
@@ -115,7 +120,7 @@ class WaitingWidget(QtWidgets.QWidget):
# - "install_container"
finished = QtCore.Signal()
- def __init__(self, global_common, gui_common):
+ def __init__(self, global_common: GlobalCommon, gui_common: GuiCommon) -> None:
super(WaitingWidget, self).__init__()
self.global_common = global_common
self.gui_common = gui_common
@@ -148,8 +153,8 @@ class WaitingWidget(QtWidgets.QWidget):
# Check the state
self.check_state()
- def check_state(self):
- state = None
+ def check_state(self) -> None:
+ state: Optional[str] = None
# Can we find the container runtime binary binary
if platform.system() == "Linux":
@@ -180,7 +185,7 @@ class WaitingWidget(QtWidgets.QWidget):
# Update the state
self.state_change(state)
- def state_change(self, state):
+ def state_change(self, state: str) -> None:
if state == "not_installed":
self.label.setText(
"Dangerzone Requires Docker Desktop
Download Docker Desktop, install it, and open it."
@@ -204,7 +209,9 @@ class WaitingWidget(QtWidgets.QWidget):
class ContentWidget(QtWidgets.QWidget):
close_window = QtCore.Signal()
- def __init__(self, global_common, gui_common, common):
+ def __init__(
+ self, global_common: GlobalCommon, gui_common: GuiCommon, common: Common
+ ) -> None:
super(ContentWidget, self).__init__()
self.global_common = global_common
@@ -244,22 +251,22 @@ class ContentWidget(QtWidgets.QWidget):
layout.addWidget(self.convert_widget, stretch=1)
self.setLayout(layout)
- def document_selected(self):
+ def document_selected(self) -> None:
self.doc_selection_widget.hide()
self.settings_widget.show()
- def start_clicked(self):
+ def start_clicked(self) -> None:
self.settings_widget.hide()
self.convert_widget.show()
- def _close_window(self):
+ def _close_window(self) -> None:
self.close_window.emit()
class DocSelectionWidget(QtWidgets.QWidget):
document_selected = QtCore.Signal()
- def __init__(self, common):
+ def __init__(self, common: Common) -> None:
super(DocSelectionWidget, self).__init__()
self.common = common
@@ -286,7 +293,7 @@ class DocSelectionWidget(QtWidgets.QWidget):
layout.addStretch()
self.setLayout(layout)
- def dangerous_doc_button_clicked(self):
+ def dangerous_doc_button_clicked(self) -> None:
filename = QtWidgets.QFileDialog.getOpenFileName(
self,
"Open document",
@@ -302,7 +309,9 @@ class SettingsWidget(QtWidgets.QWidget):
start_clicked = QtCore.Signal()
close_window = QtCore.Signal()
- def __init__(self, global_common, gui_common, common):
+ def __init__(
+ self, global_common: GlobalCommon, gui_common: GuiCommon, common: Common
+ ) -> None:
super(SettingsWidget, self).__init__()
self.global_common = global_common
self.gui_common = gui_common
@@ -424,7 +433,7 @@ class SettingsWidget(QtWidgets.QWidget):
if index != -1:
self.open_combobox.setCurrentIndex(index)
- def update_ui(self):
+ def update_ui(self) -> None:
if platform.system() == "Windows":
# Because the save checkbox is always checked in Windows, the
# start button can be enabled
@@ -439,7 +448,7 @@ class SettingsWidget(QtWidgets.QWidget):
else:
self.start_button.setEnabled(False)
- def document_selected(self):
+ def document_selected(self) -> None:
# Update the danger doc label
self.dangerous_doc_label.setText(
f"Suspicious: {os.path.basename(self.common.input_filename)}"
@@ -450,7 +459,7 @@ class SettingsWidget(QtWidgets.QWidget):
self.common.output_filename = output_filename
self.save_lineedit.setText(os.path.basename(output_filename))
- def save_browse_button_clicked(self):
+ def save_browse_button_clicked(self) -> None:
filename = QtWidgets.QFileDialog.getSaveFileName(
self,
"Save safe PDF as...",
@@ -461,7 +470,7 @@ class SettingsWidget(QtWidgets.QWidget):
self.common.output_filename = filename[0]
self.save_lineedit.setText(os.path.basename(self.common.output_filename))
- def start_button_clicked(self):
+ def start_button_clicked(self) -> None:
if self.common.output_filename is None:
# If not saving, then save it to a temp file instead
tmp = tempfile.mkstemp(suffix=".pdf", prefix="dangerzone_")
@@ -493,13 +502,13 @@ class ConvertThread(QtCore.QThread):
finished = QtCore.Signal(bool)
update = QtCore.Signal(bool, str, int)
- def __init__(self, global_common, common):
+ def __init__(self, global_common: GlobalCommon, common: Common) -> None:
super(ConvertThread, self).__init__()
self.global_common = global_common
self.common = common
self.error = False
- def run(self):
+ def run(self) -> None:
if self.global_common.settings.get("ocr"):
ocr_lang = self.global_common.ocr_languages[
self.global_common.settings.get("ocr_language")
@@ -515,7 +524,7 @@ class ConvertThread(QtCore.QThread):
):
self.finished.emit(self.error)
- def stdout_callback(self, line):
+ def stdout_callback(self, line: str) -> None:
try:
status = json.loads(line)
except:
@@ -541,7 +550,9 @@ class ConvertThread(QtCore.QThread):
class ConvertWidget(QtWidgets.QWidget):
close_window = QtCore.Signal()
- def __init__(self, global_common, gui_common, common):
+ def __init__(
+ self, global_common: GlobalCommon, gui_common: GuiCommon, common: Common
+ ) -> None:
super(ConvertWidget, self).__init__()
self.global_common = global_common
self.gui_common = gui_common
@@ -588,19 +599,19 @@ class ConvertWidget(QtWidgets.QWidget):
layout.addStretch()
self.setLayout(layout)
- def document_selected(self):
+ def document_selected(self) -> None:
# Update the danger doc label
self.dangerous_doc_label.setText(
f"Suspicious: {os.path.basename(self.common.input_filename)}"
)
- def start(self):
+ def start(self) -> None:
self.convert_t = ConvertThread(self.global_common, self.common)
self.convert_t.update.connect(self.update)
self.convert_t.finished.connect(self.all_done)
self.convert_t.start()
- def update(self, error, text, percentage):
+ def update(self, error, text, percentage) -> None:
if error:
self.error = True
self.error_image.show()
@@ -609,7 +620,7 @@ class ConvertWidget(QtWidgets.QWidget):
self.label.setText(text)
self.progress.setValue(percentage)
- def all_done(self):
+ def all_done(self) -> None:
if self.error:
return
diff --git a/dangerzone/settings.py b/dangerzone/settings.py
index 9c125f1..1aab4cc 100644
--- a/dangerzone/settings.py
+++ b/dangerzone/settings.py
@@ -19,13 +19,13 @@ class Settings:
self.load()
- def get(self, key):
+ def get(self, key: str):
return self.settings[key]
- def set(self, key, val):
+ def set(self, key: str, val) -> None:
self.settings[key] = val
- def load(self):
+ def load(self) -> None:
if os.path.isfile(self.settings_filename):
# If the settings file exists, load it
try: