poise / poise-python

A Chef cookbook to provide a unified interface for installing Python, managing Python packages, and creating virtualenvs.
Apache License 2.0
124 stars 108 forks source link

Specifying partial version for pip/setuptools/virtualenv/wheel does NOT pull latest of that major #110

Closed espoelstra closed 6 years ago

espoelstra commented 6 years ago

For the python['version'] property the documentation states,

If a partial version is given, use the latest available version matching that prefix.

I've discovered that even though the documentation only mentions true and false for pip/setuptools/virtualenv/wheel you can also specify a specific or partial version. I am going to submit a PR to update the documentation to indicate that in case people haven't discovered this on their own, but while testing the partial version matching scenario with eg pip['version'] = '9' and running a smoke test with test-kitchen, I discovered it is only pulling the first major version and not the latest of that series. My PR will reflect that you should specify the full version if you are pinning a previous version for some reason. This might just be a pip behavior aka WONTFIX but after a bit of research I think it could be solved with some Ruby creating a constraints file (since pip 7.1) and using that to narrow down the major/minor/patch with a requirement specifier like wheel >0.28,<0.30.

https://pip.pypa.io/en/stable/user_guide/#constraints-files https://pip.pypa.io/en/stable/reference/pip_install/#requirement-specifiers

My reproduction files aka poise_python_wrapper:

attributes/default.rb

default['poise-python']['options']['pip_version'] = '9.0' # or '9'
default['poise-python']['options']['setuptools_version'] = true
default['poise-python']['options']['version'] = '2.7'
default['poise-python']['options']['virtualenv_version'] = '15'
default['poise-python']['options']['wheel_version'] = '0.29.0'

recipes/default.rb

python_runtime node['poise-python']['options']['version']

test/smoke/default/default_test.rb

describe pip('pip') do
  it { should be_installed }
  its('version') { should cmp == '9.0.3' }
end

# Because we don't pin setuptools we don't test for a specific version
describe pip('setuptools') do
  it { should be_installed }
  #its('version') { should cmp == '39.0.1' }
end

describe pip('wheel') do
  it { should be_installed }
  its('version') { should cmp == '0.29.0' }
end

describe pip('virtualenv') do
  it { should be_installed }
  its('version') { should cmp == '15.1.0' }
end

Test output:

  Pip Package
     ✔  pip should be installed
     ∅  pip version should cmp == "9.0.3"

     expected: "9.0.3"
          got: 9.0.0

     (compared using `cmp` matcher)

  Pip Package
     ✔  setuptools should be installed
  Pip Package
     ✔  wheel should be installed
     ✔  wheel version should cmp == "0.29.0"
  Pip Package
     ✔  virtualenv should be installed
     ∅  virtualenv version should cmp == "15.1.0"

     expected: "15.1.0"
          got: 15.0.0

     (compared using `cmp` matcher)
coderanger commented 6 years ago

That logic applies only to the version of Python. pip/wheel/setuptools are installed using pip so the version number for those follows pip semantics.

coderanger commented 6 years ago

Going to close this since partial version matching for those packages is not a feature and I have no plans to add it.

espoelstra commented 6 years ago

Yeah after doing some testing I noticed that because python is installed using package it benefits from apt's fuzzy matching while the pip wrapper is using == which is literal, so you'll get 9.0.0 if you just specify 9. I'm going to do a bit more testing, but I discovered that if you quote the package name and version constraints to pip it will allow that, so it may be another option rather than the constraints file to allow the same fuzzy latest.

coderanger commented 6 years ago

No, it's not using apt fuzzy matching. The language version prefix stuff is a feature of poise-languages (which is why it works with all providers).

espoelstra commented 6 years ago

Ahhh interesting. Well it appears that == is hardcoded somewhere in poise-python for pip so even though I can pip install 'wheel >0.28, <0.30' myself, I can't pass default['poise-python']['options']['wheel_version'] = '>=0.29,<0.30' to the resource. I'll update my PR to remove the partial version verbiage and only mention supplying a full version to override the latest. It would be awesine to be able to use the pip native version constraints, but we can work around it by explicit versions for now.

coderanger commented 6 years ago

@espoelstra That is correct, the python_package resource works like most other package resources, not just a simple shell out. It analyzes both the currently installed and candidate versions. Syntax like that could be added (it was recently put in for the yum package provider), but currently is very limited. The more complex behavior like that I add, the more I have to reach into pip's internals because it's surprisingly hard to determine the candidate version for a set of options.