Browse Source

Use mypy to do static type checking

python3 includes support for optional type annotations which can be used by
static analysis tools to perform type checking. The mypy tool is a
static type checking tool that can also infer type information in many
cases, but which will use explicit type information if it is present.

Add mypy to test-requirements and to the pep8 job so that our pep8 job
can do more analysis work and less with the code style.

To support this, there were a few places in the current codebase that
needed an explicit type hint. For variables/attributes in 3.5 this is done via
comments. There is a conditional import that was confusion that just got
marked with an 'ignore'.

Our ansible action and lookup plugins confuse mypi with the way they
import the ansible base classes. That's ok - they confuse us with that
too. The .pyi files are 'typeshed' files, which are a way that one can
provide static type annotations without putting the information into the
file itself. mypy will always prefer a .pyi file over a .py file (since
the point of them is to be external annotion/interface description) So
in order to get mypy to not barf on the ansible import weirdness, just
add a corresponding empty .pyi file. We could potentially actually put
interface descriptions in them - but I don't think there is very much
value in that.

It should be amusing to at least someone that we have to flake8: noqa
an import from typing that was done to provide a type hint in a comment.

Change-Id: I6c4ac3dcfc6fd990e6c6886749de147ad28389d1
changes/61/488161/1
Monty Taylor 5 years ago
parent
commit
fb8f5a44bd
No known key found for this signature in database
GPG Key ID: 7BAE94BC7141A594
  1. 1
      test-requirements.txt
  2. 8
      tox.ini
  3. 0
      zuul/ansible/action/add_host.pyi
  4. 0
      zuul/ansible/action/asa_config.pyi
  5. 0
      zuul/ansible/action/asa_template.pyi
  6. 0
      zuul/ansible/action/assemble.pyi
  7. 0
      zuul/ansible/action/copy.pyi
  8. 0
      zuul/ansible/action/dellos10_config.pyi
  9. 0
      zuul/ansible/action/dellos6_config.pyi
  10. 0
      zuul/ansible/action/dellos9_config.pyi
  11. 0
      zuul/ansible/action/eos_config.pyi
  12. 0
      zuul/ansible/action/eos_template.pyi
  13. 0
      zuul/ansible/action/fetch.pyi
  14. 0
      zuul/ansible/action/include_vars.pyi
  15. 0
      zuul/ansible/action/ios_config.pyi
  16. 0
      zuul/ansible/action/ios_template.pyi
  17. 0
      zuul/ansible/action/iosxr_config.pyi
  18. 0
      zuul/ansible/action/iosxr_template.pyi
  19. 0
      zuul/ansible/action/junos_config.pyi
  20. 0
      zuul/ansible/action/junos_template.pyi
  21. 0
      zuul/ansible/action/net_config.pyi
  22. 0
      zuul/ansible/action/net_template.pyi
  23. 0
      zuul/ansible/action/network.pyi
  24. 0
      zuul/ansible/action/normal.pyi
  25. 0
      zuul/ansible/action/nxos_config.pyi
  26. 0
      zuul/ansible/action/nxos_template.pyi
  27. 0
      zuul/ansible/action/ops_config.pyi
  28. 0
      zuul/ansible/action/ops_template.pyi
  29. 0
      zuul/ansible/action/patch.pyi
  30. 0
      zuul/ansible/action/script.pyi
  31. 0
      zuul/ansible/action/sros_config.pyi
  32. 0
      zuul/ansible/action/synchronize.pyi
  33. 0
      zuul/ansible/action/template.pyi
  34. 0
      zuul/ansible/action/unarchive.pyi
  35. 0
      zuul/ansible/action/vyos_config.pyi
  36. 0
      zuul/ansible/action/win_copy.pyi
  37. 0
      zuul/ansible/action/win_template.pyi
  38. 0
      zuul/ansible/lookup/_banned.pyi
  39. 0
      zuul/ansible/lookup/consul_kv.pyi
  40. 0
      zuul/ansible/lookup/credstash.pyi
  41. 0
      zuul/ansible/lookup/csvfile.pyi
  42. 0
      zuul/ansible/lookup/dig.pyi
  43. 0
      zuul/ansible/lookup/dnstxt.pyi
  44. 0
      zuul/ansible/lookup/env.pyi
  45. 0
      zuul/ansible/lookup/etcd.pyi
  46. 0
      zuul/ansible/lookup/file.pyi
  47. 0
      zuul/ansible/lookup/fileglob.pyi
  48. 0
      zuul/ansible/lookup/filetree.pyi
  49. 0
      zuul/ansible/lookup/first_found.pyi
  50. 0
      zuul/ansible/lookup/hashi_valut.pyi
  51. 0
      zuul/ansible/lookup/ini.pyi
  52. 0
      zuul/ansible/lookup/keyring.pyi
  53. 0
      zuul/ansible/lookup/lastpass.pyi
  54. 0
      zuul/ansible/lookup/lines.pyi
  55. 0
      zuul/ansible/lookup/mongodb.pyi
  56. 0
      zuul/ansible/lookup/password.pyi
  57. 0
      zuul/ansible/lookup/passwordstore.pyi
  58. 0
      zuul/ansible/lookup/pipe.pyi
  59. 0
      zuul/ansible/lookup/redis_kv.pyi
  60. 0
      zuul/ansible/lookup/shelvefile.pyi
  61. 0
      zuul/ansible/lookup/template.pyi
  62. 0
      zuul/ansible/lookup/url.pyi
  63. 2
      zuul/driver/__init__.py
  64. 4
      zuul/driver/bubblewrap/__init__.py
  65. 3
      zuul/lib/yamlutil.py

1
test-requirements.txt

@ -14,3 +14,4 @@ sphinxcontrib-programoutput
oslosphinx
mock
PyMySQL
mypy

8
tox.ini

@ -27,8 +27,12 @@ deps = bindep
commands = bindep test
[testenv:pep8]
# streamer is python3 only, so we need to run flake8 in python3
commands = flake8 {posargs}
# --ignore-missing-imports tells mypy to not try to follow imported modules
# out of the current tree. As you might expect, we don't want to run static
# type checking on the world - just on ourselves.
commands =
flake8 {posargs}
mypy --ignore-missing-imports zuul
[testenv:cover]
commands =

0
zuul/ansible/action/add_host.pyi

0
zuul/ansible/action/asa_config.pyi

0
zuul/ansible/action/asa_template.pyi

0
zuul/ansible/action/assemble.pyi

0
zuul/ansible/action/copy.pyi

0
zuul/ansible/action/dellos10_config.pyi

0
zuul/ansible/action/dellos6_config.pyi

0
zuul/ansible/action/dellos9_config.pyi

0
zuul/ansible/action/eos_config.pyi

0
zuul/ansible/action/eos_template.pyi

0
zuul/ansible/action/fetch.pyi

0
zuul/ansible/action/include_vars.pyi

0
zuul/ansible/action/ios_config.pyi

0
zuul/ansible/action/ios_template.pyi

0
zuul/ansible/action/iosxr_config.pyi

0
zuul/ansible/action/iosxr_template.pyi

0
zuul/ansible/action/junos_config.pyi

0
zuul/ansible/action/junos_template.pyi

0
zuul/ansible/action/net_config.pyi

0
zuul/ansible/action/net_template.pyi

0
zuul/ansible/action/network.pyi

0
zuul/ansible/action/normal.pyi

0
zuul/ansible/action/nxos_config.pyi

0
zuul/ansible/action/nxos_template.pyi

0
zuul/ansible/action/ops_config.pyi

0
zuul/ansible/action/ops_template.pyi

0
zuul/ansible/action/patch.pyi

0
zuul/ansible/action/script.pyi

0
zuul/ansible/action/sros_config.pyi

0
zuul/ansible/action/synchronize.pyi

0
zuul/ansible/action/template.pyi

0
zuul/ansible/action/unarchive.pyi

0
zuul/ansible/action/vyos_config.pyi

0
zuul/ansible/action/win_copy.pyi

0
zuul/ansible/action/win_template.pyi

0
zuul/ansible/lookup/_banned.pyi

0
zuul/ansible/lookup/consul_kv.pyi

0
zuul/ansible/lookup/credstash.pyi

0
zuul/ansible/lookup/csvfile.pyi

0
zuul/ansible/lookup/dig.pyi

0
zuul/ansible/lookup/dnstxt.pyi

0
zuul/ansible/lookup/env.pyi

0
zuul/ansible/lookup/etcd.pyi

0
zuul/ansible/lookup/file.pyi

0
zuul/ansible/lookup/fileglob.pyi

0
zuul/ansible/lookup/filetree.pyi

0
zuul/ansible/lookup/first_found.pyi

0
zuul/ansible/lookup/hashi_valut.pyi

0
zuul/ansible/lookup/ini.pyi

0
zuul/ansible/lookup/keyring.pyi

0
zuul/ansible/lookup/lastpass.pyi

0
zuul/ansible/lookup/lines.pyi

0
zuul/ansible/lookup/mongodb.pyi

0
zuul/ansible/lookup/password.pyi

0
zuul/ansible/lookup/passwordstore.pyi

0
zuul/ansible/lookup/pipe.pyi

0
zuul/ansible/lookup/redis_kv.pyi

0
zuul/ansible/lookup/shelvefile.pyi

0
zuul/ansible/lookup/template.pyi

0
zuul/ansible/lookup/url.pyi

2
zuul/driver/__init__.py

@ -33,7 +33,7 @@ class Driver(object, metaclass=abc.ABCMeta):
The class or instance attribute **name** must be provided as a string.
"""
name = None
name = None # type: str
def reconfigure(self, tenant):
"""Called when a tenant is reconfigured.

4
zuul/driver/bubblewrap/__init__.py

@ -23,6 +23,8 @@ import shlex
import subprocess
import sys
from typing import Dict, List # flake8: noqa
from zuul.driver import (Driver, WrapperInterface)
@ -70,7 +72,7 @@ class BubblewrapDriver(Driver, WrapperInterface):
name = 'bubblewrap'
log = logging.getLogger("zuul.BubblewrapDriver")
mounts_map = {'rw': [], 'ro': []}
mounts_map = {'rw': [], 'ro': []} # type: Dict[str, List]
def __init__(self):
self.bwrap_command = self._bwrap_command()

3
zuul/lib/yamlutil.py

@ -13,7 +13,8 @@ import yaml
from yaml import YAMLObject, YAMLError # noqa: F401
try:
from yaml import cyaml
# Explicit type ignore to deal with provisional import failure
from yaml import cyaml # type: ignore
import _yaml
SafeLoader = cyaml.CSafeLoader
SafeDumper = cyaml.CSafeDumper

Loading…
Cancel
Save