From 6e53c264b60e475344010d0aa16a4c703aa640e5 Mon Sep 17 00:00:00 2001 From: Eric Harney Date: Mon, 18 May 2020 16:58:16 -0400 Subject: [PATCH] Add mypy tox env Add a "mypy" tox environment which runs mypy type checking against Cinder code. Taken from Stephen Finucane's Nova work at https://review.opendev.org/#/c/676208/ Added "show_error_codes" and "pretty" options. Generates an html report in ./mypy-report/ This adds stubs for oslo.i18n, so that _() calls are annotated as intended. It may be possible to do this with less .pyi files carried along here. Change-Id: I2589d22c1f16f2e177d34730a520591743c0c1e3 --- .gitignore | 1 + cinder/tests/stubs/oslo_i18n/__init__.pyi | 8 +++++ cinder/tests/stubs/oslo_i18n/_factory.pyi | 24 +++++++++++++++ .../tests/stubs/oslo_i18n/_gettextutils.pyi | 8 +++++ cinder/tests/stubs/oslo_i18n/_i18n.pyi | 4 +++ cinder/tests/stubs/oslo_i18n/_lazy.pyi | 5 ++++ cinder/tests/stubs/oslo_i18n/_locale.pyi | 7 +++++ cinder/tests/stubs/oslo_i18n/_message.pyi | 16 ++++++++++ cinder/tests/stubs/oslo_i18n/_translate.pyi | 7 +++++ cinder/tests/stubs/oslo_i18n/fixture.pyi | 29 +++++++++++++++++++ cinder/tests/stubs/oslo_i18n/log.pyi | 12 ++++++++ lower-constraints.txt | 1 + mypy-files.txt | 3 ++ setup.cfg | 12 ++++++++ test-requirements.txt | 2 ++ tools/mypywrap.sh | 24 +++++++++++++++ tox.ini | 7 +++++ 17 files changed, 170 insertions(+) create mode 100644 cinder/tests/stubs/oslo_i18n/__init__.pyi create mode 100644 cinder/tests/stubs/oslo_i18n/_factory.pyi create mode 100644 cinder/tests/stubs/oslo_i18n/_gettextutils.pyi create mode 100644 cinder/tests/stubs/oslo_i18n/_i18n.pyi create mode 100644 cinder/tests/stubs/oslo_i18n/_lazy.pyi create mode 100644 cinder/tests/stubs/oslo_i18n/_locale.pyi create mode 100644 cinder/tests/stubs/oslo_i18n/_message.pyi create mode 100644 cinder/tests/stubs/oslo_i18n/_translate.pyi create mode 100644 cinder/tests/stubs/oslo_i18n/fixture.pyi create mode 100644 cinder/tests/stubs/oslo_i18n/log.pyi create mode 100644 mypy-files.txt create mode 100644 tools/mypywrap.sh diff --git a/.gitignore b/.gitignore index 0ea6038a867..b0a6235af1a 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ instances keeper keys local_settings.py +mypy-report tools/lintstack.head.py tools/pylint_exceptions tags diff --git a/cinder/tests/stubs/oslo_i18n/__init__.pyi b/cinder/tests/stubs/oslo_i18n/__init__.pyi new file mode 100644 index 00000000000..06b03b2b1e3 --- /dev/null +++ b/cinder/tests/stubs/oslo_i18n/__init__.pyi @@ -0,0 +1,8 @@ +# Stubs for oslo_i18n (Python 3) +# +# NOTE: This dynamically typed stub was automatically generated by stubgen. + +from ._factory import * +from ._gettextutils import * +from ._lazy import * +from ._translate import * diff --git a/cinder/tests/stubs/oslo_i18n/_factory.pyi b/cinder/tests/stubs/oslo_i18n/_factory.pyi new file mode 100644 index 00000000000..d1feed6939d --- /dev/null +++ b/cinder/tests/stubs/oslo_i18n/_factory.pyi @@ -0,0 +1,24 @@ +# Stubs for oslo_i18n._factory (Python 3) +# +# NOTE: This dynamically typed stub was automatically generated by stubgen. + +from typing import Any, Optional + +class TranslatorFactory: + domain: Any = ... + localedir: Any = ... + def __init__(self, domain: Any, localedir: Optional[Any] = ...) -> None: ... + @property + def primary(self) -> ty.Callable[str]: ... + @property + def contextual_form(self): ... + @property + def plural_form(self): ... + @property + def log_info(self): ... + @property + def log_warning(self): ... + @property + def log_error(self): ... + @property + def log_critical(self): ... diff --git a/cinder/tests/stubs/oslo_i18n/_gettextutils.pyi b/cinder/tests/stubs/oslo_i18n/_gettextutils.pyi new file mode 100644 index 00000000000..0d4a3487eb0 --- /dev/null +++ b/cinder/tests/stubs/oslo_i18n/_gettextutils.pyi @@ -0,0 +1,8 @@ +# Stubs for oslo_i18n._gettextutils (Python 3) +# +# NOTE: This dynamically typed stub was automatically generated by stubgen. + +from typing import Any + +def install(domain: Any) -> None: ... +def get_available_languages(domain: Any): ... diff --git a/cinder/tests/stubs/oslo_i18n/_i18n.pyi b/cinder/tests/stubs/oslo_i18n/_i18n.pyi new file mode 100644 index 00000000000..a6eb46889ae --- /dev/null +++ b/cinder/tests/stubs/oslo_i18n/_i18n.pyi @@ -0,0 +1,4 @@ +# Stubs for oslo_i18n._i18n (Python 3) +# +# NOTE: This dynamically typed stub was automatically generated by stubgen. + diff --git a/cinder/tests/stubs/oslo_i18n/_lazy.pyi b/cinder/tests/stubs/oslo_i18n/_lazy.pyi new file mode 100644 index 00000000000..694e3e586be --- /dev/null +++ b/cinder/tests/stubs/oslo_i18n/_lazy.pyi @@ -0,0 +1,5 @@ +# Stubs for oslo_i18n._lazy (Python 3) +# +# NOTE: This dynamically typed stub was automatically generated by stubgen. + +def enable_lazy(enable: bool = ...) -> None: ... diff --git a/cinder/tests/stubs/oslo_i18n/_locale.pyi b/cinder/tests/stubs/oslo_i18n/_locale.pyi new file mode 100644 index 00000000000..6d1562a80db --- /dev/null +++ b/cinder/tests/stubs/oslo_i18n/_locale.pyi @@ -0,0 +1,7 @@ +# Stubs for oslo_i18n._locale (Python 3) +# +# NOTE: This dynamically typed stub was automatically generated by stubgen. + +from typing import Any + +def get_locale_dir_variable_name(domain: Any): ... diff --git a/cinder/tests/stubs/oslo_i18n/_message.pyi b/cinder/tests/stubs/oslo_i18n/_message.pyi new file mode 100644 index 00000000000..f5f380c69ba --- /dev/null +++ b/cinder/tests/stubs/oslo_i18n/_message.pyi @@ -0,0 +1,16 @@ +# Stubs for oslo_i18n._message (Python 3) +# +# NOTE: This dynamically typed stub was automatically generated by stubgen. + +import six +from typing import Any, Optional + +CONTEXT_SEPARATOR: str +LOG: Any + +class Message(six.text_type): + def __new__(cls, msgid: Any, msgtext: Optional[Any] = ..., params: Optional[Any] = ..., domain: str = ..., has_contextual_form: bool = ..., has_plural_form: bool = ..., *args: Any): ... + def translation(self, desired_locale: Optional[Any] = ...): ... + def __mod__(self, other: Any): ... + def __add__(self, other: Any) -> None: ... + def __radd__(self, other: Any): ... diff --git a/cinder/tests/stubs/oslo_i18n/_translate.pyi b/cinder/tests/stubs/oslo_i18n/_translate.pyi new file mode 100644 index 00000000000..7ae7f026abe --- /dev/null +++ b/cinder/tests/stubs/oslo_i18n/_translate.pyi @@ -0,0 +1,7 @@ +# Stubs for oslo_i18n._translate (Python 3) +# +# NOTE: This dynamically typed stub was automatically generated by stubgen. + +from typing import Any, Optional + +def translate(obj: Any, desired_locale: Optional[Any] = ...): ... diff --git a/cinder/tests/stubs/oslo_i18n/fixture.pyi b/cinder/tests/stubs/oslo_i18n/fixture.pyi new file mode 100644 index 00000000000..238cb71e9f3 --- /dev/null +++ b/cinder/tests/stubs/oslo_i18n/fixture.pyi @@ -0,0 +1,29 @@ +# Stubs for oslo_i18n.fixture (Python 3) +# +# NOTE: This dynamically typed stub was automatically generated by stubgen. + +import fixtures +import gettext +from typing import Any, Optional + +class Translation(fixtures.Fixture): + domain: Any = ... + def __init__(self, domain: str = ...) -> None: ... + def lazy(self, msg: Any): ... + def immediate(self, msg: Any): ... + +class ToggleLazy(fixtures.Fixture): + def __init__(self, enabled: Any) -> None: ... + def setUp(self) -> None: ... + +class _PrefixTranslator(gettext.NullTranslations): + prefix: Any = ... + def __init__(self, fp: Optional[Any] = ..., prefix: str = ...) -> None: ... + def gettext(self, message: Any): ... + def ugettext(self, message: Any): ... + +class PrefixLazyTranslation(fixtures.Fixture): + languages: Any = ... + locale: Any = ... + def __init__(self, languages: Optional[Any] = ..., locale: Optional[Any] = ...) -> None: ... + def setUp(self): ... diff --git a/cinder/tests/stubs/oslo_i18n/log.pyi b/cinder/tests/stubs/oslo_i18n/log.pyi new file mode 100644 index 00000000000..92255b664d4 --- /dev/null +++ b/cinder/tests/stubs/oslo_i18n/log.pyi @@ -0,0 +1,12 @@ +# Stubs for oslo_i18n.log (Python 3) +# +# NOTE: This dynamically typed stub was automatically generated by stubgen. + +from logging import handlers +from typing import Any, Optional + +class TranslationHandler(handlers.MemoryHandler): + locale: Any = ... + def __init__(self, locale: Optional[Any] = ..., target: Optional[Any] = ...) -> None: ... + def setFormatter(self, fmt: Any) -> None: ... + def emit(self, record: Any) -> None: ... diff --git a/lower-constraints.txt b/lower-constraints.txt index a78b8ac9ae1..30848e553e9 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -52,6 +52,7 @@ Mako==1.0.7 MarkupSafe==1.1.0 mock==2.0.0 msgpack==0.5.6 +mypy==0.761 netaddr==0.7.19 netifaces==0.10.7 networkx==2.1.0 diff --git a/mypy-files.txt b/mypy-files.txt new file mode 100644 index 00000000000..272d7908218 --- /dev/null +++ b/mypy-files.txt @@ -0,0 +1,3 @@ +cinder/i18n.py +cinder/manager.py +cinder/volume/__init__.py diff --git a/setup.cfg b/setup.cfg index a2b1a6b1067..bd89ec332de 100644 --- a/setup.cfg +++ b/setup.cfg @@ -117,3 +117,15 @@ storpool = datera = dfs-sdk>=1.2.25 # Apache-2.0 + +[mypy] +show_column_numbers = true +show_error_context = true +ignore_missing_imports = true +follow_imports = skip +incremental = true +check_untyped_defs = true +warn_unused_ignores = true +show_error_codes = true +pretty = true +html_report = mypy-report diff --git a/test-requirements.txt b/test-requirements.txt index 251ba522c58..184368f2187 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -23,3 +23,5 @@ bandit==1.6.0 # Apache-2.0 doc8>=0.6.0 # Apache-2.0 reno>=3.1.0 # Apache-2.0 Pygments>=2.2.0 # BSD license + +mypy>=0.761 # MIT diff --git a/tools/mypywrap.sh b/tools/mypywrap.sh new file mode 100644 index 00000000000..0b4c51e6189 --- /dev/null +++ b/tools/mypywrap.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# +# A wrapper around mypy that allows us to specify what files to run 'mypy' type +# checks on. Intended to be invoked via tox: +# +# tox -e mypy +# +# Eventually this should go away once we have either converted everything or +# converted enough and ignored [1] the rest. +# +# [1] http://mypy.readthedocs.io/en/latest/config_file.html#per-module-flags + +ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +export MYPYPATH=$ROOT_DIR/../cinder/tests/stubs/ + +if [ $# -eq 0 ]; then + # if no arguments provided, use the standard converted lists + lines=$(grep -v '#' $ROOT_DIR/../mypy-files.txt) + python -m mypy ${lines[@]} +else + # else test what the user asked us to + python -m mypy $@ +fi diff --git a/tox.ini b/tox.ini index 6e99f1e1610..e6b07239f9d 100644 --- a/tox.ini +++ b/tox.ini @@ -169,6 +169,13 @@ deps = bindep commands = bindep {posargs} usedevelop = False +[testenv:mypy] +description = + Run type checks. +envdir = {toxworkdir}/pep8 +commands = + bash tools/mypywrap.sh {posargs} + [flake8] # Following checks are ignored on purpose. #