openshift / openshift-ansible

Install and config an OpenShift 3.x cluster
https://try.openshift.com
Apache License 2.0
2.19k stars 2.32k forks source link

Developer workflow for Python code is too slow #3280

Closed rhcarvalho closed 6 years ago

rhcarvalho commented 7 years ago

Re-raising a point for discussion similar to #2933.

Nowadays we're using tox and the CONTRIBUTING.md guide says that one is supposed to use tox or detox to run tests.

It took me more than 10 min (time not tracked scientifically) to run detox locally, and the amount of output is enormous, making it very hard to read what pylint or pyflake or what not is being complained about.

A recent Travis run took 4 min 45 sec. Here is a run with errors, notice the amount a output, over a thousand lines where we need to dig to find the errors.

Objective: discuss ways to to improve both time and amount of output to improve developer experience.

Further notes/questions:

rhcarvalho commented 7 years ago

For future reference:

(env) [vagrant@localhost openshift-ansible]$ date
Wed Feb  8 15:44:06 UTC 2017
(env) [vagrant@localhost openshift-ansible]$ time detox
py27-ansible22-pylint create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-pylint
py27-ansible22-unit create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-unit
py27-ansible22-flake8 create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-flake8
py27-ansible22-yamllint create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-yamllint
py27-ansible22-generate_validation create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-generate_validation
py35-ansible22-pylint create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-pylint
py35-ansible22-unit create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-unit
py35-ansible22-flake8 create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-flake8
py35-ansible22-yamllint create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint
py35-ansible22-generate_validation create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-generate_validation
py27-ansible22-flake8 installdeps: -rtest-requirements.txt, ansible~=2.2
py27-ansible22-pylint installdeps: -rtest-requirements.txt, ansible~=2.2
py27-ansible22-unit installdeps: -rtest-requirements.txt, ansible~=2.2
py27-ansible22-yamllint installdeps: -rtest-requirements.txt, ansible~=2.2
py27-ansible22-generate_validation installdeps: -rtest-requirements.txt, ansible~=2.2
py35-ansible22-flake8 installdeps: -rtest-requirements.txt, flake8-bugbear, ansible~=2.2
py35-ansible22-unit installdeps: -rtest-requirements.txt, ansible~=2.2
py35-ansible22-pylint installdeps: -rtest-requirements.txt, ansible~=2.2
py35-ansible22-yamllint installdeps: -rtest-requirements.txt, ansible~=2.2
py35-ansible22-generate_validation installdeps: -rtest-requirements.txt, ansible~=2.2
ERROR: invocation failed (exit code 2), logfile: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/log/py35-ansible22-yamllint-1.log
ERROR: actionid: py35-ansible22-yamllint
...
************* Module openshift_checks.package_version
roles/openshift_health_checker/openshift_checks/package_version.py:1: [C0111(missing-docstring), ] Missing module docstring
error: lint error 30.

ERROR: InvocationError: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-pylint/bin/python setup.py lint (see /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-pylint/log/py27-ansible22-pylint-2.log)
_______________________________________________ summary _______________________________________________
ERROR:   py27-ansible22-pylint: commands failed
  py27-ansible22-unit: commands succeeded
ERROR:   py27-ansible22-flake8: commands failed
  py27-ansible22-yamllint: commands succeeded
  py27-ansible22-generate_validation: commands succeeded
ERROR:   py35-ansible22-pylint: commands failed
  py35-ansible22-unit: commands succeeded
ERROR:   py35-ansible22-flake8: commands failed
ERROR:   py35-ansible22-yamllint: could not install deps [-rtest-requirements.txt, ansible~=2.2]; v = InvocationError('/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/bin/pip install -rtest-requirements.txt ansible~=2.2 (see /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/log/py35-ansible22-yamllint-1.log)', 2)
  py35-ansible22-generate_validation: commands succeeded

real    10m1.925s
user    5m30.399s
sys     5m42.938s

Over 200 lines of output. Some lint errors in the current branch, apparently some installation errors too.

