Skip to content

Commit

Permalink
Fix broken pip state
Browse files Browse the repository at this point in the history
  • Loading branch information
dwoz committed Apr 27, 2019
1 parent 113ba8c commit fbe648c
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 44 deletions.
72 changes: 41 additions & 31 deletions salt/states/pip_state.py
Expand Up @@ -49,42 +49,35 @@
HAS_PIP = True
except ImportError:
HAS_PIP = False
# Remove references to the loaded pip module above so reloading works
import sys
pip_related_entries = [
(k, v) for (k, v) in sys.modules.items()
or getattr(v, '__module__', '').startswith('pip.')
or (isinstance(v, types.ModuleType) and v.__name__.startswith('pip.'))
]
for name, entry in pip_related_entries:
sys.modules.pop(name)
del entry

del pip
sys_modules_pip = sys.modules.pop('pip', None)
if sys_modules_pip is not None:
del sys_modules_pip

if HAS_PIP is True:
try:
from pip.req import InstallRequirement
_from_line = InstallRequirement.from_line
except ImportError:
# pip 10.0.0 move req module under pip._internal
try:
try:
from pip._internal.req import InstallRequirement
_from_line = InstallRequirement.from_line
except AttributeError:
from pip._internal.req.constructors import install_req_from_line as _from_line
except ImportError:
HAS_PIP = False
# Remove references to the loaded pip module above so reloading works
import sys
pip_related_entries = [
(k, v) for (k, v) in sys.modules.items()
or getattr(v, '__module__', '').startswith('pip.')
or (isinstance(v, types.ModuleType) and v.__name__.startswith('pip.'))
]
for name, entry in pip_related_entries:
sys.modules.pop(name)
del entry

del pip
sys_modules_pip = sys.modules.pop('pip', None)
if sys_modules_pip is not None:
del sys_modules_pip

try:
if salt.utils.versions.compare(ver1=pip.__version__,
oper='>=',
ver2='18.1'):
from pip._internal.exceptions import InstallationError
elif salt.utils.versions.compare(ver1=pip.__version__,
oper='>=',
ver2='10.0'):
from pip.exceptions import InstallationError
except ImportError:
else:
InstallationError = ValueError


# pylint: enable=import-error

log = logging.getLogger(__name__)
Expand All @@ -93,6 +86,23 @@
__virtualname__ = 'pip'


def _from_line(*args, **kwargs):
import pip
if salt.utils.versions.compare(ver1=pip.__version__,
oper='>=',
ver2='18.1'):
import pip._internal.req.constructors
return pip._internal.req.constructors.install_req_from_line(*args, **kwargs)
elif salt.utils.versions.compare(ver1=pip.__version__,
oper='>=',
ver2='10.0'):
import pip._internal.req
return pip._internal.req.InstallRequirement.from_line(*args, **kwargs)
else:
import pip.req
return pip.req.InstallRequirement.from_line(*args, **kwargs)


def __virtual__():
'''
Only load if the pip module is available in __salt__
Expand Down
28 changes: 15 additions & 13 deletions tests/unit/states/test_pip_state.py
Expand Up @@ -9,6 +9,7 @@

# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import logging

# Import Salt Testing libs
from tests.support.mixins import LoaderModuleMockMixin, SaltReturnAssertsMixin
Expand All @@ -27,6 +28,9 @@
HAS_PIP = False


log = logging.getLogger(__name__)


@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PIP,
'The \'pip\' library is not importable(installed system-wide)')
Expand All @@ -42,6 +46,7 @@ def setup_loader_modules(self):
}

def test_install_requirements_parsing(self):
log.debug("Real pip version is %s", pip.__version__)
mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.3'})
pip_version = pip.__version__
Expand All @@ -50,19 +55,16 @@ def test_install_requirements_parsing(self):
with patch.dict(pip_state.__salt__, {'cmd.run_all': mock,
'pip.list': pip_list}):
with patch.dict(pip_state.__opts__, {'test': True}):
if salt.utils.versions.compare(ver1=pip_version,
oper='<',
ver2='10.0'):
ret = pip_state.installed('pep8=1.3.2')
self.assertSaltFalseReturn({'test': ret})
self.assertInSaltComment(
'Invalid version specification in package pep8=1.3.2. '
'\'=\' is not supported, use \'==\' instead.',
{'test': ret})
else:
self.assertRaises(
pip._internal.exceptions.InstallationError,
pip_state.installed, 'pep=1.3.2')
log.debug(
'pip_state._from_line globals: %s',
[name for name in pip_state._from_line.__globals__]
)
ret = pip_state.installed('pep8=1.3.2')
self.assertSaltFalseReturn({'test': ret})
self.assertInSaltComment(
'Invalid version specification in package pep8=1.3.2. '
'\'=\' is not supported, use \'==\' instead.',
{'test': ret})

mock = MagicMock(return_value={'retcode': 0, 'stdout': ''})
pip_list = MagicMock(return_value={'pep8': '1.3.3'})
Expand Down

0 comments on commit fbe648c

Please sign in to comment.