diff --git a/.gitignore b/.gitignore index 3692c4311..f9c93920c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ __pycache__ anki.prof target user.bazelrc +.dmypy.json diff --git a/docs/development.md b/docs/development.md index f70ad95ff..653ba48d6 100644 --- a/docs/development.md +++ b/docs/development.md @@ -117,6 +117,13 @@ To run a single Python library test, eg test_bury: PYTEST=test_bury bazel run //pylib:pytest ``` +On Mac/Linux, after installing 'fswatch', you can run mypy on +each file save automatically with: + +``` +./scripts/mypy-watch +``` + ## Fixing formatting If the format tests fail, most can be fixed by running `format` diff --git a/pip/BUILD.bazel b/pip/BUILD.bazel index 88b688004..f4e59faf3 100644 --- a/pip/BUILD.bazel +++ b/pip/BUILD.bazel @@ -8,6 +8,11 @@ pip_binary(name = "isort") pip_binary(name = "mypy") +pip_binary( + name = "dmypy", + pkg = "mypy", +) + pip_binary(name = "pylint") pip_binary( diff --git a/pip/binary.bzl b/pip/binary.bzl index c2ada5ca3..e8d8aedcb 100644 --- a/pip/binary.bzl +++ b/pip/binary.bzl @@ -25,4 +25,5 @@ def pip_binary(name, pkg = None): deps = [ requirement(pkg), ], + visibility = ["//visibility:public"], ) diff --git a/qt/BUILD.bazel b/qt/BUILD.bazel index c48586ba5..dd5e50700 100644 --- a/qt/BUILD.bazel +++ b/qt/BUILD.bazel @@ -129,6 +129,23 @@ py_binary( ], ) +py_binary( + name = "dmypy", + srcs = [ + "dmypy.py", + ], + data = [ + # ensure the binary's been built + "//pip:dmypy", + ], + imports = ["."], + tags = ["manual"], + deps = [ + "//pylib/anki", + "//qt/aqt:aqt_without_data", + ], +) + py_binary( name = "profile", srcs = ["tools/profile.py"], diff --git a/qt/dmypy-watch.sh b/qt/dmypy-watch.sh deleted file mode 100755 index 86109eb62..000000000 --- a/qt/dmypy-watch.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -# -# semi-working support for mypy daemon -# - install fs_watch -# - build anki/aqt wheels first -# - create a new venv and activate it -# - install the wheels -# - then run this script from this folder - -(sleep 1 && touch aqt) -. ~/pyenv/bin/activate -fswatch -o aqt | xargs -n1 -I{} sh -c 'printf \\033c\\n; dmypy run aqt' - diff --git a/qt/dmypy.py b/qt/dmypy.py new file mode 100755 index 000000000..ba3d6dc5c --- /dev/null +++ b/qt/dmypy.py @@ -0,0 +1,39 @@ +# Copyright: Ankitects Pty Ltd and contributors +# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +""" +Helper to run mypy in daemon mode. See development.md. Windows is not +currently supported. +""" + +import os +import subprocess +import sys +import time +from pathlib import Path + +workspace = Path(os.environ["BUILD_WORKSPACE_DIRECTORY"]) +binroot = workspace / "bazel-bin" +pyroot = binroot / "pip" + +if sys.platform.startswith("win32"): + binext = ".exe" +else: + binext = "" + +if subprocess.run( + [ + str(pyroot / ("dmypy" + binext)), + ] + + [ + "run", + "--", + "--config-file", + "qt/mypy.ini", + "bazel-bin/qt/runmypy.runfiles/net_ankiweb_anki/pylib/anki", + "bazel-bin/qt/runmypy.runfiles/net_ankiweb_anki/qt/aqt", + ], + env={"MYPYPATH":"bazel-bin/qt/runmypy.runfiles/pyqt5/"}, + cwd=workspace +).returncode: + sys.exit(1) diff --git a/scripts/mypy b/scripts/mypy new file mode 100755 index 000000000..6dc249a15 --- /dev/null +++ b/scripts/mypy @@ -0,0 +1,6 @@ +#!/bin/bash +# +# Run mypy, keeping it around as a daemon for faster checks. +# Does not work on Windows. + +bazel run qt:dmypy diff --git a/scripts/mypy-watch b/scripts/mypy-watch new file mode 100755 index 000000000..f99018f75 --- /dev/null +++ b/scripts/mypy-watch @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Run mypy as a daemon each time files change. Requires +# fswatch to be installed, and not working on Windows. + +# run once at startup +cmd='printf \\033c\\n; bazel run qt:dmypy' +sh -c "$cmd" + +# then monitor for changes +fswatch -r -o pylib qt | xargs -n1 -I{} sh -c "$cmd" \ No newline at end of file