``` (env) [vagrant@localhost openshift-ansible]$ date Wed Feb 8 15:44:06 UTC 2017 (env) [vagrant@localhost openshift-ansible]$ time detox py27-ansible22-pylint create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-pylint py27-ansible22-unit create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-unit py27-ansible22-flake8 create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-flake8 py27-ansible22-yamllint create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-yamllint py27-ansible22-generate_validation create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-generate_validation py35-ansible22-pylint create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-pylint py35-ansible22-unit create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-unit py35-ansible22-flake8 create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-flake8 py35-ansible22-yamllint create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint py35-ansible22-generate_validation create: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-generate_validation py27-ansible22-flake8 installdeps: -rtest-requirements.txt, ansible~=2.2 py27-ansible22-pylint installdeps: -rtest-requirements.txt, ansible~=2.2 py27-ansible22-unit installdeps: -rtest-requirements.txt, ansible~=2.2 py27-ansible22-yamllint installdeps: -rtest-requirements.txt, ansible~=2.2 py27-ansible22-generate_validation installdeps: -rtest-requirements.txt, ansible~=2.2 py35-ansible22-flake8 installdeps: -rtest-requirements.txt, flake8-bugbear, ansible~=2.2 py35-ansible22-unit installdeps: -rtest-requirements.txt, ansible~=2.2 py35-ansible22-pylint installdeps: -rtest-requirements.txt, ansible~=2.2 py35-ansible22-yamllint installdeps: -rtest-requirements.txt, ansible~=2.2 py35-ansible22-generate_validation installdeps: -rtest-requirements.txt, ansible~=2.2 ERROR: invocation failed (exit code 2), logfile: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/log/py35-ansible22-yamllint-1.log ERROR: actionid: py35-ansible22-yamllint msg: getenv cmdargs: ['/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/bin/pip', 'install', '-rtest-requirements.txt', 'ansible~=2.2'] env: {'GOPATH': '/home/vagrant', 'LESSOPEN': '||/usr/bin/lesspipe.sh %s', 'SSH_CLIENT': '10.0.2.2 60788 22', 'SELINUX_USE_CURRENT_RANGE': '', 'LOGNAME': 'vagrant', 'USER': 'vagrant', 'HOME': '/home/vagrant', 'PATH': '/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/bin:/home/vagrant/env/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/src/github.com/openshift/origin/_output/local/bin/linux/amd64:/home/vagrant/src/github.com/openshift/source-to-image/_output/local/bin/linux/amd64:/home/vagrant/bin:/home/vagrant/.local/bin:/home/vagrant/bin', 'PS1': '(env) [\\u@\\h \\W]\\$ ', 'LANG': 'en_US.UTF-8', 'TERM': 'screen-256color', 'SHELL': '/bin/bash', 'CDPATH': '.:/home/vagrant/src:/home/vagrant/src/github.com/openshift:/home/vagrant/src/github.com/rhcarvalho', 'SHLVL': '1', 'HISTSIZE': '1000', 'PYTHONHASHSEED': '3744639088', 'XMODIFIERS': '@im=ibus', 'XDG_RUNTIME_DIR': '/run/user/1001', 'VIRTUAL_ENV': '/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint', 'SELINUX_ROLE_REQUESTED': '', 'XDG_SESSION_ID': '3', 'DBUS_SESSION_BUS_ADDRESS': 'unix:path=/run/user/1001/bus', '_': '/home/vagrant/env/bin/detox', 'LS_COLORS': 'rs=0:di=38;5;33:ln=38;5;51:mh=00:pi=40;38;5;11:so=38;5;13:do=38;5;5:bd=48;5;232;38;5;11:cd=48;5;232;38;5;3:or=48;5;232;38;5;9:mi=01;05;37;41:su=48;5;196;38;5;15:sg=48;5;11;38;5;16:ca=48;5;196;38;5;226:tw=48;5;10;38;5;16:ow=48;5;10;38;5;21:st=48;5;21;38;5;15:ex=38;5;40:*.tar=38;5;9:*.tgz=38;5;9:*.arc=38;5;9:*.arj=38;5;9:*.taz=38;5;9:*.lha=38;5;9:*.lz4=38;5;9:*.lzh=38;5;9:*.lzma=38;5;9:*.tlz=38;5;9:*.txz=38;5;9:*.tzo=38;5;9:*.t7z=38;5;9:*.zip=38;5;9:*.z=38;5;9:*.Z=38;5;9:*.dz=38;5;9:*.gz=38;5;9:*.lrz=38;5;9:*.lz=38;5;9:*.lzo=38;5;9:*.xz=38;5;9:*.bz2=38;5;9:*.bz=38;5;9:*.tbz=38;5;9:*.tbz2=38;5;9:*.tz=38;5;9:*.deb=38;5;9:*.rpm=38;5;9:*.jar=38;5;9:*.war=38;5;9:*.ear=38;5;9:*.sar=38;5;9:*.rar=38;5;9:*.alz=38;5;9:*.ace=38;5;9:*.zoo=38;5;9:*.cpio=38;5;9:*.7z=38;5;9:*.rz=38;5;9:*.cab=38;5;9:*.jpg=38;5;13:*.jpeg=38;5;13:*.gif=38;5;13:*.bmp=38;5;13:*.pbm=38;5;13:*.pgm=38;5;13:*.ppm=38;5;13:*.tga=38;5;13:*.xbm=38;5;13:*.xpm=38;5;13:*.tif=38;5;13:*.tiff=38;5;13:*.png=38;5;13:*.svg=38;5;13:*.svgz=38;5;13:*.mng=38;5;13:*.pcx=38;5;13:*.mov=38;5;13:*.mpg=38;5;13:*.mpeg=38;5;13:*.m2v=38;5;13:*.mkv=38;5;13:*.webm=38;5;13:*.ogm=38;5;13:*.mp4=38;5;13:*.m4v=38;5;13:*.mp4v=38;5;13:*.vob=38;5;13:*.qt=38;5;13:*.nuv=38;5;13:*.wmv=38;5;13:*.asf=38;5;13:*.rm=38;5;13:*.rmvb=38;5;13:*.flc=38;5;13:*.avi=38;5;13:*.fli=38;5;13:*.flv=38;5;13:*.gl=38;5;13:*.dl=38;5;13:*.xcf=38;5;13:*.xwd=38;5;13:*.yuv=38;5;13:*.cgm=38;5;13:*.emf=38;5;13:*.ogv=38;5;13:*.ogx=38;5;13:*.aac=38;5;45:*.au=38;5;45:*.flac=38;5;45:*.m4a=38;5;45:*.mid=38;5;45:*.midi=38;5;45:*.mka=38;5;45:*.mp3=38;5;45:*.mpc=38;5;45:*.ogg=38;5;45:*.ra=38;5;45:*.wav=38;5;45:*.oga=38;5;45:*.opus=38;5;45:*.spx=38;5;45:*.xspf=38;5;45:', 'SSH_TTY': '/dev/pts/0', 'OLDPWD': '/home/vagrant', 'HOSTNAME': 'localhost.localdomain', 'SELINUX_LEVEL_REQUESTED': '', 'HISTCONTROL': 'ignoredups', 'PWD': '/home/vagrant/src/github.com/openshift/openshift-ansible', 'MAIL': '/var/spool/mail/vagrant', 'SSH_CONNECTION': '10.0.2.2 60788 10.0.2.15 22'} Collecting ansible~=2.2 Requirement already satisfied: six in ./.tox/py35-ansible22-yamllint/lib/python3.5/site-packages (from -r test-requirements.txt (line 1)) Collecting pyOpenSSL (from -r test-requirements.txt (line 2)) Using cached pyOpenSSL-16.2.0-py2.py3-none-any.whl Collecting flake8 (from -r test-requirements.txt (line 3)) Using cached flake8-3.3.0-py2.py3-none-any.whl Collecting flake8-mutable (from -r test-requirements.txt (line 4)) Collecting flake8-print (from -r test-requirements.txt (line 5)) Collecting pylint (from -r test-requirements.txt (line 6)) Using cached pylint-1.6.5-py2.py3-none-any.whl Collecting setuptools-lint (from -r test-requirements.txt (line 7)) Using cached setuptools_lint-0.5.2-py3-none-any.whl Collecting PyYAML (from -r test-requirements.txt (line 8)) Collecting yamllint (from -r test-requirements.txt (line 9)) Using cached yamllint-1.6.0-py2.py3-none-any.whl Collecting nose (from -r test-requirements.txt (line 10)) Using cached nose-1.3.7-py3-none-any.whl Collecting coverage (from -r test-requirements.txt (line 11)) Using cached coverage-4.3.4-cp35-cp35m-manylinux1_x86_64.whl Requirement already satisfied: setuptools in ./.tox/py35-ansible22-yamllint/lib/python3.5/site-packages (from ansible~=2.2) Collecting pycrypto>=2.6 (from ansible~=2.2) Collecting paramiko (from ansible~=2.2) Using cached paramiko-2.1.1-py2.py3-none-any.whl Collecting jinja2<2.9 (from ansible~=2.2) Using cached Jinja2-2.8.1-py2.py3-none-any.whl Collecting cryptography>=1.3.4 (from pyOpenSSL->-r test-requirements.txt (line 2)) Collecting pyflakes<1.6.0,>=1.5.0 (from flake8->-r test-requirements.txt (line 3)) Using cached pyflakes-1.5.0-py2.py3-none-any.whl Collecting mccabe<0.7.0,>=0.6.0 (from flake8->-r test-requirements.txt (line 3)) Using cached mccabe-0.6.1-py2.py3-none-any.whl Collecting pycodestyle<2.4.0,>=2.0.0 (from flake8->-r test-requirements.txt (line 3)) Using cached pycodestyle-2.3.1-py2.py3-none-any.whl Collecting isort>=4.2.5 (from pylint->-r test-requirements.txt (line 6)) Using cached isort-4.2.5-py2.py3-none-any.whl Collecting astroid<1.5.0,>=1.4.5 (from pylint->-r test-requirements.txt (line 6)) Using cached astroid-1.4.9-py2.py3-none-any.whl Requirement already satisfied: packaging>=16.8 in ./.tox/py35-ansible22-yamllint/lib/python3.5/site-packages (from setuptools->ansible~=2.2) Requirement already satisfied: appdirs>=1.4.0 in ./.tox/py35-ansible22-yamllint/lib/python3.5/site-packages (from setuptools->ansible~=2.2) Collecting pyasn1>=0.1.7 (from paramiko->ansible~=2.2) Using cached pyasn1-0.2.2-py2.py3-none-any.whl Collecting MarkupSafe (from jinja2<2.9->ansible~=2.2) Collecting idna>=2.0 (from cryptography>=1.3.4->pyOpenSSL->-r test-requirements.txt (line 2)) Using cached idna-2.2-py2.py3-none-any.whl Collecting cffi>=1.4.1 (from cryptography>=1.3.4->pyOpenSSL->-r test-requirements.txt (line 2)) Using cached cffi-1.9.1-cp35-cp35m-manylinux1_x86_64.whl Collecting wrapt (from astroid<1.5.0,>=1.4.5->pylint->-r test-requirements.txt (line 6)) Collecting lazy-object-proxy (from astroid<1.5.0,>=1.4.5->pylint->-r test-requirements.txt (line 6)) Using cached lazy_object_proxy-1.2.2-cp35-cp35m-manylinux1_x86_64.whl Requirement already satisfied: pyparsing in ./.tox/py35-ansible22-yamllint/lib/python3.5/site-packages (from packaging>=16.8->setuptools->ansible~=2.2) Collecting pycparser (from cffi>=1.4.1->cryptography>=1.3.4->pyOpenSSL->-r test-requirements.txt (line 2)) Installing collected packages: PyYAML, pycrypto, pyasn1, idna, pycparser, cffi, cryptography, paramiko, MarkupSafe, jinja2, ansible, pyOpenSSL, pyflakes, mccabe, pycodestyle, flake8, flake8-mutable, flake8-print, isort, wrapt, lazy-object-proxy, astroid, pylint, setuptools-lint, yamllint, nose, coverage Exception: Traceback (most recent call last): File "/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/lib/python3.5/site-packages/pip/basecommand.py", line 215, in main status = self.run(options, args) File "/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/lib/python3.5/site-packages/pip/commands/install.py", line 342, in run prefix=options.prefix_path, File "/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/lib/python3.5/site-packages/pip/req/req_set.py", line 784, in install **kwargs File "/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/lib/python3.5/site-packages/pip/req/req_install.py", line 851, in install self.move_wheel_files(self.source_dir, root=root, prefix=prefix) File "/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/lib/python3.5/site-packages/pip/req/req_install.py", line 1064, in move_wheel_files isolated=self.isolated, File "/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/lib/python3.5/site-packages/pip/wheel.py", line 345, in move_wheel_files clobber(source, lib_dir, True) File "/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/lib/python3.5/site-packages/pip/wheel.py", line 323, in clobber shutil.copyfile(srcfile, destfile) File "/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/lib64/python3.5/shutil.py", line 115, in copyfile with open(dst, 'wb') as fdst: OSError: [Errno 71] Protocol error: '/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/lib64/python3.5/site-packages/cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-35.pyc' ERROR: could not install deps [-rtest-requirements.txt, ansible~=2.2]; v = InvocationError('/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/bin/pip install -rtest-requirements.txt ansible~=2.2 (see /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/log/py35-ansible22-yamllint-1.log)', 2) py35-ansible22-unit runtests: PYTHONHASHSEED='3744639088' py35-ansible22-unit runtests: commands[0] | nosetests py35-ansible22-flake8 runtests: PYTHONHASHSEED='3744639088' py35-ansible22-flake8 runtests: commands[0] | flake8 py35-ansible22-pylint runtests: PYTHONHASHSEED='3744639088' py35-ansible22-pylint runtests: commands[0] | python setup.py lint py35-ansible22-generate_validation runtests: PYTHONHASHSEED='3744639088' py35-ansible22-generate_validation runtests: commands[0] | python setup.py generate_validation py27-ansible22-flake8 runtests: PYTHONHASHSEED='3744639088' py27-ansible22-flake8 runtests: commands[0] | flake8 py27-ansible22-yamllint runtests: PYTHONHASHSEED='3744639088' py27-ansible22-yamllint runtests: commands[0] | python setup.py yamllint py27-ansible22-generate_validation runtests: PYTHONHASHSEED='3744639088' py27-ansible22-generate_validation runtests: commands[0] | python setup.py generate_validation py27-ansible22-unit runtests: PYTHONHASHSEED='3744639088' py27-ansible22-unit runtests: commands[0] | nosetests py27-ansible22-pylint runtests: PYTHONHASHSEED='3744639088' py27-ansible22-pylint runtests: commands[0] | python setup.py lint ERROR: invocation failed (exit code 1), logfile: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-flake8/log/py35-ansible22-flake8-2.log ERROR: actionid: py35-ansible22-flake8 msg: runtests cmdargs: ['/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-flake8/bin/flake8'] env: {'LANG': 'en_US.UTF-8', 'PATH': '/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-flake8/bin:/home/vagrant/env/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/src/github.com/openshift/origin/_output/local/bin/linux/amd64:/home/vagrant/src/github.com/openshift/source-to-image/_output/local/bin/linux/amd64:/home/vagrant/bin:/home/vagrant/.local/bin:/home/vagrant/bin', 'VIRTUAL_ENV': '/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-flake8', 'PYTHONHASHSEED': '3744639088'} ./roles/openshift_health_checker/action_plugins/openshift_health_check.py:16:1: E402 module level import not at top of file ./roles/openshift_health_checker/action_plugins/openshift_health_check.py:36:29: B306 `BaseException.message` has been deprecated as of Python 2.6 and is removed in Python 3. Use `str(e)` to access the user-readable message. Use `e.args` to access arguments passed to the exception. ./roles/openshift_health_checker/action_plugins/openshift_health_check.py:63:32: B306 `BaseException.message` has been deprecated as of Python 2.6 and is removed in Python 3. Use `str(e)` to access the user-readable message. Use `e.args` to access arguments passed to the exception. ./roles/openshift_health_checker/openshift_checks/__init__.py:20:5: B303 `__metaclass__` does nothing on Python 3. Use `class MyClass(BaseClass, metaclass=...)`. For Python 2 compatibility, use `six.add_metaclass`. ./roles/openshift_health_checker/openshift_checks/mixins.py:11:13: W503 line break before binary operator ERROR: InvocationError: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-flake8/bin/flake8 (see /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-flake8/log/py35-ansible22-flake8-2.log) ERROR: invocation failed (exit code 1), logfile: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-flake8/log/py27-ansible22-flake8-2.log ERROR: actionid: py27-ansible22-flake8 msg: runtests cmdargs: ['/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-flake8/bin/flake8'] env: {'LANG': 'en_US.UTF-8', 'PATH': '/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-flake8/bin:/home/vagrant/env/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/src/github.com/openshift/origin/_output/local/bin/linux/amd64:/home/vagrant/src/github.com/openshift/source-to-image/_output/local/bin/linux/amd64:/home/vagrant/bin:/home/vagrant/.local/bin:/home/vagrant/bin', 'VIRTUAL_ENV': '/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-flake8', 'PYTHONHASHSEED': '3744639088'} ./roles/openshift_health_checker/action_plugins/openshift_health_check.py:16:1: E402 module level import not at top of file ./roles/openshift_health_checker/openshift_checks/mixins.py:11:13: W503 line break before binary operator ERROR: InvocationError: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-flake8/bin/flake8 (see /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-flake8/log/py27-ansible22-flake8-2.log) ERROR: invocation failed (exit code 1), logfile: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-pylint/log/py35-ansible22-pylint-2.log ERROR: actionid: py35-ansible22-pylint msg: runtests cmdargs: ['/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-pylint/bin/python', 'setup.py', 'lint'] env: {'LANG': 'en_US.UTF-8', 'PATH': '/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-pylint/bin:/home/vagrant/env/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/src/github.com/openshift/origin/_output/local/bin/linux/amd64:/home/vagrant/src/github.com/openshift/source-to-image/_output/local/bin/linux/amd64:/home/vagrant/bin:/home/vagrant/.local/bin:/home/vagrant/bin', 'VIRTUAL_ENV': '/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-pylint', 'PYTHONHASHSEED': '3744639088'} running lint ************* Module aos_version roles/openshift_health_checker/library/aos_version.py:17: [R0912(too-many-branches), main] Too many branches (13/12) ************* Module openshift_health_check roles/openshift_health_checker/action_plugins/openshift_health_check.py:1: [C0111(missing-docstring), ] Missing module docstring roles/openshift_health_checker/action_plugins/openshift_health_check.py:16: [C0413(wrong-import-position), ] Import "from openshift_checks import OpenShiftCheck, OpenShiftCheckException" should be placed at the top of the module roles/openshift_health_checker/action_plugins/openshift_health_check.py:19: [C0111(missing-docstring), ActionModule] Missing class docstring roles/openshift_health_checker/action_plugins/openshift_health_check.py:34: [C0103(invalid-name), ActionModule.run] Invalid variable name "e" roles/openshift_health_checker/action_plugins/openshift_health_check.py:36: [E1101(no-member), ActionModule.run] Instance of 'OpenShiftCheckException' has no 'message' member roles/openshift_health_checker/action_plugins/openshift_health_check.py:59: [C0103(invalid-name), ActionModule.run] Invalid variable name "r" roles/openshift_health_checker/action_plugins/openshift_health_check.py:60: [C0103(invalid-name), ActionModule.run] Invalid variable name "e" roles/openshift_health_checker/action_plugins/openshift_health_check.py:61: [C0103(invalid-name), ActionModule.run] Invalid variable name "r" roles/openshift_health_checker/action_plugins/openshift_health_check.py:63: [E1101(no-member), ActionModule.run] Instance of 'OpenShiftCheckException' has no 'message' member roles/openshift_health_checker/action_plugins/openshift_health_check.py:65: [C0103(invalid-name), ActionModule.run] Invalid variable name "r" roles/openshift_health_checker/action_plugins/openshift_health_check.py:75: [C0111(missing-docstring), ActionModule.load_known_checks] Missing method docstring roles/openshift_health_checker/action_plugins/openshift_health_check.py:75: [W0613(unused-argument), ActionModule.load_known_checks] Unused argument 'task_vars' ************* Module openshift_checks roles/openshift_health_checker/openshift_checks/__init__.py:1: [C0111(missing-docstring), ] Missing module docstring roles/openshift_health_checker/openshift_checks/__init__.py:13: [C0111(missing-docstring), OpenShiftCheckException] Missing class docstring roles/openshift_health_checker/openshift_checks/__init__.py:40: [W0613(unused-argument), OpenShiftCheck.is_active] Unused argument 'task_vars' roles/openshift_health_checker/openshift_checks/__init__.py:52: [E1101(no-member), OpenShiftCheck.subclasses] Class 'OpenShiftCheck' has no '__subclasses__' member roles/openshift_health_checker/openshift_checks/__init__.py:76: [C0103(invalid-name), ] Invalid constant name "excludes" ************* Module openshift_checks.mixins roles/openshift_health_checker/openshift_checks/mixins.py:1: [C0111(missing-docstring), ] Missing module docstring roles/openshift_health_checker/openshift_checks/mixins.py:8: [C0111(missing-docstring), NotContainerized.is_active] Missing method docstring roles/openshift_health_checker/openshift_checks/mixins.py:10: [E1101(no-member), NotContainerized.is_active] Super of 'NotContainerized' has no 'is_active' member roles/openshift_health_checker/openshift_checks/mixins.py:15: [C0111(missing-docstring), NotContainerized.is_containerized] Missing method docstring ************* Module openshift_checks.package_availability roles/openshift_health_checker/openshift_checks/package_availability.py:1: [C0111(missing-docstring), ] Missing module docstring roles/openshift_health_checker/openshift_checks/package_availability.py:26: [C0111(missing-docstring), PackageAvailability.master_packages] Missing method docstring roles/openshift_health_checker/openshift_checks/package_availability.py:42: [C0111(missing-docstring), PackageAvailability.node_packages] Missing method docstring ************* Module openshift_checks.package_update roles/openshift_health_checker/openshift_checks/package_update.py:1: [C0111(missing-docstring), ] Missing module docstring ************* Module openshift_checks.package_version roles/openshift_health_checker/openshift_checks/package_version.py:1: [C0111(missing-docstring), ] Missing module docstring error: lint error 30. ERROR: InvocationError: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-pylint/bin/python setup.py lint (see /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-pylint/log/py35-ansible22-pylint-2.log) ERROR: invocation failed (exit code 1), logfile: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-pylint/log/py27-ansible22-pylint-2.log ERROR: actionid: py27-ansible22-pylint msg: runtests cmdargs: ['/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-pylint/bin/python', 'setup.py', 'lint'] env: {'LANG': 'en_US.UTF-8', 'PATH': '/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-pylint/bin:/home/vagrant/env/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/src/github.com/openshift/origin/_output/local/bin/linux/amd64:/home/vagrant/src/github.com/openshift/source-to-image/_output/local/bin/linux/amd64:/home/vagrant/bin:/home/vagrant/.local/bin:/home/vagrant/bin', 'VIRTUAL_ENV': '/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-pylint', 'PYTHONHASHSEED': '3744639088'} running lint ************* Module aos_version roles/openshift_health_checker/library/aos_version.py:17: [R0912(too-many-branches), main] Too many branches (13/12) ************* Module openshift_health_check roles/openshift_health_checker/action_plugins/openshift_health_check.py:1: [C0111(missing-docstring), ] Missing module docstring roles/openshift_health_checker/action_plugins/openshift_health_check.py:16: [C0413(wrong-import-position), ] Import "from openshift_checks import OpenShiftCheck, OpenShiftCheckException" should be placed at the top of the module roles/openshift_health_checker/action_plugins/openshift_health_check.py:19: [C0111(missing-docstring), ActionModule] Missing class docstring roles/openshift_health_checker/action_plugins/openshift_health_check.py:34: [C0103(invalid-name), ActionModule.run] Invalid variable name "e" roles/openshift_health_checker/action_plugins/openshift_health_check.py:59: [C0103(invalid-name), ActionModule.run] Invalid variable name "r" roles/openshift_health_checker/action_plugins/openshift_health_check.py:60: [C0103(invalid-name), ActionModule.run] Invalid variable name "e" roles/openshift_health_checker/action_plugins/openshift_health_check.py:61: [C0103(invalid-name), ActionModule.run] Invalid variable name "r" roles/openshift_health_checker/action_plugins/openshift_health_check.py:65: [C0103(invalid-name), ActionModule.run] Invalid variable name "r" roles/openshift_health_checker/action_plugins/openshift_health_check.py:75: [C0111(missing-docstring), ActionModule.load_known_checks] Missing method docstring roles/openshift_health_checker/action_plugins/openshift_health_check.py:75: [W0613(unused-argument), ActionModule.load_known_checks] Unused argument 'task_vars' ************* Module openshift_checks roles/openshift_health_checker/openshift_checks/__init__.py:8: [W0622(redefined-builtin), ] Redefining built-in 'reduce' roles/openshift_health_checker/openshift_checks/__init__.py:1: [C0111(missing-docstring), ] Missing module docstring roles/openshift_health_checker/openshift_checks/__init__.py:13: [C0111(missing-docstring), OpenShiftCheckException] Missing class docstring roles/openshift_health_checker/openshift_checks/__init__.py:40: [W0613(unused-argument), OpenShiftCheck.is_active] Unused argument 'task_vars' roles/openshift_health_checker/openshift_checks/__init__.py:52: [E1101(no-member), OpenShiftCheck.subclasses] Class 'OpenShiftCheck' has no '__subclasses__' member roles/openshift_health_checker/openshift_checks/__init__.py:76: [C0103(invalid-name), ] Invalid constant name "excludes" ************* Module openshift_checks.mixins roles/openshift_health_checker/openshift_checks/mixins.py:1: [C0111(missing-docstring), ] Missing module docstring roles/openshift_health_checker/openshift_checks/mixins.py:8: [C0111(missing-docstring), NotContainerized.is_active] Missing method docstring roles/openshift_health_checker/openshift_checks/mixins.py:10: [E1101(no-member), NotContainerized.is_active] Super of 'NotContainerized' has no 'is_active' member roles/openshift_health_checker/openshift_checks/mixins.py:15: [C0111(missing-docstring), NotContainerized.is_containerized] Missing method docstring ************* Module openshift_checks.package_availability roles/openshift_health_checker/openshift_checks/package_availability.py:1: [C0111(missing-docstring), ] Missing module docstring roles/openshift_health_checker/openshift_checks/package_availability.py:26: [C0111(missing-docstring), PackageAvailability.master_packages] Missing method docstring roles/openshift_health_checker/openshift_checks/package_availability.py:42: [C0111(missing-docstring), PackageAvailability.node_packages] Missing method docstring ************* Module openshift_checks.package_update roles/openshift_health_checker/openshift_checks/package_update.py:1: [C0111(missing-docstring), ] Missing module docstring ************* Module openshift_checks.package_version roles/openshift_health_checker/openshift_checks/package_version.py:1: [C0111(missing-docstring), ] Missing module docstring error: lint error 30. ERROR: InvocationError: /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-pylint/bin/python setup.py lint (see /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py27-ansible22-pylint/log/py27-ansible22-pylint-2.log) _______________________________________________ summary _______________________________________________ ERROR: py27-ansible22-pylint: commands failed py27-ansible22-unit: commands succeeded ERROR: py27-ansible22-flake8: commands failed py27-ansible22-yamllint: commands succeeded py27-ansible22-generate_validation: commands succeeded ERROR: py35-ansible22-pylint: commands failed py35-ansible22-unit: commands succeeded ERROR: py35-ansible22-flake8: commands failed ERROR: py35-ansible22-yamllint: could not install deps [-rtest-requirements.txt, ansible~=2.2]; v = InvocationError('/home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/bin/pip install -rtest-requirements.txt ansible~=2.2 (see /home/vagrant/src/github.com/openshift/openshift-ansible/.tox/py35-ansible22-yamllint/log/py35-ansible22-yamllint-1.log)', 2) py35-ansible22-generate_validation: commands succeeded real 10m1.925s user 5m30.399s sys 5m42.938s ```
tbielawa commented 7 years ago

Weird. My tests are giving me different results than you.

Quick clone of the 11MiB from the openshift-ansible repo

[/tmp/tmp.Kt1GdBt8yg] 7:46:13
$ git clone git@github.com:openshift/openshift-ansible.git
Cloning into 'openshift-ansible'...
remote: Counting objects: 38592, done.
remote: Compressing objects: 100% (50/50), done.
remote: Total 38592 (delta 24), reused 0 (delta 0), pack-reused 38542
Receiving objects: 100% (38592/38592), 8.97 MiB | 1.40 MiB/s, done.
Resolving deltas: 100% (22522/22522), done.
Checking connectivity... done.
[/tmp/tmp.Kt1GdBt8yg] 7:46:24

And running detox -v from the master branch works in less than a minute

[/tmp/tmp.Kt1GdBt8yg] 7:46:24
$ cd ./openshift-ansible

[/tmp/tmp.Kt1GdBt8yg/openshift-ansible] 7:46:29  (master)
$ time detox -v
using tox.ini: /tmp/tmp.Kt1GdBt8yg/openshift-ansible/tox.ini
py27-ansible22-pylint create: /tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-pylint
  /tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox$ /usr/bin/python2 -m virtualenv --python /usr/bin/python2.7 py27-ansible22-pylint >/tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-pylint/log/py27-ansible22-pylint-0.log
