Repository: kialo/stubalyzer (language: python)

Issue:
Evaluate Flit 
Evaluate using [Flit](https://flit.readthedocs.io/en/latest/) for packaging/publishing the package instead of using setuptools/twine.

See [notes here](https://realpython.com/pypi-publish-python-package/#flit).
Evaluate Flit 
Evaluate using [Flit](https://flit.readthedocs.io/en/latest/) for packaging/publishing the package instead of using setuptools/twine.

See [notes here](https://realpython.com/pypi-publish-python-package/#flit).


Discussion / hints:

Fix patch:
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 0610c6f..16659b6 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -2,6 +2,4 @@
 current_version = 0.5.0
 commit = True
 
-[bumpversion:file:setup.py]
-
 [bumpversion:file:stubalyzer/__init__.py]
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 0c2a48f..7ecd707 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,27 +1,39 @@
+version: 2
+
 jobs:
   build:
-    executor: python/default
+    working_directory: ~/stubalyzer
+    docker:
+      - image: cimg/python:3.9
     steps:
       - checkout
-      - python/install-packages:
-          pkg-manager: pip
+      - restore_cache:  # ensure this step occurs *before* installing dependencies
+          key: deps9-{{ .Branch }}-{{ checksum "pyproject.toml" }}-{{ checksum ".circleci/config.yml" }}
       - run:
-          command: python -m flake8 stubalyzer testing
+          name: Install Dependencies
+          command: ./dev/setup.sh
+      - save_cache:
+          key: deps9-{{ .Branch }}-{{ checksum "pyproject.toml" }}-{{ checksum ".circleci/config.yml" }}
+          paths:
+            - venv
+            - ~/.pyenv/versions/3.9.9/bin
+            - ~/.pyenv/versions/3.9.9/lib/python3.9/site-packages
+      - run:
+          command: |
+            source ./venv/bin/activate
+            python -m flake8 stubalyzer testing
           name: Lint
       - run:
-          command: python -m mypy stubalyzer testing --junit-xml "reports/mypy/result.xml" --exclude 'testing/(stubs-generated|test-stubs/test_compile_error_invalid_syntax|test-stubs/test_include_private/attr|stubs-handwritten)'
+          command: |
+            source ./venv/bin/activate
+            python -m mypy stubalyzer testing --junit-xml "reports/mypy/result.xml" --exclude 'testing/(stubs-generated|test-stubs/test_compile_error_invalid_syntax|test-stubs/test_include_private/attr|stubs-handwritten)'
           name: Typecheck
       - run:
-          command: python -m pytest --junitxml="reports/pytest/result.xml"
+          command: |
+            source ./venv/bin/activate
+            python -m pytest --junitxml="reports/pytest/result.xml"
           name: Test
       - store_test_results:
           path: reports
       - store_artifacts:
           path: reports
-orbs:
-  python: circleci/python@1.3.5
-version: 2.1
-workflows:
-  main:
-    jobs:
-      - build
diff --git a/.gitignore b/.gitignore
index b5a68b8..25db94a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,6 +46,7 @@ coverage.xml
 *.cover
 .hypothesis/
 .pytest_cache/
+reports/
 
 # Translations
 *.mo
@@ -89,6 +90,7 @@ venv/
 ENV/
 env.bak/
 venv.bak/
+.envrc
 
 # Spyder project settings
 .spyderproject
@@ -115,3 +117,6 @@ stubalyzer.iml
 
 # mypy source
 /mypy
+
+# OS
+.DS_Store
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..d5f965c
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,30 @@
+# See https://pre-commit.com for more information
+# See https://pre-commit.com/hooks.html for more hooks
+# Keep versions in sync with pyproject.toml
+repos:
+- repo: https://github.com/pre-commit/pre-commit-hooks
+  rev: v3.2.0
+  hooks:
+  - id: trailing-whitespace
+  - id: end-of-file-fixer
+  - id: check-yaml
+  - id: check-added-large-files
+
+- repo: https://github.com/pycqa/isort
+  rev: 5.10.1
+  hooks:
+  - id: isort
+
+- repo: https://github.com/psf/black
+  rev: 22.6.0
+  hooks:
+  - id: black
+    exclude: ^(testing/test-stubs/).*
+
+- repo: https://github.com/pycqa/flake8
+  rev: 4.0.1
+  hooks:
+  - id: flake8
+    additional_dependencies:
+      - pep8
+      - flake8-rst-docstrings==0.2.7
diff --git a/README.rst b/README.rst
index 84ec5dc..2279639 100644
--- a/README.rst
+++ b/README.rst
@@ -131,8 +131,7 @@ Development Setup
 
 Requirements for development:
 
--  A recent Python version (we currently use 3.7)
--  ``virtualenv`` and ``virtualenvwrapper``
+-  A recent Python version (we currently use 3.9)
 
 For a development setup, run the following shell script:
 
@@ -140,10 +139,10 @@ For a development setup, run the following shell script:
 
    $ ./dev/setup.sh
 
-This will create a virtual environment called ``stubalyzer`` and install
-the projects dependencies. The setup script also creates a ``.venv``
-file so the environment activates automatically if you use
-auto-activation with virtualenv.
+This will create a virtual environment in the directory ``venv`` and install the
+project's dependencies.
+To activate the virtual environment, run ``source ./venv/bin/activate`` from the project
+directory.
 
 Tests
 ~~~~~
@@ -166,19 +165,18 @@ Type checking is done with Mypy:
 Code Formatting
 ~~~~~~~~~~~~~~~
 
-To set up the pre-commit hook to automatically format files, create the
-following link:
+To set up the pre-commit hook to automatically format files, run:
 
 .. code:: shell-session
 
-   $ ln -sf ../../dev/pre-commit.sh .git/hooks/pre-commit
+   $ pre-commit install
 
 The source code is formatted using ``black`` and ``isort``. The
 following will format all files in the project:
 
 .. code:: shell-session
 
-   $ ./dev/fmt.sh
+   $ pre-commit run -a
 
 Linting
 ~~~~~~~
@@ -189,25 +187,18 @@ Linting is done using ``flake8``, in the root directory run:
 
    $ flake8
 
+On commit, ``pre-commit`` automtically runs ``flake8`` on changed files.
+
 Dependency Management
 ~~~~~~~~~~~~~~~~~~~~~
 
-If you need new dependencies, add them in ``requirements.in`` and
-``setup.py``, then run the ``pip-compile`` command specified at the top
-of ``requirements.txt``.
+If you need new dependencies, add them in ``pyproject.toml``.
 
 Documentation
 ~~~~~~~~~~~~~
 
 The documentation is written using Sphinx.
-
-First install the requirements:
-
-.. code:: shell-session
-
-   $ pip install -r docs/requirements.txt
-
-Then build the documentation using:
+Build the documentation using:
 
 .. code:: shell-session
 
diff --git a/dev/ensure_venv.sh b/dev/ensure_venv.sh
new file mode 100644
index 0000000..0819bb3
--- /dev/null
+++ b/dev/ensure_venv.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+# Source this script
+if [[ -z $VIRTUAL_ENV ]]; then
+    python3 -m venv ./venv
+    source ./venv/bin/activate
+fi
diff --git a/dev/fmt.sh b/dev/fmt.sh
deleted file mode 100755
index d218843..0000000
--- a/dev/fmt.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-
-# Apply autoformatting to Python files
-# Usage: ./dev/fmt.sh [FILES]
-#
-# The behaviour can be configured using environment variables:
-# SILENT: disable printing of executed commands command
-
-set -eu
-function enable_xtrace {
-    [ "${SILENT:-}" ] || set -x
-}
-enable_xtrace
-
-cd $(dirname $0)/..
-
-
-if [ $# -eq 0 ]
-then
-    isort_params="--recursive stubalyzer testing setup.py"
-    black_params="stubalyzer testing setup.py"
-else
-    isort_params="$@"
-    black_params="$@"
-fi
-
-isort $isort_params
-black $black_params
diff --git a/dev/lint.sh b/dev/lint.sh
deleted file mode 100755
index cbc7ab0..0000000
--- a/dev/lint.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-cd $(dirname $0)/..
-
-flake8 stubalyzer testing
-# Keep exclude list in sync with /.circleci/config.yml
-# Note that we can't put this in /testing/mypy.ini because the stubs need to be found for the tests
-mypy stubalyzer testing --exclude 'testing/(stubs-generated|test-stubs/test_compile_error_invalid_syntax|test-stubs/test_include_private/attr|stubs-handwritten)'
diff --git a/dev/pre-commit.sh b/dev/pre-commit.sh
deleted file mode 100755
index ee513a2..0000000
--- a/dev/pre-commit.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-# Add the pre commit hook e.g. by running the following command in the root project directory
-#   ln -sf ../../dev/pre-commit.sh .git/hooks/pre-commit
-set -eu
-
-files_to_consider=$@
-if [ -z "$files_to_consider" ]; then
-    files_to_consider=$(git diff --cached --name-only --diff-filter=ACM)
-else
-    files_to_consider=$(echo "$files_to_consider" | tr ' ' '\n')
-fi
-
-pyfiles=$(echo "$files_to_consider" | grep -E '\.py$' | tr '\n' ' ')
-if [ "$pyfiles" ]; then
-    venv=$(ls -1 ~/.virtualenvs/stubalyzer{,*}/bin/activate 2>/dev/null | head -n1)
-    if [ -f "$venv" ]; then
-        # Allow multiple environments
-        set +u  # Ignore error: "bin/activate: line 57: PS1: unbound variable"
-        . $venv
-        set -u
-    fi
-    SILENT=1 dev/fmt.sh $pyfiles
-    git add $pyfiles
-fi
diff --git a/dev/release.sh b/dev/release.sh
index cfc4573..31f80ab 100755
--- a/dev/release.sh
+++ b/dev/release.sh
@@ -1,9 +1,13 @@
 #!/bin/bash
 set -e
+
+source "$(dirname $0)/ensure_venv.sh"
 source "$(dirname $0)/util.sh"
 
-function get_version {
-    python -c 'print(__import__("stubalyzer").__version__)'
+old_version="v$(get_version)"
+
+function changes {
+    git log --abbrev-commit --format='-  %s - %h' ${old_version}..HEAD | cat
 }
 
 if [ -z "$1" ]; then
@@ -14,58 +18,67 @@ fi
 echo "Cleaning up build and dist output..."
 rm -rf build dist
 
-old_version="v$(get_version)"
-
 echo "Bumping $1 version..."
 bump2version $@
 
 new_version="v$(get_version)"
 
+echo ""
 echo "Bumped version from $old_version to $new_version"
+
 echo ""
-tput smso
-echo "Please update the 'Commits' link under 'Development' in CHANGELOG.rst to the following:"
-echo "<<<<<<<<<<<<<<<<"
-tput rmso
+if confirm "Tag new version" "Y"; then
+    echo "Tagging ${new_version}..."
+    cat << EOF | git tag -s ${new_version} -F-
+Release ${new_version}
+
+$(changes)
+EOF
+    tagged=true
+else
+    tagged=false
+    echo "Not tagging ${new_version}."
+fi
+
 echo ""
-echo "\`Commits <https://github.com/kialo/stubalyzer/compare/${new_version}...master>\`__"
+if $tagged && confirm "Push tag ${new_version} to remote?"; then
+    echo "Pushing tag ${new_version}..."
+    git push origin ${new_version}
+else
+    echo "Not pushing tag."
+fi
+
 echo ""
-tput smso
-echo ">>>>>>>>>>>>>>>>"
-tput rmso
+if confirm "Publish ${new_version} to pypi?"; then
+    echo "Publishing ${new_version} to pypi..."
+    flit publish
+    echo "git push origin ${new_version}"
+else
+    echo "Not publishing to pypi."
+fi
 
 heading="${new_version} - $(format_date)"
 heading_line=$(dashes $(length "$heading"))
 
-tput smso
-echo "Also add a new section below 'Development':"
-echo "<<<<<<<<<<<<<<<<"
-tput rmso
-echo ""
-echo "$heading"
-echo "$heading_line"
-echo ""
-echo "\`Commits <https://github.com/kialo/stubalyzer/compare/${old_version}...${new_version}>\`__"
-echo ""
-git log --abbrev-commit --format='-  %s - %h' ${old_version}..HEAD | cat
-echo ""
-tput smso
-echo ">>>>>>>>>>>>>>>>"
-tput rmso
+changelog=$(cat <<EOF
+\`Commits <https://github.com/kialo/stubalyzer/compare/${new_version}...master>\`__
+
+$heading
+$heading_line
+
+\`Commits <https://github.com/kialo/stubalyzer/compare/${old_version}...${new_version}>\`__
 
+$(changes)
+EOF
+)
+
+echo ""
 tput smso
-echo "Once updated, commit the changes, tag, push and upload to PyPI:"
+echo "Please replace the \"Commits\" link under the \"Development\" heading in CHANGELOG.rst with the following:"
 echo "<<<<<<<<<<<<<<<<"
 tput rmso
-echo ""
-echo "git commit -a -m 'Update changelog'"
-echo "git tag -s ${new_version}"
-echo "git push"
-# Is this necessary?
-echo "git push --tags"
-echo "python setup.py -q sdist bdist_wheel"
-echo "twine upload dist/*"
-echo ""
+echo "$changelog"
 tput smso
 echo ">>>>>>>>>>>>>>>>"
+echo "Once updated, commit the changes and push."
 tput rmso
diff --git a/dev/setup.sh b/dev/setup.sh
index 5f9f699..2e5115a 100755
--- a/dev/setup.sh
+++ b/dev/setup.sh
@@ -1,15 +1,7 @@
 #!/bin/bash
 
+source "$(dirname $0)/ensure_venv.sh"
 cd $(dirname $0)/..
 
-rm -rf ./venv
-python3 -m venv venv
-source ./venv/bin/activate
-pip install --upgrade pip
-pip install --upgrade -r requirements.txt
-pip install -e .
-
-if [ ! -f .venv ]
-then
-    echo "venv" > .venv
-fi
+pip install --upgrade pip wheel setuptools flit
+flit install --deps all
diff --git a/dev/update-apidoc.sh b/dev/update-apidoc.sh
index 1382ab4..d8524fe 100755
--- a/dev/update-apidoc.sh
+++ b/dev/update-apidoc.sh
@@ -1,4 +1,5 @@
 #!/bin/bash
 
+source "$(dirname $0)/ensure_venv.sh"
 cd $(dirname $0)/..
 sphinx-apidoc -o docs/api -e -f stubalyzer '*_test.py' '**/conftest.py'
diff --git a/dev/util.sh b/dev/util.sh
index f3b8076..29566ab 100644
--- a/dev/util.sh
+++ b/dev/util.sh
@@ -32,3 +32,43 @@ function length {
 function dashes {
     printf -- '-%.s' $(eval "echo {1.."$(($1))"}")
 }
+
+function get_version {
+    python -c 'print(__import__("stubalyzer").__version__)'
+}
+
+function confirm() {
+    local prompt default reply
+
+    if [[ ${2:-} = 'Y' ]]; then
+        prompt='Y/n'
+        default='Y'
+    elif [[ ${2:-} = 'N' ]]; then
+        prompt='y/N'
+        default='N'
+    else
+        prompt='y/n'
+        default=''
+    fi
+
+    while true; do
+
+        # Ask the question (not using "read -p" as it uses stderr not stdout)
+        echo -n "$1 [$prompt] "
+
+        # Read the answer (use /dev/tty in case stdin is redirected from somewhere else)
+        read -r reply </dev/tty
+
+        # Default?
+        if [[ -z $reply ]]; then
+            reply=$default
+        fi
+
+        # Check if the reply is valid
+        case "$reply" in
+            Y*|y*) return 0 ;;
+            N*|n*) return 1 ;;
+        esac
+
+    done
+}
diff --git a/docs/api/stubalyzer.rst b/docs/api/stubalyzer.rst
index 02522c0..e6488b3 100644
--- a/docs/api/stubalyzer.rst
+++ b/docs/api/stubalyzer.rst
@@ -5,6 +5,7 @@ Submodules
 ----------
 
 .. toctree::
+   :maxdepth: 4
 
    stubalyzer.analyze
    stubalyzer.collect
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 5570412..79a599e 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,2 +1,3 @@
+Pygments
 Sphinx>=2.2.0
 sphinx-rtd-theme
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..a6e71ee
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,54 @@
+[build-system]
+requires = ["flit_core >=3.2,<4"]
+build-backend = "flit_core.buildapi"
+
+[project]
+name = "stubalyzer"
+authors = [{name = "Kialo GmbH", email = "open-source@kialo.com"}]
+description = "Analysis tool comparing hand written stubs to stubgen-generated ones, reporting inconsistencies"
+readme = "README.rst"
+license = {file = "LICENSE"}
+dynamic = ["version"]
+classifiers=[
+    "Development Status :: 3 - Alpha",
+    "Intended Audience :: Developers",
+    "Topic :: Software Development :: Build Tools",
+    "Typing :: Typed",
+    "License :: OSI Approved :: MIT License",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.9",
+]
+keywords = ["mypy", "analysis", "stubgen", "stubs"]
+requires-python=">=3.9"
+dependencies = [
+    "mypy==0.930",
+    "schema>=0.7.5",
+]
+
+[project.scripts]
+stubalyzer = "stubalyzer.analyze:main"
+
+[project.optional-dependencies]
+dev = [
+    "bump2version>=1.0.1",
+    "pre-commit>=2.20.0",
+    # Linters, keep versions in sync with .pre-commit-config.yaml
+    "black==22.6.0",
+    "flake8==4.0.1",
+    "flake8-rst-docstrings==0.2.7",
+    "isort==5.10.1",
+]
+test = [
+    "pytest>=6.2.5",
+    "attrs==19.3.0",  # for stub testing
+]
+# When changing these, please also update docs/requriements.txt
+doc = [
+    "Sphinx>=2.2.0",
+    "Pygments",
+    "sphinx-rtd-theme"
+]
+
+[project.urls]
+Home = "https://github.com/kialo/stubalyzer"
+"Bug Reports" = "https://github.com/kialo/stubalyzer/issues"
diff --git a/requirements.in b/requirements.in
deleted file mode 100644
index 5dd0e3c..0000000
--- a/requirements.in
+++ /dev/null
@@ -1,15 +0,0 @@
-mypy==0.930
-
-black
-flake8
-flake8-rst-docstrings
-isort
-pip-tools
-pytest
-schema
-Pygments
-bump2version
-wheel
-lxml
-
-attrs==19.3.0  # for tests
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index db95318..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,246 +0,0 @@
-#
-# This file is autogenerated by pip-compile with python 3.9
-# To update, run:
-#
-#    pip-compile --allow-unsafe --generate-hashes requirements.in
-#
-attrs==19.3.0 \
-    --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \
-    --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72
-    # via
-    #   -r requirements.in
-    #   pytest
-black==21.12b0 \
-    --hash=sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3 \
-    --hash=sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f
-    # via -r requirements.in
-bump2version==1.0.1 \
-    --hash=sha256:37f927ea17cde7ae2d7baf832f8e80ce3777624554a653006c9144f8017fe410 \
-    --hash=sha256:762cb2bfad61f4ec8e2bdf452c7c267416f8c70dd9ecb1653fd0bbb01fa936e6
-    # via -r requirements.in
-click==8.0.3 \
-    --hash=sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3 \
-    --hash=sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b
-    # via
-    #   black
-    #   pip-tools
-contextlib2==21.6.0 \
-    --hash=sha256:3fbdb64466afd23abaf6c977627b75b6139a5a3e8ce38405c5b413aed7a0471f \
-    --hash=sha256:ab1e2bfe1d01d968e1b7e8d9023bc51ef3509bba217bb730cee3827e1ee82869
-    # via schema
-docutils==0.18.1 \
-    --hash=sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c \
-    --hash=sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06
-    # via restructuredtext-lint
-flake8==4.0.1 \
-    --hash=sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d \
-    --hash=sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d
-    # via
-    #   -r requirements.in
-    #   flake8-rst-docstrings
-flake8-rst-docstrings==0.2.5 \
-    --hash=sha256:4fe93f997dea45d9d3c8bd220f12f0b6c359948fb943b5b48021a3f927edd816 \
-    --hash=sha256:b99d9041b769b857efe45a448dc8c71b1bb311f9cacbdac5de82f96498105082
-    # via -r requirements.in
-iniconfig==1.1.1 \
-    --hash=sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3 \
-    --hash=sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32
-    # via pytest
-isort==5.10.1 \
-    --hash=sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7 \
-    --hash=sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951
-    # via -r requirements.in
-lxml==4.9.1 \
-    --hash=sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318 \
-    --hash=sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c \
-    --hash=sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b \
-    --hash=sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000 \
-    --hash=sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73 \
-    --hash=sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d \
-    --hash=sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb \
-    --hash=sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8 \
-    --hash=sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2 \
-    --hash=sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345 \
-    --hash=sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94 \
-    --hash=sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e \
-    --hash=sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b \
-    --hash=sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc \
-    --hash=sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a \
-    --hash=sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9 \
-    --hash=sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc \
-    --hash=sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387 \
-    --hash=sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb \
-    --hash=sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7 \
-    --hash=sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4 \
-    --hash=sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97 \
-    --hash=sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67 \
-    --hash=sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627 \
-    --hash=sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7 \
-    --hash=sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd \
-    --hash=sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3 \
-    --hash=sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7 \
-    --hash=sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130 \
-    --hash=sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b \
-    --hash=sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036 \
-    --hash=sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785 \
-    --hash=sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca \
-    --hash=sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91 \
-    --hash=sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc \
-    --hash=sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536 \
-    --hash=sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391 \
-    --hash=sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3 \
-    --hash=sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d \
-    --hash=sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21 \
-    --hash=sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3 \
-    --hash=sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d \
-    --hash=sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29 \
-    --hash=sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715 \
-    --hash=sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed \
-    --hash=sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25 \
-    --hash=sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c \
-    --hash=sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785 \
-    --hash=sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837 \
-    --hash=sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4 \
-    --hash=sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b \
-    --hash=sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2 \
-    --hash=sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067 \
-    --hash=sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448 \
-    --hash=sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d \
-    --hash=sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2 \
-    --hash=sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc \
-    --hash=sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c \
-    --hash=sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5 \
-    --hash=sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84 \
-    --hash=sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8 \
-    --hash=sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf \
-    --hash=sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7 \
-    --hash=sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e \
-    --hash=sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb \
-    --hash=sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b \
-    --hash=sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3 \
-    --hash=sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad \
-    --hash=sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8 \
-    --hash=sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f
-    # via -r requirements.in
-mccabe==0.6.1 \
-    --hash=sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42 \
-    --hash=sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f
-    # via flake8
-mypy==0.930 \
-    --hash=sha256:0feb82e9fa849affca7edd24713dbe809dce780ced9f3feca5ed3d80e40b777f \
-    --hash=sha256:1d2296f35aae9802eeb1327058b550371ee382d71374b3e7d2804035ef0b830b \
-    --hash=sha256:1e689e92cdebd87607a041585f1dc7339aa2e8a9f9bad9ba7e6ece619431b20c \
-    --hash=sha256:1ea7199780c1d7940b82dbc0a4e37722b4e3851264dbba81e01abecc9052d8a7 \
-    --hash=sha256:221cc94dc6a801ccc2be7c0c9fd791c5e08d1fa2c5e1c12dec4eab15b2469871 \
-    --hash=sha256:2e9c5409e9cb81049bb03fa1009b573dea87976713e3898561567a86c4eaee01 \
-    --hash=sha256:45a4dc21c789cfd09b8ccafe114d6de66f0b341ad761338de717192f19397a8c \
-    --hash=sha256:51426262ae4714cc7dd5439814676e0992b55bcc0f6514eccb4cf8e0678962c2 \
-    --hash=sha256:554873e45c1ca20f31ddf873deb67fa5d2e87b76b97db50669f0468ccded8fae \
-    --hash=sha256:5feb56f8bb280468fe5fc8e6f56f48f99aa0df9eed3c507a11505ee4657b5380 \
-    --hash=sha256:601f46593f627f8a9b944f74fd387c9b5f4266b39abad77471947069c2fc7651 \
-    --hash=sha256:70b197dd8c78fc5d2daf84bd093e8466a2b2e007eedaa85e792e513a820adbf7 \
-    --hash=sha256:959319b9a3cafc33a8185f440a433ba520239c72e733bf91f9efd67b0a8e9b30 \
-    --hash=sha256:a9d8dffefba634b27d650e0de2564379a1a367e2e08d6617d8f89261a3bf63b2 \
-    --hash=sha256:b419e9721260161e70d054a15abbd50603c16f159860cfd0daeab647d828fc29 \
-    --hash=sha256:bc1a0607ea03c30225347334af66b0af12eefba018a89a88c209e02b7065ea95 \
-    --hash=sha256:bf4a44e03040206f7c058d1f5ba02ef2d1820720c88bc4285c7d9a4269f54173 \
-    --hash=sha256:db3a87376a1380f396d465bed462e76ea89f838f4c5e967d68ff6ee34b785c31 \
-    --hash=sha256:ed4e0ea066bb12f56b2812a15ff223c57c0a44eca817ceb96b214bb055c7051f \
-    --hash=sha256:f9f665d69034b1fcfdbcd4197480d26298bbfb5d2dfe206245b6498addb34999
-    # via -r requirements.in
-mypy-extensions==0.4.3 \
-    --hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \
-    --hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8
-    # via
-    #   black
-    #   mypy
-packaging==21.3 \
-    --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \
-    --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522
-    # via pytest
-pathspec==0.9.0 \
-    --hash=sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a \
-    --hash=sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1
-    # via black
-pep517==0.12.0 \
-    --hash=sha256:931378d93d11b298cf511dd634cf5ea4cb249a28ef84160b3247ee9afb4e8ab0 \
-    --hash=sha256:dd884c326898e2c6e11f9e0b64940606a93eb10ea022a2e067959f3a110cf161
-    # via pip-tools
-pip-tools==6.4.0 \
-    --hash=sha256:65553a15b1ba34be5e43889345062e38fb9b219ffa23b084ca0d4c4039b6f53b \
-    --hash=sha256:bb2c3272bc229b4a6d25230ebe255823aba1aa466a0d698c48ab7eb5ab7efdc9
-    # via -r requirements.in
-platformdirs==2.4.1 \
-    --hash=sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca \
-    --hash=sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda
-    # via black
-pluggy==1.0.0 \
-    --hash=sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159 \
-    --hash=sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3
-    # via pytest
-py==1.11.0 \
-    --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \
-    --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378
-    # via pytest
-pycodestyle==2.8.0 \
-    --hash=sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20 \
-    --hash=sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f
-    # via flake8
-pyflakes==2.4.0 \
-    --hash=sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c \
-    --hash=sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e
-    # via flake8
-pygments==2.11.1 \
-    --hash=sha256:59b895e326f0fb0d733fd28c6839bd18ad0687ba20efc26d4277fd1d30b971f4 \
-    --hash=sha256:9135c1af61eec0f650cd1ea1ed8ce298e54d56bcd8cc2ef46edd7702c171337c
-    # via
-    #   -r requirements.in
-    #   flake8-rst-docstrings
-pyparsing==3.0.6 \
-    --hash=sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4 \
-    --hash=sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81
-    # via packaging
-pytest==6.2.5 \
-    --hash=sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89 \
-    --hash=sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134
-    # via -r requirements.in
-restructuredtext-lint==1.3.2 \
-    --hash=sha256:d3b10a1fe2ecac537e51ae6d151b223b78de9fafdd50e5eb6b08c243df173c80
-    # via flake8-rst-docstrings
-schema==0.7.5 \
-    --hash=sha256:f06717112c61895cabc4707752b88716e8420a8819d71404501e114f91043197 \
-    --hash=sha256:f3ffdeeada09ec34bf40d7d79996d9f7175db93b7a5065de0faa7f41083c1e6c
-    # via -r requirements.in
-toml==0.10.2 \
-    --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \
-    --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f
-    # via pytest
-tomli==1.2.3 \
-    --hash=sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f \
-    --hash=sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c
-    # via
-    #   black
-    #   mypy
-    #   pep517
-typing-extensions==4.0.1 \
-    --hash=sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e \
-    --hash=sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b
-    # via
-    #   black
-    #   mypy
-wheel==0.37.1 \
-    --hash=sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a \
-    --hash=sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4
-    # via
-    #   -r requirements.in
-    #   pip-tools
-
-# The following packages are considered to be unsafe in a requirements file:
-pip==21.3.1 \
-    --hash=sha256:deaf32dcd9ab821e359cd8330786bcd077604b5c5730c0b096eda46f95c24a2d \
-    --hash=sha256:fd11ba3d0fdb4c07fbc5ecbba0b1b719809420f25038f8ee3cd913d3faa3033a
-    # via pip-tools
-setuptools==60.2.0 \
-    --hash=sha256:5c89b1a14a67ac5f0956f1cb0aeb7d1d3f4c8ba4e4e1ab7bf1af4933f9a2f0fe \
-    --hash=sha256:675fcebecb43c32eb930481abf907619137547f4336206e4d673180242e1a278
-    # via pip-tools
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 91b0b21..0000000
--- a/setup.py
+++ /dev/null
@@ -1,104 +0,0 @@
-from os import path
-
-# Always prefer setuptools over distutils
-from setuptools import setup
-
-VERSION = "0.5.0"
-# This is the name of the GitHub repo and the package name on pypi
-PACKAGE_NAME = "stubalyzer"
-
-
-here = path.abspath(path.dirname(__file__))
-
-# Get the long description from the README file
-with open(path.join(here, "README.rst"), encoding="utf-8") as f:
-    long_description = f.read()
-
-setup(
-    # This is the name of your project. The first time you publish this
-    # package, this name will be registered for you. It will determine how
-    # users can install this project, e.g.:
-    #
-    # $ pip install sampleproject
-    #
-    # And where it will live on PyPI: https://pypi.org/project/sampleproject/
-    name=PACKAGE_NAME,
-    version=VERSION,
-    description=(
-        "Analysis tool comparing hand written stubs to stubgen-generated ones, "
-        "reporting inconsistencies"
-    ),
-    long_description=long_description,
-    long_description_content_type="text/x-rst",
-    url=f"https://github.com/kialo/{PACKAGE_NAME}",
-    author="Kialo GmbH",
-    author_email="open-source@kialo.com",
-    # For a list of valid classifiers, see https://pypi.org/classifiers/
-    classifiers=[
-        # How mature is this project? Common values are
-        #   3 - Alpha
-        #   4 - Beta
-        #   5 - Production/Stable
-        "Development Status :: 3 - Alpha",
-        # Indicate who your project is intended for
-        "Intended Audience :: Developers",
-        "Topic :: Software Development :: Build Tools",
-        "Typing :: Typed",
-        "License :: OSI Approved :: MIT License",
-        # Specify the Python versions you support here. In particular, ensure
-        # that you indicate whether you support Python 2, Python 3 or both.
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.6",
-        "Programming Language :: Python :: 3.7",
-    ],
-    # This field adds keywords for your project which will appear on the
-    # project page. What does your project relate to?
-    #
-    # Note that this is a string of words separated by whitespace, not a list.
-    keywords="mypy analysis stubgen stubs",
-    packages=["stubalyzer"],
-    python_requires=">=3.6",
-    # This field lists other packages that your project depends on to run.
-    # Any package you put here will be installed by pip when your project is
-    # installed, so they must be valid existing projects.
-    #
-    # For an analysis of "install_requires" vs pip's requirements files see:
-    # https://packaging.python.org/en/latest/requirements.html
-    install_requires=["mypy", "schema"],
-    # List additional groups of dependencies here (e.g. development
-    # dependencies). Users will be able to install these using the "extras"
-    # syntax, for example:
-    #
-    #   $ pip install sampleproject[dev]
-    #
-    # Similar to `install_requires` above, these must be valid existing
-    # projects.
-    extras_require={
-        "dev": [
-            "black",
-            "bump2version",
-            "flake8-rst-docstrings",
-            "flake8",
-            "ipython",
-            "isort",
-            "lxml",
-            "pip-tools",
-            "pytest",
-        ]
-    },
-    # To provide executable scripts, use entry points in preference to the
-    # "scripts" keyword. Entry points provide cross-platform support and allow
-    # `pip` to create the appropriate form of executable for the target
-    # platform.
-    entry_points={
-        "console_scripts": ["stubalyzer=stubalyzer.analyze:main"]
-    },  # Optional
-    # List additional URLs that are relevant to your project as a dict.
-    project_urls={
-        "Bug Reports": f"https://github.com/kialo/{PACKAGE_NAME}/issues",
-        "Source": f"https://github.com/kialo/{PACKAGE_NAME}",
-    },
-    # For mypy to find types
-    zip_safe=False,
-    package_data={"stubalyzer": ["py.typed"]},
-)


Test patch:
diff --git a/testing/stub-expectations/additional_function_params.json b/testing/stub-expectations/additional_function_params.json
index a058b7e..62395f0 100644
--- a/testing/stub-expectations/additional_function_params.json
+++ b/testing/stub-expectations/additional_function_params.json
@@ -1,4 +1,4 @@
 {
     "functions.additional_args": "mismatch",
     "functions.matching_function": "mismatch"
-}
\ No newline at end of file
+}
diff --git a/testing/stub-expectations/matching.json b/testing/stub-expectations/matching.json
index 5661704..adeb886 100644
--- a/testing/stub-expectations/matching.json
+++ b/testing/stub-expectations/matching.json
@@ -1,4 +1,4 @@
 {
   "matching.MATCHING_CONSTANT": "not_found",
   "matching.matching_variable": "mismatch"
-}
\ No newline at end of file
+}
diff --git a/testing/stub-expectations/mismatching.json b/testing/stub-expectations/mismatching.json
index 4bb8737..95397df 100644
--- a/testing/stub-expectations/mismatching.json
+++ b/testing/stub-expectations/mismatching.json
@@ -2,4 +2,4 @@
   "mismatching.mismatching_function": "mismatch",
   "mismatching.MISMATCHING_CONSTANT": "not_found",
   "mismatching.missing_parameters": "mismatch"
-}
\ No newline at end of file
+}
diff --git a/testing/stub-expectations/missing.json b/testing/stub-expectations/missing.json
index 34d7833..3741ec0 100644
--- a/testing/stub-expectations/missing.json
+++ b/testing/stub-expectations/missing.json
@@ -2,4 +2,4 @@
   "missing.missing_decorator": "not_found",
   "missing.MISSING_CONSTANT": "not_found",
   "missing.missing_function": "mismatch"
-}
\ No newline at end of file
+}
diff --git a/testing/test_report.xml b/testing/test_report.xml
index 95b33ff..7948198 100644
--- a/testing/test_report.xml
+++ b/testing/test_report.xml
@@ -1,2 +1,2 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<checkstyle version="4.3"><file name="{path}/testing/stubs-handwritten/classes.pyi"><error column="4" line="15" message="&#10;Found symbol &quot;classes.ClassWithoutSuperClassInHandwritten.a_method&quot; in different location &quot;classes.AClass.a_method&quot;." severity="error" /><error column="0" line="18" message="&#10;Symbol &quot;classes.MissingClass&quot; not found in generated stubs" severity="error" /><error column="4" line="35" message="&#10;Types for classes.ClassWithInvalidCustomStub.argument_order_wrong do not match:&#10;    Handwritten type: def (self: classes.ClassWithInvalidCustomStub, bar: builtins.str, foo: builtins.int) -&gt; builtins.int&#10;    Reference type  : def (self: classes.ClassWithInvalidCustomStub, foo: Any, bar: Any) -&gt; Any" severity="error" /><error column="4" line="36" message="&#10;Types for classes.ClassWithInvalidCustomStub.argument_names_wrong do not match:&#10;    Handwritten type: def (self: classes.ClassWithInvalidCustomStub, foor: builtins.int, bart: builtins.str) -&gt; builtins.str&#10;    Reference type  : def (self: classes.ClassWithInvalidCustomStub, foo: Any, bar: Any) -&gt; Any" severity="error" /><error column="4" line="37" message="&#10;Types for classes.ClassWithInvalidCustomStub.argument_types_wrong do not match:&#10;    Handwritten type: def (self: classes.ClassWithInvalidCustomStub, foo: builtins.str, bar: builtins.bool) -&gt; builtins.bool&#10;    Reference type  : def (self: classes.ClassWithInvalidCustomStub, foo: builtins.int, bar: builtins.str) -&gt; Any" severity="error" /><error column="4" line="39" message="&#10;Types for classes.ClassWithInvalidCustomStub.return_type_wrong do not match:&#10;    Handwritten type: def (self: classes.ClassWithInvalidCustomStub, foo: builtins.int, bar: builtins.str) -&gt; builtins.str&#10;    Reference type  : def (self: classes.ClassWithInvalidCustomStub, foo: builtins.int, bar: builtins.str) -&gt; builtins.bool" severity="error" /></file><file name="{path}/testing/stubs-handwritten/functions.pyi"><error column="0" line="6" message="&#10;Types for functions.additional_args do not match:&#10;    Handwritten type: def (foo: builtins.int, bar: builtins.int) -&gt; builtins.str&#10;    Reference type  : def (foo: builtins.int) -&gt; builtins.str" severity="error" /><error column="0" line="7" message="&#10;Types for functions.additional_optional_args do not match:&#10;    Handwritten type: def (foo: builtins.int, bar: builtins.int =) -&gt; builtins.str&#10;    Reference type  : def (foo: builtins.int) -&gt; Any" severity="error" /><error column="0" line="9" message="&#10;Types for functions.matching_with_missing_arg_star do not match:&#10;    Handwritten type: def (foo: Any, bar: Any) -&gt; Any&#10;    Reference type  : def (foo: Any, bar: Any, *args: Any) -&gt; Any" severity="error" /><error column="0" line="10" message="&#10;Types for functions.mismatching_with_arg_star do not match:&#10;    Handwritten type: def (foo: builtins.int, *args: Any) -&gt; Any&#10;    Reference type  : def (foo: Any, bar: Any, *args: Any) -&gt; Any" severity="error" /><error column="0" line="11" message="&#10;Types for functions.mismatching_with_additional_arg_star do not match:&#10;    Handwritten type: def (foo: builtins.int, *args: builtins.str) -&gt; Any&#10;    Reference type  : def (foo: Any) -&gt; Any" severity="error" /><error column="0" line="13" message="&#10;Types for functions.matching_with_missing_kwarg_star2 do not match:&#10;    Handwritten type: def (foo: Any, bar: Any) -&gt; Any&#10;    Reference type  : def (foo: Any, bar: Any, **kwargs: Any) -&gt; Any" severity="error" /><error column="0" line="14" message="&#10;Types for functions.mismatching_with_kwarg_star2 do not match:&#10;    Handwritten type: def (foo: builtins.int, **kwargs: Any) -&gt; Any&#10;    Reference type  : def (foo: Any, bar: Any, **kwargs: Any) -&gt; Any" severity="error" /><error column="0" line="15" message="&#10;Types for functions.mismatching_with_additional_kwarg_star2 do not match:&#10;    Handwritten type: def (foo: builtins.int, **kwargs: Any) -&gt; Any&#10;    Reference type  : def (foo: Any) -&gt; Any" severity="error" /><error column="0" line="16" message="&#10;Symbol &quot;functions.missing_function&quot; not found in generated stubs" severity="error" /><error column="0" line="17" message="&#10;Arguments don't match." severity="error" /><error column="0" line="18" message="&#10;Types for functions.mismatching_with_zero_parameters do not match:&#10;    Handwritten type: def (foo: builtins.str) -&gt; Any&#10;    Reference type  : def () -&gt; Any" severity="error" /><error column="1" line="21" message="&#10;Types for functions.overloaded_additional_args do not match:&#10;    Handwritten type: Overload(def (foo: builtins.str, bar: builtins.str) -&gt; builtins.str, def (foo: builtins.int, bar: builtins.int) -&gt; builtins.int)&#10;    Reference type  : Overload(def (foo: builtins.str) -&gt; Any, def (foo: builtins.int, bar: builtins.int) -&gt; Any)" severity="error" /><error column="1" line="25" message="&#10;Types for functions.overloaded_additional_optional_args do not match:&#10;    Handwritten type: Overload(def (foo: builtins.str, bar: builtins.str =) -&gt; builtins.str, def (foo: builtins.int, bar: builtins.int =) -&gt; builtins.int)&#10;    Reference type  : Overload(def (foo: builtins.str) -&gt; Any, def (foo: builtins.int, bar: builtins.int) -&gt; Any)" severity="error" /><error column="1" line="31" message="&#10;Types for functions.decorated_with_additional_args do not match:&#10;    Handwritten type: def (foo: builtins.int, bar: builtins.str) -&gt; builtins.str&#10;    Reference type  : def (foo: Any) -&gt; Any" severity="error" /><error column="1" line="33" message="&#10;Types for functions.decorated_with_additional_optional_args do not match:&#10;    Handwritten type: def (foo: builtins.int, bar: builtins.int =) -&gt; builtins.str&#10;    Reference type  : def (foo: Any) -&gt; Any" severity="error" /></file><file name="{path}/testing/stubs-handwritten/mismatching.pyi"><error column="0" line="1" message="&#10;Types for mismatching.mismatching_function do not match:&#10;    Handwritten type: def (foo: builtins.str) -&gt; Any&#10;    Reference type  : def (foo: builtins.int) -&gt; Any" severity="error" /><error column="0" line="3" message="&#10;Types for mismatching.MISMATCHING_CONSTANT do not match:&#10;    Handwritten type: builtins.str&#10;    Reference type  : builtins.int" severity="error" /><error column="0" line="4" message="&#10;Types for mismatching.mismatch_variable do not match:&#10;    Handwritten type: builtins.int&#10;    Reference type  : builtins.str" severity="error" /><error column="0" line="6" message="&#10;Arguments don't match." severity="error" /></file><file name="{path}/testing/stubs-handwritten/missing.pyi"><error column="0" line="1" message="&#10;Symbol &quot;missing.MISSING_CONSTANT&quot; not found in generated stubs" severity="error" /><error column="0" line="3" message="&#10;Symbol &quot;missing.missing_function&quot; not found in generated stubs" severity="error" /><error column="0" line="5" message="&#10;Symbol &quot;missing.MissingClass&quot; not found in generated stubs" severity="error" /></file><file name="{path}/testing/stubs-handwritten/mypy_node_factory_test_nodes.pyi"><error column="0" line="3" message="&#10;Symbol &quot;mypy_node_factory_test_nodes.not_in_generated&quot; not found in generated stubs" severity="error" /></file><file name="{path}/testing/stubs-handwritten/typevars.pyi"><error column="-1" line="7" message="&#10;Types for typevars.ValuesTypeVarWrongOrder do not match:&#10;    Handwritten type: ValuesTypeVarWrongOrder = TypeVar('ValuesTypeVarWrongOrder', builtins.int, builtins.str, builtins.bool)&#10;    Reference type  : ValuesTypeVarWrongOrder = TypeVar('ValuesTypeVarWrongOrder', builtins.str, builtins.int, builtins.bool)" severity="error" /><error column="-1" line="8" message="&#10;Types for typevars.ValuesTypeVarNoValuesInGenerated do not match:&#10;    Handwritten type: ValuesTypeVarNoValuesInGenerated = TypeVar('ValuesTypeVarNoValuesInGenerated', builtins.int, builtins.str, builtins.bool)&#10;    Reference type  : ValuesTypeVarNoValuesInGenerated = TypeVar('ValuesTypeVarNoValuesInGenerated')" severity="error" /></file><file name="{path}/testing/stubs-handwritten/vars.pyi"><error column="0" line="3" message="&#10;Symbol &quot;vars.any_var&quot; not found in generated stubs" severity="error" /><error column="0" line="4" message="&#10;Symbol &quot;vars.int_var&quot; not found in generated stubs" severity="error" /><error column="0" line="5" message="&#10;Symbol &quot;vars.bool_var&quot; not found in generated stubs" severity="error" /><error column="0" line="6" message="&#10;Symbol &quot;vars.str_var&quot; not found in generated stubs" severity="error" /></file></checkstyle>
\ No newline at end of file
+<checkstyle version="4.3"><file name="{path}/testing/stubs-handwritten/classes.pyi"><error column="4" line="15" message="&#10;Found symbol &quot;classes.ClassWithoutSuperClassInHandwritten.a_method&quot; in different location &quot;classes.AClass.a_method&quot;." severity="error" /><error column="0" line="18" message="&#10;Symbol &quot;classes.MissingClass&quot; not found in generated stubs" severity="error" /><error column="4" line="35" message="&#10;Types for classes.ClassWithInvalidCustomStub.argument_order_wrong do not match:&#10;    Handwritten type: def (self: classes.ClassWithInvalidCustomStub, bar: builtins.str, foo: builtins.int) -&gt; builtins.int&#10;    Reference type  : def (self: classes.ClassWithInvalidCustomStub, foo: Any, bar: Any) -&gt; Any" severity="error" /><error column="4" line="36" message="&#10;Types for classes.ClassWithInvalidCustomStub.argument_names_wrong do not match:&#10;    Handwritten type: def (self: classes.ClassWithInvalidCustomStub, foor: builtins.int, bart: builtins.str) -&gt; builtins.str&#10;    Reference type  : def (self: classes.ClassWithInvalidCustomStub, foo: Any, bar: Any) -&gt; Any" severity="error" /><error column="4" line="37" message="&#10;Types for classes.ClassWithInvalidCustomStub.argument_types_wrong do not match:&#10;    Handwritten type: def (self: classes.ClassWithInvalidCustomStub, foo: builtins.str, bar: builtins.bool) -&gt; builtins.bool&#10;    Reference type  : def (self: classes.ClassWithInvalidCustomStub, foo: builtins.int, bar: builtins.str) -&gt; Any" severity="error" /><error column="4" line="39" message="&#10;Types for classes.ClassWithInvalidCustomStub.return_type_wrong do not match:&#10;    Handwritten type: def (self: classes.ClassWithInvalidCustomStub, foo: builtins.int, bar: builtins.str) -&gt; builtins.str&#10;    Reference type  : def (self: classes.ClassWithInvalidCustomStub, foo: builtins.int, bar: builtins.str) -&gt; builtins.bool" severity="error" /></file><file name="{path}/testing/stubs-handwritten/functions.pyi"><error column="0" line="6" message="&#10;Types for functions.additional_args do not match:&#10;    Handwritten type: def (foo: builtins.int, bar: builtins.int) -&gt; builtins.str&#10;    Reference type  : def (foo: builtins.int) -&gt; builtins.str" severity="error" /><error column="0" line="7" message="&#10;Types for functions.additional_optional_args do not match:&#10;    Handwritten type: def (foo: builtins.int, bar: builtins.int =) -&gt; builtins.str&#10;    Reference type  : def (foo: builtins.int) -&gt; Any" severity="error" /><error column="0" line="9" message="&#10;Types for functions.matching_with_missing_arg_star do not match:&#10;    Handwritten type: def (foo: Any, bar: Any) -&gt; Any&#10;    Reference type  : def (foo: Any, bar: Any, *args: Any) -&gt; Any" severity="error" /><error column="0" line="10" message="&#10;Types for functions.mismatching_with_arg_star do not match:&#10;    Handwritten type: def (foo: builtins.int, *args: Any) -&gt; Any&#10;    Reference type  : def (foo: Any, bar: Any, *args: Any) -&gt; Any" severity="error" /><error column="0" line="11" message="&#10;Types for functions.mismatching_with_additional_arg_star do not match:&#10;    Handwritten type: def (foo: builtins.int, *args: builtins.str) -&gt; Any&#10;    Reference type  : def (foo: Any) -&gt; Any" severity="error" /><error column="0" line="13" message="&#10;Types for functions.matching_with_missing_kwarg_star2 do not match:&#10;    Handwritten type: def (foo: Any, bar: Any) -&gt; Any&#10;    Reference type  : def (foo: Any, bar: Any, **kwargs: Any) -&gt; Any" severity="error" /><error column="0" line="14" message="&#10;Types for functions.mismatching_with_kwarg_star2 do not match:&#10;    Handwritten type: def (foo: builtins.int, **kwargs: Any) -&gt; Any&#10;    Reference type  : def (foo: Any, bar: Any, **kwargs: Any) -&gt; Any" severity="error" /><error column="0" line="15" message="&#10;Types for functions.mismatching_with_additional_kwarg_star2 do not match:&#10;    Handwritten type: def (foo: builtins.int, **kwargs: Any) -&gt; Any&#10;    Reference type  : def (foo: Any) -&gt; Any" severity="error" /><error column="0" line="16" message="&#10;Symbol &quot;functions.missing_function&quot; not found in generated stubs" severity="error" /><error column="0" line="17" message="&#10;Arguments don't match." severity="error" /><error column="0" line="18" message="&#10;Types for functions.mismatching_with_zero_parameters do not match:&#10;    Handwritten type: def (foo: builtins.str) -&gt; Any&#10;    Reference type  : def () -&gt; Any" severity="error" /><error column="1" line="21" message="&#10;Types for functions.overloaded_additional_args do not match:&#10;    Handwritten type: Overload(def (foo: builtins.str, bar: builtins.str) -&gt; builtins.str, def (foo: builtins.int, bar: builtins.int) -&gt; builtins.int)&#10;    Reference type  : Overload(def (foo: builtins.str) -&gt; Any, def (foo: builtins.int, bar: builtins.int) -&gt; Any)" severity="error" /><error column="1" line="25" message="&#10;Types for functions.overloaded_additional_optional_args do not match:&#10;    Handwritten type: Overload(def (foo: builtins.str, bar: builtins.str =) -&gt; builtins.str, def (foo: builtins.int, bar: builtins.int =) -&gt; builtins.int)&#10;    Reference type  : Overload(def (foo: builtins.str) -&gt; Any, def (foo: builtins.int, bar: builtins.int) -&gt; Any)" severity="error" /><error column="1" line="31" message="&#10;Types for functions.decorated_with_additional_args do not match:&#10;    Handwritten type: def (foo: builtins.int, bar: builtins.str) -&gt; builtins.str&#10;    Reference type  : def (foo: Any) -&gt; Any" severity="error" /><error column="1" line="33" message="&#10;Types for functions.decorated_with_additional_optional_args do not match:&#10;    Handwritten type: def (foo: builtins.int, bar: builtins.int =) -&gt; builtins.str&#10;    Reference type  : def (foo: Any) -&gt; Any" severity="error" /></file><file name="{path}/testing/stubs-handwritten/mismatching.pyi"><error column="0" line="1" message="&#10;Types for mismatching.mismatching_function do not match:&#10;    Handwritten type: def (foo: builtins.str) -&gt; Any&#10;    Reference type  : def (foo: builtins.int) -&gt; Any" severity="error" /><error column="0" line="3" message="&#10;Types for mismatching.MISMATCHING_CONSTANT do not match:&#10;    Handwritten type: builtins.str&#10;    Reference type  : builtins.int" severity="error" /><error column="0" line="4" message="&#10;Types for mismatching.mismatch_variable do not match:&#10;    Handwritten type: builtins.int&#10;    Reference type  : builtins.str" severity="error" /><error column="0" line="6" message="&#10;Arguments don't match." severity="error" /></file><file name="{path}/testing/stubs-handwritten/missing.pyi"><error column="0" line="1" message="&#10;Symbol &quot;missing.MISSING_CONSTANT&quot; not found in generated stubs" severity="error" /><error column="0" line="3" message="&#10;Symbol &quot;missing.missing_function&quot; not found in generated stubs" severity="error" /><error column="0" line="5" message="&#10;Symbol &quot;missing.MissingClass&quot; not found in generated stubs" severity="error" /></file><file name="{path}/testing/stubs-handwritten/mypy_node_factory_test_nodes.pyi"><error column="0" line="3" message="&#10;Symbol &quot;mypy_node_factory_test_nodes.not_in_generated&quot; not found in generated stubs" severity="error" /></file><file name="{path}/testing/stubs-handwritten/typevars.pyi"><error column="-1" line="7" message="&#10;Types for typevars.ValuesTypeVarWrongOrder do not match:&#10;    Handwritten type: ValuesTypeVarWrongOrder = TypeVar('ValuesTypeVarWrongOrder', builtins.int, builtins.str, builtins.bool)&#10;    Reference type  : ValuesTypeVarWrongOrder = TypeVar('ValuesTypeVarWrongOrder', builtins.str, builtins.int, builtins.bool)" severity="error" /><error column="-1" line="8" message="&#10;Types for typevars.ValuesTypeVarNoValuesInGenerated do not match:&#10;    Handwritten type: ValuesTypeVarNoValuesInGenerated = TypeVar('ValuesTypeVarNoValuesInGenerated', builtins.int, builtins.str, builtins.bool)&#10;    Reference type  : ValuesTypeVarNoValuesInGenerated = TypeVar('ValuesTypeVarNoValuesInGenerated')" severity="error" /></file><file name="{path}/testing/stubs-handwritten/vars.pyi"><error column="0" line="3" message="&#10;Symbol &quot;vars.any_var&quot; not found in generated stubs" severity="error" /><error column="0" line="4" message="&#10;Symbol &quot;vars.int_var&quot; not found in generated stubs" severity="error" /><error column="0" line="5" message="&#10;Symbol &quot;vars.bool_var&quot; not found in generated stubs" severity="error" /><error column="0" line="6" message="&#10;Symbol &quot;vars.str_var&quot; not found in generated stubs" severity="error" /></file></checkstyle>