From 37a239cf38ffa31a85320608414fbdc98b506685 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 16 Dec 2019 08:17:28 +1000 Subject: [PATCH] add basic type checking for anki/ --- .gitignore | 1 + .travis.sh | 3 +++ .travis.yml | 3 ++- README.development | 3 ++- anki/exporting.py | 6 +++--- anki/hooks.py | 3 ++- anki/models.py | 3 ++- anki/sound.py | 11 ++++++----- mypy.ini | 23 +++++++++++++++++++++++ requirements.dev | 3 +++ requirements.txt | 1 + tools/typecheck.sh | 4 ++++ 12 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 mypy.ini create mode 100644 requirements.dev create mode 100755 tools/typecheck.sh diff --git a/.gitignore b/.gitignore index de80392d5..9522b1a49 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ aqt/forms locale tools/runanki.system anki/buildhash.py +.mypy_cache diff --git a/.travis.sh b/.travis.sh index 4770d7e57..305114e52 100755 --- a/.travis.sh +++ b/.travis.sh @@ -8,5 +8,8 @@ echo "building ui..." echo "running unit tests..." nosetests ./tests +echo "type checking..." +./tools/typecheck.sh + echo "linting..." ./tools/lint.sh diff --git a/.travis.yml b/.travis.yml index 62ad927c4..dc40af4cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ install: - sudo apt-get update - sudo apt-get install portaudio19-dev - pip install -r requirements.txt - - pip install nose pylint pyqt5 pyqtwebengine + - pip install -r requirements.dev + - pip install pyqt5 pyqtwebengine script: ./.travis.sh diff --git a/README.development b/README.development index e8e3cfe1d..e460453d8 100644 --- a/README.development +++ b/README.development @@ -13,13 +13,14 @@ provide support for problems you encounter when running from source. Anki requires: - Python 3.6+ - - Qt 5.9.x/5.11.x/5.12.x and a PyQT that supports it + - Qt 5.9.x or 5.11.x+, and a PyQT that supports it - mpv - lame It also requires a number of Python packages, which you can grab via pip: $ pip3 install -r requirements.txt +$ pip3 install -r requirements.dev If you're on a Linux distribution that packages a compatible Qt then you can use the distro's packages. Make sure you install the development tools (eg diff --git a/anki/exporting.py b/anki/exporting.py index faa4dd7ea..4b91859ca 100644 --- a/anki/exporting.py +++ b/anki/exporting.py @@ -3,7 +3,7 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import re, os, zipfile, shutil, unicodedata -import json +import json, typing from anki.lang import _ from anki.utils import ids2str, splitFields, namedtmp, stripHTML @@ -11,7 +11,7 @@ from anki.hooks import runHook from anki import Collection class Exporter: - includeHTML = None + includeHTML: typing.Union[bool, None] = None def __init__(self, col, did=None): self.col = col @@ -134,7 +134,7 @@ class AnkiExporter(Exporter): key = _("Anki 2.0 Deck") ext = ".anki2" - includeSched = False + includeSched: typing.Union[bool, None] = False includeMedia = True def __init__(self, col): diff --git a/anki/hooks.py b/anki/hooks.py index bbd9a25f0..c8d909e41 100644 --- a/anki/hooks.py +++ b/anki/hooks.py @@ -14,11 +14,12 @@ automatically but can be called with _old(). """ import decorator +from typing import Dict, List, Callable, Any # Hooks ############################################################################## -_hooks = {} +_hooks: Dict[str, List[Callable[..., Any]]] = {} def runHook(hook, *args): "Run all functions on hook." diff --git a/anki/models.py b/anki/models.py index 08d366f3d..3a729de89 100644 --- a/anki/models.py +++ b/anki/models.py @@ -3,6 +3,7 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import copy, re, json +from typing import Dict, Any from anki.utils import intTime, joinFields, splitFields, ids2str,\ checksum from anki.lang import _ @@ -43,7 +44,7 @@ defaultModel = { """ } -defaultField = { +defaultField: Dict[str, Any] = { 'name': "", 'ord': None, 'sticky': False, diff --git a/anki/sound.py b/anki/sound.py index aa3431b14..b6b82ab6d 100644 --- a/anki/sound.py +++ b/anki/sound.py @@ -5,6 +5,7 @@ import html import re, sys, threading, time, subprocess, os, atexit import random +from typing import List from anki.hooks import addHook, runHook from anki.utils import tmpdir, isWin, isMac, isLin from anki.lang import _ @@ -56,15 +57,15 @@ def _packagedCmd(cmd): processingSrc = "rec.wav" processingDst = "rec.mp3" -processingChain = [] -recFiles = [] +processingChain: List[List[str]] = [] +recFiles: List[str] = [] processingChain = [ ["lame", processingSrc, processingDst, "--noreplaygain", "--quiet"], ] # don't show box on windows -if isWin: +if sys.platform == "win32": si = subprocess.STARTUPINFO() try: si.dwFlags |= subprocess.STARTF_USESHOWWINDOW @@ -177,7 +178,7 @@ if isWin: cleanupOldMplayerProcesses() -mplayerQueue = [] +mplayerQueue: List[str] = [] mplayerManager = None mplayerReader = None mplayerEvt = threading.Event() @@ -409,7 +410,7 @@ class PyAudioRecorder(_Recorder): return processingSrc if not pyaudio: - PyAudioRecorder = None + PyAudioRecorder = None # type: ignore # Audio interface ########################################################################## diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 000000000..a7cebccdc --- /dev/null +++ b/mypy.ini @@ -0,0 +1,23 @@ +[mypy] +python_version = 3.6 + +[mypy-win32file] +ignore_missing_imports = True +[mypy-win32pipe] +ignore_missing_imports = True +[mypy-pywintypes] +ignore_missing_imports = True +[mypy-winerror] +ignore_missing_imports = True +[mypy-distro] +ignore_missing_imports = True +[mypy-pyaudio] +ignore_missing_imports = True +[mypy-win32api] +ignore_missing_imports = True +[mypy-xml.dom] +ignore_missing_imports = True +[mypy-psutil] +ignore_missing_imports = True +[mypy-bs4] +ignore_missing_imports = True diff --git a/requirements.dev b/requirements.dev new file mode 100644 index 000000000..3fd7e14a7 --- /dev/null +++ b/requirements.dev @@ -0,0 +1,3 @@ +nose +mypy==0.750 +pylint diff --git a/requirements.txt b/requirements.txt index 8d3fe3ef5..3dd8678ba 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ markdown jsonschema psutil; sys_platform == "win32" distro; sys_platform != "win32" and sys_platform != "darwin" +typing diff --git a/tools/typecheck.sh b/tools/typecheck.sh new file mode 100755 index 000000000..2f55a7a61 --- /dev/null +++ b/tools/typecheck.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +TOOLS="$(cd "`dirname "$0"`"; pwd)" +mypy $TOOLS/../anki