py27-ansible22-unit create: /tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-unit
  /tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox$ /usr/bin/python2 -m virtualenv --python /usr/bin/python2.7 py27-ansible22-unit >/tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-unit/log/py27-ansible22-unit-0.log

...
______________________________________________________________________________________________________ summary ______________________________________________________________________________________________________
  py27-ansible22-pylint: commands succeeded
  py27-ansible22-unit: commands succeeded
  py27-ansible22-flake8: commands succeeded
  py27-ansible22-yamllint: commands succeeded
  py27-ansible22-generate_validation: commands succeeded
  py35-ansible22-pylint: commands succeeded
  py35-ansible22-unit: commands succeeded
  py35-ansible22-flake8: commands succeeded
  py35-ansible22-yamllint: commands succeeded
  py35-ansible22-generate_validation: commands succeeded
  congratulations :)

detox -v  231.76s user 10.10s system 451% cpu 53.597 total

I've got 8 cores in this system, so detox can run a lot of tests in parallel. Maybe that's different? When I run with just tox (so all tests in serial, not parallel) it takes longer:

[/tmp/tmp.Kt1GdBt8yg/openshift-ansible] 7:54:22  (master)
$ time tox -v
using tox.ini: /tmp/tmp.Kt1GdBt8yg/openshift-ansible/tox.ini
using tox-2.3.1 from /usr/lib/python3.5/site-packages/tox/__init__.py
py27-ansible22-pylint create: /tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-pylint
  /tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox$ /usr/bin/python3 -m virtualenv --python /usr/bin/python2.7 py27-ansible22-pylint >/tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-pylint/log/py27-ansible22-p
