add type hints (1st pass: non problematic cases)

This commit is contained in:
deeplow 2022-07-21 11:39:08 +01:00
parent 1f8e23f164
commit d579a47a84
No known key found for this signature in database
GPG key ID: 577982871529A52A
7 changed files with 92 additions and 69 deletions

View file

@ -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']}% "

View file

@ -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

View file

@ -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.
"""

View file

@ -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()

View file

@ -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_()

View file

@ -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(
"<strong>Dangerzone Requires Docker Desktop</strong><br><br><a href='https://www.docker.com/products/docker-desktop'>Download Docker Desktop</a>, 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

View file

@ -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: