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
This commit is contained in:
Eric Harney 2020-05-18 16:58:16 -04:00
parent 2ce35aa94b
commit 6e53c264b6
17 changed files with 170 additions and 0 deletions

1
.gitignore vendored
View File

@ -27,6 +27,7 @@ instances
keeper keeper
keys keys
local_settings.py local_settings.py
mypy-report
tools/lintstack.head.py tools/lintstack.head.py
tools/pylint_exceptions tools/pylint_exceptions
tags tags

View File

@ -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 *

View File

@ -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): ...

View File

@ -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): ...

View File

@ -0,0 +1,4 @@
# Stubs for oslo_i18n._i18n (Python 3)
#
# NOTE: This dynamically typed stub was automatically generated by stubgen.

View File

@ -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: ...

View File

@ -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): ...

View File

@ -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): ...

View File

@ -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] = ...): ...

View File

@ -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): ...

View File

@ -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: ...

View File

@ -52,6 +52,7 @@ Mako==1.0.7
MarkupSafe==1.1.0 MarkupSafe==1.1.0
mock==2.0.0 mock==2.0.0
msgpack==0.5.6 msgpack==0.5.6
mypy==0.761
netaddr==0.7.19 netaddr==0.7.19
netifaces==0.10.7 netifaces==0.10.7
networkx==2.1.0 networkx==2.1.0

3
mypy-files.txt Normal file
View File

@ -0,0 +1,3 @@
cinder/i18n.py
cinder/manager.py
cinder/volume/__init__.py

View File

@ -117,3 +117,15 @@ storpool =
datera = datera =
dfs-sdk>=1.2.25 # Apache-2.0 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

View File

@ -23,3 +23,5 @@ bandit==1.6.0 # Apache-2.0
doc8>=0.6.0 # Apache-2.0 doc8>=0.6.0 # Apache-2.0
reno>=3.1.0 # Apache-2.0 reno>=3.1.0 # Apache-2.0
Pygments>=2.2.0 # BSD license Pygments>=2.2.0 # BSD license
mypy>=0.761 # MIT

24
tools/mypywrap.sh Normal file
View File

@ -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

View File

@ -169,6 +169,13 @@ deps = bindep
commands = bindep {posargs} commands = bindep {posargs}
usedevelop = False usedevelop = False
[testenv:mypy]
description =
Run type checks.
envdir = {toxworkdir}/pep8
commands =
bash tools/mypywrap.sh {posargs}
[flake8] [flake8]
# Following checks are ignored on purpose. # Following checks are ignored on purpose.
# #