ylint-0.log
py27-ansible22-pylint installdeps: -rtest-requirements.txt, ansible~=2.2
  /tmp/tmp.Kt1GdBt8yg/openshift-ansible$ /tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-pylint/bin/pip install -rtest-requirements.txt ansible~=2.2 >/tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-pylint/log/py27-ansible22-pylint-1.log
  /tmp/tmp.Kt1GdBt8yg/openshift-ansible$ /tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-pylint/bin/pip freeze >/tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-pylint/log/py27-ansible22-pylint-2.log

....

  py27-ansible22-pylint: commands succeeded
  py27-ansible22-unit: commands succeeded
  py27-ansible22-flake8: commands succeeded
  py27-ansible22-yamllint: commands succeeded
  py27-ansible22-generate_validation: commands succeeded
  py35-ansible22-pylint: commands succeeded
  py35-ansible22-unit: commands succeeded
  py35-ansible22-flake8: commands succeeded
  py35-ansible22-yamllint: commands succeeded
  py35-ansible22-generate_validation: commands succeeded
  congratulations :)

tox -v  153.41s user 6.74s system 101% cpu 2:37.95 total

[/tmp/tmp.Kt1GdBt8yg/openshift-ansible] 7:57:05  (master)

Still, only a total of 2½ minutes.

