Repository: docker/docker-py

Issue:
Please don't require exact versions in requirements
It's a good idea to pin requirements in applications.

It's a bad idea to pin requirements in libraries.  Doing so makes reusing libraries difficult.  If you have minimum requirements, that's fine.



Discussion:
BTW, thanks for this module. It's going to make a current project a lot easier. :)

Continuing since this resurfaced with #228: I've had problems with non-pinned versions in the past, especially since pip's primitives when it comes to specifying version ranges are fairly limited in my opinion ([compared to npm, for example](https://www.npmjs.org/doc/misc/semver.html#ranges)).

I'm inclined to say: call us out / send patches if pinned versions are getting unreasonably old, and use virtualenvs as much as possible since they _will_ save you a lot of trouble. I'm happy to discuss this further, I may be missing some valid counter-arguments, but I genuinely believe unpinning versions will be worse for everyone (maintainers and users) in the long run.

@shin- virtualenvs don't solve this problem if someone has something that depends on docker-py and one of your pinned dependencies; you'll still be forcing them to use a particular version of that dependency.

Perhaps not a problem right now, but imagine a situation where a version of requests is released which introduces a new feature and a (perhaps unknown) regression, both unrelated to how docker-py uses it. Do you accept the PR from person A which bumps your pin up? What do you do when person B opens a PR reverting that change because the regression breaks their app? And then what does person A do with their codebase that is using this shiny new requests feature?

If you specified a minimum version that you require (rather than pinning at a specific version), then person A could use the shiny new feature _and_ person B could stick with the version before regression.

> Perhaps not a problem right now, but imagine a situation where a version of requests is released which introduces a new feature and a (perhaps unknown) regression, both unrelated to how docker-py uses it. Do you accept the PR from person A which bumps your pin up? What do you do when person B opens a PR reverting that change because the regression breaks their app? And then what does person A do with their codebase that is using this shiny new requests feature?

In that example, my opinion is that person B should either update their code to support the newest version of requests, or stick with an older version of docker-py that doesn't require said version of requests. If they're okay with an "outdated" version of requests why wouldn't they be okay with an "outdated" version of docker-py?

So, as I mentioned on #218, I'm looking into this specifically in the context of packaging the library.  Currently, "python-websocket" is at 0.12 in Debian (which is the package for websocket-client), but the dep here is `==0.11`, so I get fun errors that aren't easy to workaround without patching the requirements.txt myself, which I don't think you as an upstream would appreciate much.

At the risk of repeating myself, best practice:
- Libraries: either don't restrict versions of package dependencies, or restrict them to
  ranges, ideally without upper bounds.
- Applications: pin dependencies to particular versions.

Pinning _library_ dependencies to specific versions makes it hard to reuse the library.

You should heed sound advice, born of great experience, gently offered twice.


Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -6,17 +6,19 @@
 ROOT_DIR = os.path.dirname(__file__)
 SOURCE_DIR = os.path.join(ROOT_DIR)
 
-if sys.version_info[0] == 3:
-    requirements_file = './requirements3.txt'
-else:
-    requirements_file = './requirements.txt'
+requirements = [
+    'requests >= 2.2.1',
+    'six >= 1.3.0',
+]
+
+if sys.version_info[0] < 3:
+    requirements.append('websocket-client >= 0.11.0')
 
 exec(open('docker/version.py').read())
 
 with open('./test-requirements.txt') as test_reqs_txt:
     test_requirements = [line for line in test_reqs_txt]
-with open(requirements_file) as requirements_txt:
-    requirements = [line for line in requirements_txt]
+
 
 setup(
     name="docker-py",
@@ -24,7 +26,8 @@
     description="Python client for Docker.",
     packages=['docker', 'docker.auth', 'docker.unixconn', 'docker.utils',
               'docker.ssladapter'],
-    install_requires=requirements + test_requirements,
+    install_requires=requirements,
+    tests_require=test_requirements,
     zip_safe=False,
     test_suite='tests',
     classifiers=[


Test patch: