Repository: ansible/ansible

Issue:
pip module considers an empty string as a version
##### SUMMARY
pip module considers an empty string as a version and attempts to install an empty string version.

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
pip

##### ANSIBLE VERSION
```
ansible 2.5.4
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /tmp/reproducer/lib/python2.7/site-packages/ansible
  executable location = /tmp/reproducer/bin/ansible
  python version = 2.7.5 (default, Aug  4 2017, 00:39:18) [GCC 4.8.5 20150623 (Red Hat 4.8.5-16)]
```

##### CONFIGURATION
not relevant

##### OS / ENVIRONMENT
not relevant

##### STEPS TO REPRODUCE
```yaml
- hosts: localhost
  gather_facts: no
  tasks:
    - name: "Omit a version (or not!)"
      pip:
        name: ansible
        version: ""
        state: present
        virtualenv: /tmp/reproducer
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
```
$ ansible localhost -m pip -a "name=ansible state=present version=''"

# ansible localhost -m pip -a "name=ansible state=present version=''"
 [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

localhost | SUCCESS => {
    "changed": false, 
    "cmd": "/tmp/reproducer/bin/pip2 install ansible", 
    "name": [
        "ansible"
    ], 
    "requirements": null, 
    "state": "present", 
    "stderr": "You are using pip version 9.0.1, however version 10.0.1 is available.\nYou should consider upgrading via the 'pip install --upgrade pip' command.\n", 
    "stderr_lines": [
        "You are using pip version 9.0.1, however version 10.0.1 is available.", 
        "You should consider upgrading via the 'pip install --upgrade pip' command."
    ], 
    "stdout": "Requirement already satisfied: ansible in ./reproducer/lib/python2.7/site-packages\nRequirement already satisfied: setuptools in ./reproducer/lib/python2.7/site-packages (from ansible)\nRequirement already satisfied: cryptography in ./reproducer/lib/python2.7/site-packages (from ansible)\nRequirement already satisfied: paramiko in ./reproducer/lib/python2.7/site-packages (from ansible)\nRequirement already satisfied: jinja2 in ./reproducer/lib/python2.7/site-packages (from ansible)\nRequirement already satisfied: PyYAML in ./reproducer/lib/python2.7/site-packages (from ansible)\nRequirement already satisfied: cffi>=1.7; platform_python_implementation != \"PyPy\" in ./reproducer/lib/python2.7/site-packages (from cryptography->ansible)\nRequirement already satisfied: enum34; python_version < \"3\" in ./reproducer/lib/python2.7/site-packages (from cryptography->ansible)\nRequirement already satisfied: asn1crypto>=0.21.0 in ./reproducer/lib/python2.7/site-packages (from cryptography->ansible)\nRequirement already satisfied: idna>=2.1 in ./reproducer/lib/python2.7/site-packages (from cryptography->ansible)\nRequirement already satisfied: six>=1.4.1 in ./reproducer/lib/python2.7/site-packages (from cryptography->ansible)\nRequirement already satisfied: ipaddress; python_version < \"3\" in ./reproducer/lib/python2.7/site-packages (from cryptography->ansible)\nRequirement already satisfied: pyasn1>=0.1.7 in ./reproducer/lib/python2.7/site-packages (from paramiko->ansible)\nRequirement already satisfied: bcrypt>=3.1.3 in ./reproducer/lib/python2.7/site-packages (from paramiko->ansible)\nRequirement already satisfied: pynacl>=1.0.1 in ./reproducer/lib/python2.7/site-packages (from paramiko->ansible)\nRequirement already satisfied: MarkupSafe>=0.23 in ./reproducer/lib/python2.7/site-packages (from jinja2->ansible)\nRequirement already satisfied: pycparser in ./reproducer/lib/python2.7/site-packages (from cffi>=1.7; platform_python_implementation != \"PyPy\"->cryptography->ansible)\n", 
    "stdout_lines": [
        "Requirement already satisfied: ansible in ./reproducer/lib/python2.7/site-packages", 
        "Requirement already satisfied: setuptools in ./reproducer/lib/python2.7/site-packages (from ansible)", 
        "Requirement already satisfied: cryptography in ./reproducer/lib/python2.7/site-packages (from ansible)", 
        "Requirement already satisfied: paramiko in ./reproducer/lib/python2.7/site-packages (from ansible)", 
        "Requirement already satisfied: jinja2 in ./reproducer/lib/python2.7/site-packages (from ansible)", 
        "Requirement already satisfied: PyYAML in ./reproducer/lib/python2.7/site-packages (from ansible)", 
        "Requirement already satisfied: cffi>=1.7; platform_python_implementation != \"PyPy\" in ./reproducer/lib/python2.7/site-packages (from cryptography->ansible)", 
        "Requirement already satisfied: enum34; python_version < \"3\" in ./reproducer/lib/python2.7/site-packages (from cryptography->ansible)", 
        "Requirement already satisfied: asn1crypto>=0.21.0 in ./reproducer/lib/python2.7/site-packages (from cryptography->ansible)", 
        "Requirement already satisfied: idna>=2.1 in ./reproducer/lib/python2.7/site-packages (from cryptography->ansible)", 
        "Requirement already satisfied: six>=1.4.1 in ./reproducer/lib/python2.7/site-packages (from cryptography->ansible)", 
        "Requirement already satisfied: ipaddress; python_version < \"3\" in ./reproducer/lib/python2.7/site-packages (from cryptography->ansible)", 
        "Requirement already satisfied: pyasn1>=0.1.7 in ./reproducer/lib/python2.7/site-packages (from paramiko->ansible)", 
        "Requirement already satisfied: bcrypt>=3.1.3 in ./reproducer/lib/python2.7/site-packages (from paramiko->ansible)", 
        "Requirement already satisfied: pynacl>=1.0.1 in ./reproducer/lib/python2.7/site-packages (from paramiko->ansible)", 
        "Requirement already satisfied: MarkupSafe>=0.23 in ./reproducer/lib/python2.7/site-packages (from jinja2->ansible)", 
        "Requirement already satisfied: pycparser in ./reproducer/lib/python2.7/site-packages (from cffi>=1.7; platform_python_implementation != \"PyPy\"->cryptography->ansible)"
    ], 
    "version": "", 
    "virtualenv": null
}

```
##### ACTUAL RESULTS
```
$ ansible localhost -m pip -a "name=ansible state=present version=''"

localhost | FAILED! => {
    "changed": false, 
    "cmd": "/tmp/reproducer/bin/pip2 install ansible==", 
    "msg": "stdout: Collecting ansible==\n\n:stderr:   Could not find a version that satisfies the requirement ansible== (from versions: 1.0, 1.1, 1.2, 1.2.1, 1.2.2, 1.2.3, 1.3.0, 1.3.1, 1.3.2, 1.3.3, 1.3.4, 1.4, 1.4.1, 1.4.2, 1.4.3, 1.4.4, 1.4.5, 1.5, 1.5.1, 1.5.2, 1.5.3, 1.5.4, 1.5.5, 1.6, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.6.5, 1.6.6, 1.6.7, 1.6.8, 1.6.9, 1.6.10, 1.7, 1.7.1, 1.7.2, 1.8, 1.8.1, 1.8.2, 1.8.3, 1.8.4, 1.9.0.1, 1.9.1, 1.9.2, 1.9.3, 1.9.4, 1.9.5, 1.9.6, 2.0.0.0, 2.0.0.1, 2.0.0.2, 2.0.1.0, 2.0.2.0, 2.1.0.0, 2.1.1.0, 2.1.2.0, 2.1.3.0, 2.1.4.0, 2.1.5.0, 2.1.6.0, 2.2.0.0, 2.2.1.0, 2.2.2.0, 2.2.3.0, 2.3.0.0, 2.3.1.0, 2.3.2.0, 2.3.3.0, 2.4.0.0, 2.4.1.0, 2.4.2.0, 2.4.3.0, 2.4.4.0, 2.5.0a1, 2.5.0b1, 2.5.0b2, 2.5.0rc1, 2.5.0rc2, 2.5.0rc3, 2.5.0, 2.5.1, 2.5.2, 2.5.3, 2.5.4, 2.6.0a1, 2.6.0a2)\nNo matching distribution found for ansible==\nYou are using pip version 9.0.1, however version 10.0.1 is available.\nYou should consider upgrading via the 'pip install --upgrade pip' command.\n"
}

```



Discussion:

Resolving patch:
diff --git a/lib/ansible/modules/packaging/language/pip.py b/lib/ansible/modules/packaging/language/pip.py
--- a/lib/ansible/modules/packaging/language/pip.py
+++ b/lib/ansible/modules/packaging/language/pip.py
@@ -219,7 +219,7 @@ def _get_cmd_options(module, cmd):
 
 
 def _get_full_name(name, version=None):
-    if version is None:
+    if version is None or version == "":
         resp = name
     else:
         resp = name + '==' + version


Test patch:
diff --git a/test/integration/targets/pip/tasks/pip.yml b/test/integration/targets/pip/tasks/pip.yml
--- a/test/integration/targets/pip/tasks/pip.yml
+++ b/test/integration/targets/pip/tasks/pip.yml
@@ -256,3 +256,17 @@
   assert:
     that:
       - not pip_install_empty.changed
+
+# https://github.com/ansible/ansible/issues/41043
+- name: do not consider an empty string as a version
+  pip:
+    name: q
+    state: present
+    version: ""
+    virtualenv: "{{ output_dir }}/pipenv"
+  register: pip_install_empty_version_string
+
+- name: ensure that task installation did not fail
+  assert:
+    that:
+      - pip_install_empty_version_string is successful