]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
tests: Add support for linting and formatting of Python code
authorDaniel Wagner <dwagner@suse.de>
Thu, 3 Mar 2022 17:31:44 +0000 (18:31 +0100)
committerDaniel Wagner <dwagner@suse.de>
Thu, 3 Mar 2022 17:44:28 +0000 (18:44 +0100)
Shamelessly steal the linting and formatting tooling for Python code
form python-sdbus. Update the documentation accordingly.

Link: https://github.com/python-sdbus/python-sdbus
Signed-off-by: Daniel Wagner <dwagner@suse.de>
tests/README
tests/meson.build
tests/run_py_linters.py [new file with mode: 0644]

index 686bd04557d318fbfc9868e2f1e5ed2ead2cdfb7..53ffc592f24af4f63aa8173af74c0f9aeeaad470 100644 (file)
@@ -11,18 +11,16 @@ nvmetests
 1. Common Package Dependencies
 ------------------------------
 
-    1. Python(>= 2.7.5 or >= 3.3)
-    2. nose(http://nose.readthedocs.io/en/latest/)
-    3. nose2(Installation guide http://nose2.readthedocs.io/)
-    4. pep8(https://pypi.python.org/pypi/setuptools-pep8)
-    5. flake8(https://pypi.python.org/pypi/flake8)
-    6. pylint(https://www.pylint.org/)
-    7. Epydoc(http://epydoc.sourceforge.net/)
-    8. nvme-cli(https://github.com/linux-nvme/nvme-cli.git)
+    1. Python(>= 3.3)
+    2. nose2 (Installation guide http://nose2.readthedocs.io/)
+    3. flake8 (https://pypi.python.org/pypi/flake8)
+    4. mypy (https://pypi.org/project/mypy/)
+    5. autopep8 (https://pypi.org/project/autopep8/)
+    6. isort (https://pypi.org/project/isort/)
 
     Python package management system pip can be used to install most of the
     listed packages(https://pip.pypa.io/en/stable/installing/) :-
-    $ pip install nose nose2 pep8 flake8 pylint epydoc
+    $ pip install nose2 flake8 mypy autopep8 isort
 
 2. Overview
 -----------
@@ -76,12 +74,12 @@ nvmetests
     6. Before writing a new function have a look into TestNVMe to see if it
        can be reused.
     7. Once testcase is ready make sure :-
-           a. Run pep8, flake8, pylint on the testcase and fix errors/warnings.
-              -Example "$ make static_check" will run pep8, flake8 and pylint on
-              all the python files in current directory.
-           b. Execute make doc to generate the documentation.
-              -Example "$ make doc" will create and update existing
-              documentation.
+           a. Run flake8, mypy, autopep8 and isort on the testcase and fix
+             errors/warnings.
+               - Example "$ ninja -C .build lint-python" will run flake8 and
+                mypy on all the python files in current directory.
+              - Example "$ ninja -C .build fomrat-python" will run autopep8 and
+                isort on all the python files in the current directory.
 
 4. Running testcases with framework
 -----------------------------------
@@ -89,5 +87,5 @@ nvmetests
        $ nose2 --verbose nvme_writezeros_test
        $ nose2 --verbose nvme_read_write_test
 
-    2. Running all the testcases with Makefile :-
-       $ make run
+    2. Running all the testcases with ninja :-
+       $ ninja test -C .build
index 5acf2aafe3d5b7f781ca6e0e877bd2e32678869c..efd3ea8fa4a21d7623db41540355195de495c520 100644 (file)
@@ -30,3 +30,45 @@ if runtests.found()
          timeout: 500)
   endforeach
 endif
+
+python_module = import('python')
+
+python = python_module.find_installation('python3')
+
+mypy = find_program(
+    'mypy',
+    required : false,
+)
+flake8 = find_program(
+    'flake8',
+    required : false,
+)
+linter_script = files('run_py_linters.py')
+
+if mypy.found() and flake8.found()
+    run_target(
+        'lint-python',
+        command : [python, linter_script, 'lint'],
+    )
+else
+    message('Mypy or Flake8 not found. Python linting disabled')
+endif
+
+
+autopep8 = find_program(
+    'autopep8',
+    required : false,
+)
+isort = find_program(
+    'isort',
+    required : false,
+)
+
+if autopep8.found() and isort.found()
+    run_target(
+        'format-python',
+        command : [python, linter_script, 'format'],
+    )
+else
+    message('autopep8 or isort not found. Python formating disabled')
+endif
diff --git a/tests/run_py_linters.py b/tests/run_py_linters.py
new file mode 100644 (file)
index 0000000..869b3e4
--- /dev/null
@@ -0,0 +1,123 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+# Copied from https://github.com/python-sdbus/python-sdbus
+# Copyright (C) 2020, 2021 igo95862
+
+# This file is part of nvme-cli
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+from __future__ import annotations
+
+from argparse import ArgumentParser
+from os import environ
+from pathlib import Path
+from subprocess import run
+from typing import List
+
+source_root = Path(environ['MESON_SOURCE_ROOT'])
+build_dir = Path(environ['MESON_BUILD_ROOT'])
+
+tests_dir = source_root / 'tests'
+
+all_python_modules = [
+    tests_dir,
+]
+
+mypy_cache_dir = build_dir / '.mypy_cache'
+
+
+def run_mypy(path: Path) -> None:
+    print(f"Running mypy on {path}")
+    run(
+        args=(
+            'mypy', '--strict',
+            '--cache-dir', mypy_cache_dir,
+            '--python-version', '3.8',
+            '--namespace-packages',
+            '--ignore-missing-imports',
+            path,
+        ),
+        check=False,
+        env={'MYPYPATH': str(tests_dir.absolute()), **environ},
+    )
+
+
+def linter_main() -> None:
+    run(
+        args=(
+            'flake8',
+            *all_python_modules,
+        ),
+        check=False,
+    )
+
+    for x in all_python_modules:
+        run_mypy(x)
+
+
+def get_all_python_files() -> List[Path]:
+    python_files: List[Path] = []
+
+    for python_module in all_python_modules:
+        if python_module.is_dir():
+            for a_file in python_module.iterdir():
+                if a_file.suffix == '.py':
+                    python_files.append(a_file)
+        else:
+            python_files.append(python_module)
+
+    return python_files
+
+
+def formater_main() -> None:
+    all_python_files = get_all_python_files()
+
+    run(
+        args=('autopep8', '--in-place', *all_python_files),
+        check=False,
+    )
+
+    run(
+        args=(
+            'isort',
+            '-m', 'VERTICAL_HANGING_INDENT',
+            '--trailing-comma',
+            *all_python_files,
+        ),
+        check=False,
+    )
+
+
+def main() -> None:
+    parser = ArgumentParser()
+    parser.add_argument(
+        'mode',
+        choices=('lint', 'format'),
+    )
+
+    args = parser.parse_args()
+
+    mode = args.mode
+
+    if mode == 'lint':
+        linter_main()
+    elif mode == 'format':
+        formater_main()
+    else:
+        raise ValueError('Unknown mode', mode)
+
+
+if __name__ == '__main__':
+    main()