Once tox has all the deps downloaded a second run is even quicker, 1 minute+15s was trimmed off:

[/tmp/tmp.Kt1GdBt8yg/openshift-ansible] 7:58:55  (master)
$ time tox -v
using tox.ini: /tmp/tmp.Kt1GdBt8yg/openshift-ansible/tox.ini
using tox-2.3.1 from /usr/lib/python3.5/site-packages/tox/__init__.py
py27-ansible22-pylint reusing: /tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-pylint
  /tmp/tmp.Kt1GdBt8yg/openshift-ansible$ /tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-pylint/bin/pip freeze >/tmp/tmp.Kt1GdBt8yg/openshift-ansible/.tox/py27-ansible22-pylint/log/py27-ansible22-pylint-
3.log

...

  py35-ansible22-yamllint: commands succeeded
  py35-ansible22-generate_validation: commands succeeded
  congratulations :)

tox -v  80.83s user 1.66s system 107% cpu 1:16.54 total

[/tmp/tmp.Kt1GdBt8yg/openshift-ansible] 8:00:12  (master)

I wonder what's causing your installation to run the tests so much slower? You obviously couldn't be the only person who the tests run slow for.

Can you tell me the following stats for your system?

rhcarvalho commented 7 years ago

@tbielawa thanks for the data for comparison. tox is taking 16 min.

