Browse Source

Add mypy and pylance

Basti Tee 3 years ago
parent
commit
3a55281f2c
7 changed files with 86 additions and 48 deletions
  1. 3 2
      .vscode/extensions.json
  2. 8 7
      .vscode/settings.json
  3. 38 19
      Makefile
  4. 3 0
      Pipfile
  5. 4 1
      my_module/utils.py
  6. 21 14
      setup.cfg
  7. 9 5
      tests/test_utils.py

+ 3 - 2
.vscode/extensions.json

@@ -1,6 +1,7 @@
 {
     "recommendations": [
         "ms-python.python",
-        "wayou.vscode-todo-highlight"
-    ]
+        "ms-python.vscode-pylance"
+    ],
+    "unwantedRecommendations": []
 }

+ 8 - 7
.vscode/settings.json

@@ -1,5 +1,10 @@
 {
-    "python.pythonPath": "${workspaceFolder}/.venv",
+    "python.pythonPath": ".venv/bin/python",
+    "python.analysis.extraPaths": [
+        "my_module",
+        "tests",
+        ".venv/bin/python"
+    ],
     // PEP8 settings (https://www.python.org/dev/peps/pep-0008/)
     "editor.tabSize": 4,
     "editor.insertSpaces": true,
@@ -15,6 +20,7 @@
     "python.linting.enabled": true,
     "python.linting.lintOnSave": true,
     "python.linting.pylintEnabled": false,
+    "python.linting.mypyEnabled": true,
     "python.linting.flake8Enabled": true,
     "python.linting.flake8Args": [
         "--verbose"
@@ -23,10 +29,5 @@
     "python.testing.unittestEnabled": false,
     "python.testing.nosetestsEnabled": false,
     "python.testing.pytestEnabled": true,
-    "python.testing.pytestArgs": [],
-    "[python]": {
-        "editor.codeActionsOnSave": {
-            "source.organizeImports": true
-        }
-    }
+    "python.testing.pytestArgs": []
 }

+ 38 - 19
Makefile

@@ -7,18 +7,19 @@ ifeq (, $(shell which pipenv))
 endif
 
 # Suppress warning if pipenv is started inside .venv
-export PIPENV_VERBOSITY=1
+export PIPENV_VERBOSITY = 1
 # Use relative .venv folder instead of home-folder based
-export PIPENV_VENV_IN_PROJECT=1
-# Ignore existing venvs (required for travis)
-export PIPENV_IGNORE_VIRTUALENVS=1
-# Setup python path
-export PYTHONPATH=.
+export PIPENV_VENV_IN_PROJECT = 1
+# Ignore existing venvs
+export PIPENV_IGNORE_VIRTUALENVS = 1
 # Make sure we are running with an explicit encoding
-export LC_ALL=C.UTF-8
-export LANG=C.UTF-8
-# Current package version
+export LC_ALL = C
+export LANG = C.UTF-8
+# Set configuration folder to venv
+export PYPE_CONFIG_FOLDER = $(shell pwd)/.venv/.pype-cli
+# Process variables
 VERSION = $(shell python3 setup.py --version)
+PY_FILES := setup.py my_module tests
 
 all: clean venv build
 
@@ -32,10 +33,23 @@ shell:
 
 clean:
 	@echo Clean project base
-	rm -rfv .venv .tox .egg build dist src
-	find . -type d -name ".ropeproject" -exec rm -rf "{}" +;
-	find . -type d -name ".pytest_cache" -exec rm -rf "{}" +;
-	find . -type d -name "__pycache__" -exec rm -rf "{}" +;
+	find . -type d \
+	-name ".venv" -o \
+	-name ".tox" -o \
+	-name ".ropeproject" -o \
+	-name ".mypy_cache" -o \
+	-name ".pytest_cache" -o \
+	-name "__pycache__" -o \
+	-iname "*.egg-info" -o \
+	-name "build" -o \
+	-name "dist" \
+	|xargs rm -rfv
+
+	find . -type f \
+	-name "pyproject.toml" -o \
+	-name "Pipfile.lock" \
+	|xargs rm -rfv
+
 
 test:
 	@echo Run all tests in default virtualenv
@@ -45,19 +59,24 @@ testall:
 	@echo Run all tests against all virtualenvs defined in tox.ini
 	pipenv run tox -c setup.cfg tests
 
-coverage:
-	@echo Run test coverage checks
-	pipenv run py.test --verbose tests
-
 isort:
 	@echo Check for incorrectly sorted imports
-	pipenv run isort --check-only .
+	pipenv run isort --check-only $(PY_FILES)
+
+isort-apply:
+	@echo Check for incorrectly sorted imports
+	pipenv run isort $(PY_FILES)
+
+mypy:
+	@echo Run static code checks against source code base
+	pipenv run mypy my_module
+	pipenv run mypy tests
 
 lint:
 	@echo Run code formatting checks against source code base
 	pipenv run flake8 my_module tests
 
-build: test coverage isort lint
+build: test mypy isort lint
 	@echo Run setup.py-based build process to package application
 	pipenv run python setup.py bdist_wheel
 

+ 3 - 0
Pipfile

@@ -11,12 +11,15 @@ flake8-docstrings = "*" # flake8-ext for strict docstring linting
 flake8-builtins = "*" # flake8-ext to check python builtins used as vars etc.
 flake8-blind-except = "*" # flake8-ext to catch blind exception catches
 flake8-use-fstring = "*" # flake8-ext to enforce f-strings
+flake8-isort = "*" # flake8-ext to show isort issues
 pep8-naming = "*" # flake8-ext to enforce pep8 naming conventions
 isort = "*" # Automated import sorting
 pytest = "*" # Python base-testing library
 tox = "*" # Automated and standardized testing in Python
 rope = "*" # Refactoring library
 twine = "*" # Interoperability with pypi.org
+mypy = "*" # Optional static type checker
+typing_extensions = "*" # Typing extensions for mypy
 my_module = {path = ".", editable = true}
 
 [packages]

+ 4 - 1
my_module/utils.py

@@ -2,7 +2,10 @@
 """Utility functions."""
 
 
-def add_two_numbers(number_left, number_right):
+def add_two_numbers(
+    number_left: int = None,
+    number_right: int = None,
+) -> int:
     """Add two numbers."""
     if not number_left:
         raise ValueError('Input number_left must be set.')

+ 21 - 14
setup.cfg

@@ -3,10 +3,14 @@
 # -----------------------------------------------------------------------------
 
 [metadata]
-license_files = LICENSE.txt, README.md
+# https://wheel.readthedocs.io/en/stable/user_guide.html#including-license-files-in-the-generated-wheel-file
+license_files =
+    LICENSE.txt
+    README.md
 
 [bdist_wheel]
-universal = 1
+# https://packaging.python.org/guides/distributing-packages-using-setuptools/#wheels
+universal=0
 
 # -----------------------------------------------------------------------------
 # FORMATTING AND LINTING
@@ -20,11 +24,21 @@ ignore = Q003,W503
 percent-greedy = 0
 format-greedy = 2
 
-[tool:isort]
-# See https://github.com/timothycrosley/isort/wiki/isort-Settings
-# Default values for demonstration purposes
-sections = FUTURE,STDLIB,FIRSTPARTY,THIRDPARTY,LOCALFOLDER
-lines_between_sections = 1
+[mypy]
+# Untyped definitions and calls
+# Disallows defining functions without type annotations or with
+# incomplete type annotations.
+disallow_untyped_defs = true
+# Type-checks the interior of functions without type annotations
+check_untyped_defs = true
+# Import discovery
+follow_imports = normal
+ignore_missing_imports = True
+# Warning configuration
+warn_unused_ignores = true
+warn_unreachable = true
+# Error message config
+# pretty = true
 
 # -----------------------------------------------------------------------------
 # TEST CONFIGURATION
@@ -32,10 +46,3 @@ lines_between_sections = 1
 
 [tool:pytest]
 addopts = -p no:warnings
-
-[testenv]
-deps = pytest
-commands = python -m pytest tests
-
-[tox:tox]
-envlist = py37

+ 9 - 5
tests/test_utils.py

@@ -11,23 +11,27 @@ import json  # noqa: F401
 from os import path  # noqa: F401
 from re import IGNORECASE, sub  # noqa: F401
 
-import my_module  # noqa: F401
-from my_module.utils import add_two_numbers
-
 import pytest
 import requests  # noqa: F401
 
+import my_module  # noqa: F401
+from my_module.utils import add_two_numbers
+
 
 class TestUtils:  # noqa: D101
 
     @pytest.mark.parametrize('number_left, number_right', [
         (None, 1), (1, None), (None, None)
     ])
-    def test_add_two_numbers_no_input(self, number_left, number_right):
+    def test_add_two_numbers_no_input(
+            self,
+            number_left: int,
+            number_right: int
+    ) -> None:
         """Basic input validation."""
         with pytest.raises(ValueError):
             add_two_numbers(number_left, number_right)
 
-    def test_add_two_numbers_regular_input(self):
+    def test_add_two_numbers_regular_input(self) -> None:
         """Basic asserting test."""
         assert add_two_numbers(2, 3) == 5