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)