detiber commented 7 years ago

It took me more than 10 min (time not tracked scientifically) to run detox locally, and the amount of output is enormous, making it very hard to read what pylint or pyflake or what not is being complained about.

The only time I've seen this is when I have an extraneous virutalenv in the repo that isn't in the exclude list for the tests.

Objective: discuss ways to to improve both time and amount of output to improve developer experience.

One thing that comes to mind for improving the runtimes would be limit some of the tests to just code that has changed since a specified commit id. That would drastically decrease the scope of what is being tested for that workflow and would meet your criteria.

Further notes/questions: How serious are we about supporting both Python 2.7 and 3.5 in the code base?

We are already hitting python2/python3 issues in some places with Fedora installs, which is what prompted adding testing support for python 3.5. Ansible is also increasing it's python3 support with every release and I fully expect that we are going to hit a point within the next few Ansible releases that they will default to python3 as well.

It feels a bit counter productive to need commits like 7767df1 that are "making peace with linters" (and git log --grep=lint --no-merges --oneline reveals at least 59 of them). There are over 700 comments like # pylint: ... in about 140 files. Following a code style is good, but coding to satisfy tools and sprinkling comments to configure such tools may not always lead to the intended effects of higher code quality. This might be a separate topic for discussion, though.

There are a few different reasons for this, and I agree with you here for the most part.

rhcarvalho commented 7 years ago

(FTR) Got it down to 3'17" yesterday. Indeed I had a utils/oo-installenv/ with a virtualenv (created by make ci)...

rhcarvalho commented 7 years ago

I'm noticing that since we merged the tests for root and utils into one tox config (excellent thing), we're reinstalling some dependencies apparently all the time.

