diff --git a/.github/scripts/trailing-newlines.sh b/.github/scripts/trailing-newlines.sh index 332e65280..5e4c7e8e5 100755 --- a/.github/scripts/trailing-newlines.sh +++ b/.github/scripts/trailing-newlines.sh @@ -1,8 +1,13 @@ #!/bin/bash -set -e +set -eo pipefail + +# Checking version to force it fail the build if rg is not installed. +# Because `set -e` does not work inside the subshell $() +rg --version > /dev/null 2>&1 + +files=$(rg -l '[^\n]\z' -g '!*.{png,svg,scss,json,sql}' || true) -files=$(rg -l '[^\n]\z' -g '!*.{svg,scss,json,sql}' || true) if [ "$files" != "" ]; then echo "the following files are missing a newline on the last line:" echo $files diff --git a/Makefile b/Makefile index fdfa2c182..5ade34310 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ ifndef OS OS := unknown endif -ifeq ($(OS),Windows_NT) +ifeq (${OS},Windows_NT) ifndef ACTIVATE_SCRIPT ACTIVATE_SCRIPT := pyenv/Scripts/activate endif diff --git a/pylib/Makefile b/pylib/Makefile index c78af5bf4..a168d00dc 100644 --- a/pylib/Makefile +++ b/pylib/Makefile @@ -1,5 +1,19 @@ SHELL := /bin/bash FIND := $(if $(wildcard /bin/find),/bin/find,/usr/bin/find) +MYPY_ARGS := + +ifndef OS + OS := unknown +endif + +ifndef UNAME + UNAME := unknown +endif + +# https://anki.tenderapp.com/discussions/beta-testing/1860-error-unused-type-ignore-comment +ifneq (${OS},Windows_NT) + MYPY_ARGS := --warn-unused-ignores +endif .SHELLFLAGS := -eu -o pipefail -c .DELETE_ON_ERROR: @@ -33,7 +47,7 @@ PROTODEPS := $(wildcard ../proto/*.proto) .build/hooks: tools/genhooks.py tools/hookslib.py python tools/genhooks.py - black anki/hooks.py + python -m black anki/hooks.py @touch $@ BUILD_STEPS := .build/run-deps .build/dev-deps .build/py-proto anki/buildinfo.py .build/hooks @@ -47,7 +61,7 @@ check: $(BUILD_STEPS) .build/mypy .build/test .build/fmt .build/imports .build/l .PHONY: fix fix: $(BUILD_STEPS) isort $(ISORTARGS) - black $(BLACKARGS) + python -m black $(BLACKARGS) .PHONY: clean clean: @@ -59,7 +73,7 @@ clean: CHECKDEPS := $(shell ${FIND} anki tests -name '*.py' | grep -v buildinfo.py) .build/mypy: $(CHECKDEPS) - mypy anki + python -m mypy ${MYPY_ARGS} anki @touch $@ .build/test: $(CHECKDEPS) @@ -67,7 +81,8 @@ CHECKDEPS := $(shell ${FIND} anki tests -name '*.py' | grep -v buildinfo.py) @touch $@ .build/lint: $(CHECKDEPS) - pylint -j 0 --rcfile=.pylintrc -f colorized --extension-pkg-whitelist=ankirspy anki tests setup.py + python -m pylint -j 0 --rcfile=.pylintrc -f colorized \ + --extension-pkg-whitelist=ankirspy anki tests setup.py @touch $@ .build/imports: $(CHECKDEPS) @@ -75,7 +90,7 @@ CHECKDEPS := $(shell ${FIND} anki tests -name '*.py' | grep -v buildinfo.py) @touch $@ .build/fmt: $(CHECKDEPS) - black --check $(BLACKARGS) + python -m black --check $(BLACKARGS) @touch $@ # Building diff --git a/pylib/mypy.ini b/pylib/mypy.ini index 4215061bb..6ad6b351b 100644 --- a/pylib/mypy.ini +++ b/pylib/mypy.ini @@ -7,7 +7,6 @@ check_untyped_defs = true disallow_untyped_decorators = True warn_redundant_casts = True warn_unused_configs = True -warn_unused_ignores = True [mypy-win32file] ignore_missing_imports = True diff --git a/pylib/tests/test_importing.py b/pylib/tests/test_importing.py index fc90dcfe0..b563c1734 100644 --- a/pylib/tests/test_importing.py +++ b/pylib/tests/test_importing.py @@ -18,6 +18,15 @@ srcNotes = None srcCards = None +def clear_tempfile(tf): + """ https://stackoverflow.com/questions/23212435/permission-denied-to-write-to-my-temporary-file """ + try: + tf.close() + os.unlink(tf.name) + except: + pass + + def test_anki2_mediadupes(): tmp = getEmptyCol() # add a note that references a sound @@ -208,13 +217,15 @@ def test_tsv_tag_modified(): n.addTag("four") deck.addNote(n) - with NamedTemporaryFile(mode="w") as tf: + # https://stackoverflow.com/questions/23212435/permission-denied-to-write-to-my-temporary-file + with NamedTemporaryFile(mode="w", delete=False) as tf: tf.write("1\tb\tc\n") tf.flush() i = TextImporter(deck, tf.name) i.initMapping() i.tagModified = "boom" i.run() + clear_tempfile(tf) n.load() assert n["Front"] == "1" @@ -243,13 +254,15 @@ def test_tsv_tag_multiple_tags(): n.addTag("five") deck.addNote(n) - with NamedTemporaryFile(mode="w") as tf: + # https://stackoverflow.com/questions/23212435/permission-denied-to-write-to-my-temporary-file + with NamedTemporaryFile(mode="w", delete=False) as tf: tf.write("1\tb\tc\n") tf.flush() i = TextImporter(deck, tf.name) i.initMapping() i.tagModified = "five six" i.run() + clear_tempfile(tf) n.load() assert n["Front"] == "1" @@ -273,13 +286,15 @@ def test_csv_tag_only_if_modified(): n["Left"] = "3" deck.addNote(n) - with NamedTemporaryFile(mode="w") as tf: + # https://stackoverflow.com/questions/23212435/permission-denied-to-write-to-my-temporary-file + with NamedTemporaryFile(mode="w", delete=False) as tf: tf.write("1,2,3\n") tf.flush() i = TextImporter(deck, tf.name) i.initMapping() i.tagModified = "right" i.run() + clear_tempfile(tf) n.load() assert n.tags == [] diff --git a/pylib/tests/test_stats.py b/pylib/tests/test_stats.py index 7de3dc831..045983ac0 100644 --- a/pylib/tests/test_stats.py +++ b/pylib/tests/test_stats.py @@ -1,4 +1,5 @@ -# coding: utf-8 +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- import os import tempfile @@ -34,6 +35,6 @@ def test_graphs(): d = aopen(os.path.join(dir, "test.anki2")) g = d.stats() rep = g.report() - with open(os.path.join(dir, "test.html"), "w") as f: + with open(os.path.join(dir, "test.html"), "w", encoding="UTF-8") as f: f.write(rep) return diff --git a/qt/Makefile b/qt/Makefile index 82cd91292..9793e0cb8 100644 --- a/qt/Makefile +++ b/qt/Makefile @@ -1,5 +1,22 @@ SHELL := /bin/bash FIND := $(if $(wildcard /bin/find),/bin/find,/usr/bin/find) +MYPY_ARGS := +PYLINT_ARGS := + +ifndef OS + OS := unknown +endif + +ifndef UNAME + UNAME := unknown +endif + +# https://anki.tenderapp.com/discussions/beta-testing/1860-error-unused-type-ignore-comment +ifneq (${OS},Windows_NT) + MYPY_ARGS := --warn-unused-ignores +else + PYLINT_ARGS := --ignored-modules=win32file,pywintypes,socket,win32pipe +endif .SHELLFLAGS := -eu -o pipefail -c .DELETE_ON_ERROR: @@ -42,7 +59,7 @@ TSDEPS := $(wildcard ts/src/*.ts) $(wildcard ts/scss/*.scss) .build/hooks: tools/genhooks_gui.py ../pylib/tools/hookslib.py python tools/genhooks_gui.py - black aqt/gui_hooks.py + python -m black aqt/gui_hooks.py @touch $@ BUILD_STEPS := .build/run-deps .build/dev-deps .build/js .build/ui aqt/buildinfo.py .build/hooks .build/i18n @@ -56,7 +73,7 @@ check: $(BUILD_STEPS) .build/mypy .build/test .build/fmt .build/imports .build/l .PHONY: fix fix: $(BUILD_STEPS) isort $(ISORTARGS) - black $(BLACKARGS) + python -m black $(BLACKARGS) (cd ts && npm run pretty) .PHONY: clean @@ -80,7 +97,7 @@ PYLIB := ../pylib CHECKDEPS := $(shell ${FIND} aqt tests -name '*.py' | grep -v buildinfo.py) .build/mypy: $(CHECKDEPS) .build/qt-stubs - mypy aqt + python -m mypy ${MYPY_ARGS} aqt @touch $@ .build/test: $(CHECKDEPS) @@ -88,7 +105,8 @@ CHECKDEPS := $(shell ${FIND} aqt tests -name '*.py' | grep -v buildinfo.py) @touch $@ .build/lint: $(CHECKDEPS) - pylint -j 0 --rcfile=.pylintrc -f colorized --extension-pkg-whitelist=PyQt5,ankirspy aqt tests setup.py + python -m pylint -j 0 --rcfile=.pylintrc -f colorized ${PYLINT_ARGS} \ + --extension-pkg-whitelist=PyQt5,ankirspy aqt tests setup.py @touch $@ .build/imports: $(CHECKDEPS) @@ -96,7 +114,7 @@ CHECKDEPS := $(shell ${FIND} aqt tests -name '*.py' | grep -v buildinfo.py) @touch $@ .build/fmt: $(CHECKDEPS) - black --check $(BLACKARGS) + python -m black --check $(BLACKARGS) @touch $@ .build/qt-stubs: diff --git a/qt/aqt/main.py b/qt/aqt/main.py index baf5c49f9..7e84f59aa 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -1462,8 +1462,8 @@ will be lost. Continue?""" # make sure ctypes is bundled from ctypes import windll, wintypes # type: ignore - _dummy = windll - _dummy = wintypes + _dummy1 = windll + _dummy2 = wintypes def maybeHideAccelerators(self, tgt: Optional[Any] = None) -> None: if not self.hideMenuAccels: diff --git a/qt/mypy.ini b/qt/mypy.ini index 5d5a5ca40..a69375016 100644 --- a/qt/mypy.ini +++ b/qt/mypy.ini @@ -6,7 +6,6 @@ show_error_codes = true disallow_untyped_decorators = True warn_redundant_casts = True warn_unused_configs = True -warn_unused_ignores = True [mypy-win32file] ignore_missing_imports = True diff --git a/qt/po/scripts/copy-qt-files b/qt/po/scripts/copy-qt-files index 0a8a7eb25..71218733a 100755 --- a/qt/po/scripts/copy-qt-files +++ b/qt/po/scripts/copy-qt-files @@ -14,4 +14,4 @@ case "${unameOut}" in ;; esac -rsync -a "$qtTranslations"/qt* "$out" +rsync -a "$qtTranslations/" "$out/" diff --git a/qt/tools/typecheck-setup.sh b/qt/tools/typecheck-setup.sh index 65311f07c..93cca0447 100755 --- a/qt/tools/typecheck-setup.sh +++ b/qt/tools/typecheck-setup.sh @@ -6,8 +6,21 @@ # able to resolve. A solution that doesn't require modifying the python install # would be welcome! -TOOLS="$(cd "`dirname "$0"`"; pwd)" -modDir=$(python -c 'import PyQt5, sys, os; print(os.path.dirname(sys.modules["PyQt5"].__file__))') -cmd="rsync -a $TOOLS/stubs/PyQt5/* $modDir/" +set -eo pipefail -$cmd > /dev/null 2>&1 || sudo $cmd +TOOLS="$(cd "`dirname "$0"`"; pwd)" +modDir=$(python -c 'import PyQt5, sys, os; sys.stdout.write(os.path.dirname(sys.modules["PyQt5"].__file__))') + +unameOut="$(uname -s)" +case "${unameOut}" in + CYGWIN*) + modDir="$(cygpath -u "${modDir}")" + ;; +esac + +if [[ "w${OS}" == "wWindows_NT" ]]; +then + rsync -a "${TOOLS}/stubs/PyQt5/" "${modDir}/" +else + rsync -a "${TOOLS}/stubs/PyQt5/" "${modDir}/" || sudo rsync -a "${TOOLS}/stubs/PyQt5/" "${modDir}/" +fi diff --git a/rspy/Makefile b/rspy/Makefile index 798a67515..49c5237b6 100644 --- a/rspy/Makefile +++ b/rspy/Makefile @@ -5,7 +5,7 @@ ifndef OS OS := unknown endif -ifeq ($(OS),Windows_NT) +ifeq (${OS},Windows_NT) ifndef PYTHON_BIN PYTHON_BIN := python endif