diff --git a/Makefile b/Makefile
index 42c59a4c9e..9d43af856b 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ SHELL := /bin/bash
.PHONY: mypy
mypy: ## Run static type checker
- @mypy securedrop_client
+ @mypy --ignore-missing-imports securedrop_client
.PHONY: clean
clean: ## Clean the workspace of generated resources
diff --git a/securedrop_client/__init__.py b/securedrop_client/__init__.py
index 578e3fc875..dc7b12a144 100644
--- a/securedrop_client/__init__.py
+++ b/securedrop_client/__init__.py
@@ -10,8 +10,11 @@
# Use the operating system's locale.
current_locale, encoding = locale.getdefaultlocale()
# Get the language code.
- language_code = current_locale[:2]
-except (TypeError, ValueError): # pragma: no cover
+ if current_locale is None:
+ language_code = 'en'
+ else:
+ language_code = current_locale[:2]
+except ValueError: # pragma: no cover
language_code = 'en' # pragma: no cover
# DEBUG/TRANSLATE: override the language code here (e.g. to Chinese).
# language_code = 'zh'
diff --git a/securedrop_client/app.py b/securedrop_client/app.py
index 6455c2a237..efb06cdc7f 100644
--- a/securedrop_client/app.py
+++ b/securedrop_client/app.py
@@ -68,7 +68,7 @@ def configure_logging(sdc_home: str) -> None:
# define log handlers such as for rotating log files
handler = TimedRotatingFileHandler(log_file, when='midnight',
- backupCount=5, delay=0,
+ backupCount=5, delay=False,
encoding=ENCODING)
handler.setFormatter(formatter)
handler.setLevel(logging.DEBUG)
diff --git a/securedrop_client/db.py b/securedrop_client/db.py
index 2e05557402..4d92fc395e 100644
--- a/securedrop_client/db.py
+++ b/securedrop_client/db.py
@@ -1,5 +1,7 @@
import os
+from typing import Any # noqa: F401
+
from sqlalchemy import Boolean, Column, create_engine, DateTime, ForeignKey, Integer, String, \
Text, MetaData, CheckConstraint, text, UniqueConstraint
from sqlalchemy.ext.declarative import declarative_base
@@ -16,7 +18,7 @@
metadata = MetaData(naming_convention=convention)
-Base = declarative_base(metadata=metadata)
+Base = declarative_base(metadata=metadata) # type: Any
def make_engine(home: str):
diff --git a/securedrop_client/gui/main.py b/securedrop_client/gui/main.py
index 8010361192..4e41a65d4c 100644
--- a/securedrop_client/gui/main.py
+++ b/securedrop_client/gui/main.py
@@ -20,7 +20,8 @@
along with this program. If not, see .
"""
import logging
-from typing import List
+from gettext import gettext as _
+from typing import Dict, List, Optional # noqa: F401
from PyQt5.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QVBoxLayout, QDesktopWidget, \
QApplication
@@ -28,6 +29,7 @@
from securedrop_client import __version__
from securedrop_client.db import Source
from securedrop_client.storage import source_exists
+from securedrop_client.logic import Controller # noqa: F401
from securedrop_client.gui.widgets import TopPane, LeftPane, MainView, LoginDialog, \
SourceConversationWrapper
from securedrop_client.resources import load_icon
@@ -57,7 +59,7 @@ def __init__(self, sdc_home: str):
self.sdc_home = sdc_home
# Cache a dict of source.uuid -> SourceConversationWrapper
# We do this to not create/destroy widgets constantly (because it causes UI "flicker")
- self.conversations = {}
+ self.conversations = {} # type: Dict
self.setWindowTitle(_("SecureDrop Controller {}").format(__version__))
self.setWindowIcon(load_icon(self.icon))
diff --git a/securedrop_client/gui/widgets.py b/securedrop_client/gui/widgets.py
index cd594e21b4..100414b51f 100644
--- a/securedrop_client/gui/widgets.py
+++ b/securedrop_client/gui/widgets.py
@@ -18,6 +18,7 @@
"""
import logging
import arrow
+from gettext import gettext as _
import html
import sys
from typing import List
@@ -727,15 +728,13 @@ def _construct_message(self, source: Source) -> str:
elif isinstance(submission, File):
files += 1
- message = (
- "Deleting the Source account for",
- "{} will also".format(source.journalist_designation,),
- "delete {} files, {} replies, and {} messages.".format(files, replies, messages),
- "
",
- "This Source will no longer be able to correspond",
- "through the log-in tied to this account.",
- )
- message = ' '.join(message)
+ message = ("Deleting the Source account for "
+ "{} will also "
+ "delete {} files, {} replies, and {} messages."
+ "
"
+ "This Source will no longer be able to correspond "
+ "through the log-in tied to this account.").format(
+ source.journalist_designation, files, replies, messages)
return message
diff --git a/securedrop_client/logic.py b/securedrop_client/logic.py
index 8c3a233acf..15a4764bd7 100644
--- a/securedrop_client/logic.py
+++ b/securedrop_client/logic.py
@@ -25,6 +25,7 @@
import uuid
from PyQt5.QtCore import QObject, QThread, pyqtSignal, QTimer, QProcess
+from typing import Dict, Tuple # noqa: F401
from securedrop_client import storage
from securedrop_client import db
@@ -143,9 +144,9 @@ def __init__(self, hostname, gui, session,
self.gui = gui
# Reference to the API for secure drop proxy.
- self.api = None
+ self.api = None # type: sdclientapi.API
# Contains active threads calling the API.
- self.api_threads = {}
+ self.api_threads = {} # type: Dict[str, Dict]
# Reference to the SqlAlchemy session.
self.session = session
@@ -719,7 +720,7 @@ def send_reply(self, source_uuid: str, msg_uuid: str, message: str) -> None:
logger.error('not logged in - not implemented!') # pragma: no cover
self.reply_failed.emit(msg_uuid) # pragma: no cover
- def _on_reply_complete(self, result, current_object: (str, str)) -> None:
+ def _on_reply_complete(self, result, current_object: Tuple[str, str]) -> None:
source_uuid, reply_uuid = current_object
source = self.session.query(db.Source).filter_by(uuid=source_uuid).one()
if isinstance(result, sdclientapi.Reply):
@@ -735,6 +736,6 @@ def _on_reply_complete(self, result, current_object: (str, str)) -> None:
else:
self.reply_failed.emit(reply_uuid)
- def _on_reply_timeout(self, current_object: (str, str)) -> None:
+ def _on_reply_timeout(self, current_object: Tuple[str, str]) -> None:
_, reply_uuid = current_object
self.reply_failed.emit(reply_uuid)