$ tox -e py27-unit -- test/modify_yaml_tests.py
py27-unit installed: ansible==2.2.1.0,appdirs==1.4.3,asn1crypto==0.22.0,astroid==1.4.9,backports.functools-lru-cache==1.3,backports.shutil-get-terminal-size==1.0.0,cffi==1.9.1,click==6.7,configparser==3.5.0,cove
rage==4.3.4,cryptography==1.8.1,decorator==4.0.11,enum34==1.1.6,flake8==3.3.0,flake8-mutable==1.1.0,flake8-print==2.0.2,funcsigs==1.0.2,idna==2.5,ipaddress==1.0.18,ipdb==0.10.2,ipython==5.3.0,ipython-genutils==0
.2.0,isort==4.2.5,Jinja2==2.8.1,lazy-object-proxy==1.2.2,MarkupSafe==1.0,mccabe==0.6.1,mock==2.0.0,-e git+git@github.com:rhcarvalho/openshift-ansible.git@874aeab775a848e7ce9f8a5e417a9690663f5b36#egg=ooinstall&su
bdirectory=utils,packaging==16.8,paramiko==2.1.2,pathlib2==2.2.1,pbr==2.0.0,pexpect==4.2.1,pickleshare==0.7.4,prompt-toolkit==1.0.13,ptyprocess==0.5.1,py==1.4.32,pyasn1==0.2.3,pycodestyle==2.3.1,pycparser==2.17,
pycrypto==2.6.1,pyflakes==1.5.0,Pygments==2.2.0,pylint==1.6.5,pyOpenSSL==16.2.0,pyparsing==2.2.0,pytest==3.0.7,pytest-cov==2.4.0,PyYAML==3.12,scandir==1.5,setuptools-lint==0.5.2,simplegeneric==0.8.1,six==1.10.0,
traitlets==4.3.2,wcwidth==0.1.7,wrapt==1.10.10,yamllint==1.6.1
py27-unit runtests: PYTHONHASHSEED='2161935373'
py27-unit runtests: commands[0] | pip install -e utils
Obtaining file:///home/rodolfo/openshift/src/github.com/openshift/openshift-ansible/utils
Requirement already satisfied: click in ./.tox/py27-unit/lib/python2.7/site-packages (from ooinstall==3.0.0)
Requirement already satisfied: PyYAML in ./.tox/py27-unit/lib/python2.7/site-packages (from ooinstall==3.0.0)
Requirement already satisfied: ansible in ./.tox/py27-unit/lib/python2.7/site-packages (from ooinstall==3.0.0)
Requirement already satisfied: paramiko in ./.tox/py27-unit/lib/python2.7/site-packages (from ansible->ooinstall==3.0.0)
Requirement already satisfied: setuptools in ./.tox/py27-unit/lib/python2.7/site-packages (from ansible->ooinstall==3.0.0)
Requirement already satisfied: jinja2<2.9 in ./.tox/py27-unit/lib/python2.7/site-packages (from ansible->ooinstall==3.0.0)
Requirement already satisfied: pycrypto>=2.6 in ./.tox/py27-unit/lib/python2.7/site-packages (from ansible->ooinstall==3.0.0)
Requirement already satisfied: pyasn1>=0.1.7 in ./.tox/py27-unit/lib/python2.7/site-packages (from paramiko->ansible->ooinstall==3.0.0)
Requirement already satisfied: cryptography>=1.1 in ./.tox/py27-unit/lib/python2.7/site-packages (from paramiko->ansible->ooinstall==3.0.0)
Requirement already satisfied: appdirs>=1.4.0 in ./.tox/py27-unit/lib/python2.7/site-packages (from setuptools->ansible->ooinstall==3.0.0)
Requirement already satisfied: packaging>=16.8 in ./.tox/py27-unit/lib/python2.7/site-packages (from setuptools->ansible->ooinstall==3.0.0)
Requirement already satisfied: six>=1.6.0 in ./.tox/py27-unit/lib/python2.7/site-packages (from setuptools->ansible->ooinstall==3.0.0)
Requirement already satisfied: MarkupSafe in ./.tox/py27-unit/lib/python2.7/site-packages (from jinja2<2.9->ansible->ooinstall==3.0.0)
Requirement already satisfied: asn1crypto>=0.21.0 in ./.tox/py27-unit/lib/python2.7/site-packages (from cryptography>=1.1->paramiko->ansible->ooinstall==3.0.0)
Requirement already satisfied: ipaddress in ./.tox/py27-unit/lib/python2.7/site-packages (from cryptography>=1.1->paramiko->ansible->ooinstall==3.0.0)
Requirement already satisfied: idna>=2.1 in ./.tox/py27-unit/lib/python2.7/site-packages (from cryptography>=1.1->paramiko->ansible->ooinstall==3.0.0)
Requirement already satisfied: enum34 in ./.tox/py27-unit/lib/python2.7/site-packages (from cryptography>=1.1->paramiko->ansible->ooinstall==3.0.0)
Requirement already satisfied: cffi>=1.4.1 in ./.tox/py27-unit/lib/python2.7/site-packages (from cryptography>=1.1->paramiko->ansible->ooinstall==3.0.0)
Requirement already satisfied: pyparsing in ./.tox/py27-unit/lib/python2.7/site-packages (from packaging>=16.8->setuptools->ansible->ooinstall==3.0.0)
Requirement already satisfied: pycparser in ./.tox/py27-unit/lib/python2.7/site-packages (from cffi>=1.4.1->cryptography>=1.1->paramiko->ansible->ooinstall==3.0.0)
Installing collected packages: ooinstall
  Found existing installation: ooinstall 3.0.0
    Uninstalling ooinstall-3.0.0:
      Successfully uninstalled ooinstall-3.0.0
  Running setup.py develop for ooinstall
Successfully installed ooinstall
py27-unit runtests: commands[1] | pytest test/modify_yaml_tests.py
...

That makes the output a bit more messier, and the process a bit more slow to running single / a fraction of tests.

Installing once is great, re-installing all the time is the problem.

Not sure how this would affect code under utils if there were local changes (is the install copying or symlinking files?!).