Repository: docker/docker-py

Issue:
Feature Request: docker.from_env(version='auto')
Feature request to add auto api version support for ```docker.from_env()``` similar to ```docker.Client(version='auto')```?

I noticed that one of the suggestions from #402 for the ```version='auto'``` option was now available for ```docker.Client()``` but doesn't work for ```docker.from_env()```.

Discussion:
dnephin: LGTM, just a minor nit

Patch:
diff --git a/docker/client.py b/docker/client.py
index d1c6ee5f..dc28ac46 100644
--- a/docker/client.py
+++ b/docker/client.py
@@ -114,7 +114,8 @@ class Client(
 
     @classmethod
     def from_env(cls, **kwargs):
-        return cls(**kwargs_from_env(**kwargs))
+        version = kwargs.pop('version', None)
+        return cls(version=version, **kwargs_from_env(**kwargs))
 
     def _retrieve_server_version(self):
         try:
@@ -268,7 +269,7 @@ class Client(
         else:
             # Response isn't chunked, meaning we probably
             # encountered an error immediately
-            yield self._result(response, json=decode)
+            yield self._result(response)
 
     def _multiplexed_buffer_helper(self, response):
         """A generator of multiplexed data blocks read from a buffered
diff --git a/docker/utils/utils.py b/docker/utils/utils.py
index c108a835..a5fbe0ba 100644
--- a/docker/utils/utils.py
+++ b/docker/utils/utils.py
@@ -623,7 +623,7 @@ def create_host_config(binds=None, port_bindings=None, lxc_conf=None,
                        device_write_iops=None, oom_kill_disable=False,
                        shm_size=None, sysctls=None, version=None, tmpfs=None,
                        oom_score_adj=None, dns_opt=None, cpu_shares=None,
-                       cpuset_cpus=None, userns_mode=None, pids_limit=None):
+                       cpuset_cpus=None, userns_mode=None):
 
     host_config = {}
 
@@ -904,13 +904,6 @@ def create_host_config(binds=None, port_bindings=None, lxc_conf=None,
             raise host_config_value_error("userns_mode", userns_mode)
         host_config['UsernsMode'] = userns_mode
 
-    if pids_limit:
-        if not isinstance(pids_limit, int):
-            raise host_config_type_error('pids_limit', pids_limit, 'int')
-        if version_lt(version, '1.23'):
-            raise host_config_version_error('pids_limit', '1.23')
-        host_config["PidsLimit"] = pids_limit
-
     return host_config
 
 
@@ -1000,7 +993,7 @@ def format_environment(environment):
     def format_env(key, value):
         if value is None:
             return key
-        return u'{key}={value}'.format(key=key, value=value)
+        return '{key}={value}'.format(key=key, value=value)
     return [format_env(*var) for var in six.iteritems(environment)]
 
 
diff --git a/docs/hostconfig.md b/docs/hostconfig.md
index 008d5cf2..6645bd1f 100644
--- a/docs/hostconfig.md
+++ b/docs/hostconfig.md
@@ -111,12 +111,11 @@ for example:
   CPU period.
 * cpu_shares (int): CPU shares (relative weight)
 * cpuset_cpus (str): CPUs in which to allow execution (0-3, 0,1)
-* blkio_weight: Block IO weight (relative weight), accepts a weight value
-  between 10 and 1000.
+* blkio_weight: Block IO weight (relative weight), accepts a weight value between 10 and 1000.
 * blkio_weight_device: Block IO weight (relative device weight) in the form of:
   `[{"Path": "device_path", "Weight": weight}]`
-* device_read_bps: Limit read rate (bytes per second) from a device in the
-  form of: `[{"Path": "device_path", "Rate": rate}]`
+* device_read_bps: Limit read rate (bytes per second) from a device in the form of:
+  `[{"Path": "device_path", "Rate": rate}]`
 * device_write_bps: Limit write rate (bytes per second) from a device.
 * device_read_iops: Limit read rate (IO per second) from a device.
 * device_write_iops: Limit write rate (IO per second) from a device.
@@ -129,7 +128,6 @@ for example:
 * sysctls (dict): Kernel parameters to set in the container.
 * userns_mode (str): Sets the user namespace mode for the container when user
   namespace remapping option is enabled. Supported values are: `host`
-* pids_limit (int): Tune a container’s pids limit. Set -1 for unlimited.
 
 **Returns** (dict) HostConfig dictionary
 


Test patch:
diff --git a/tests/unit/api_test.py b/tests/unit/api_test.py
index 5850afa2..712f57e0 100644
--- a/tests/unit/api_test.py
+++ b/tests/unit/api_test.py
@@ -22,11 +22,9 @@ import sys
 import tempfile
 import threading
 import time
-import io
 
 import docker
 import requests
-from requests.packages import urllib3
 import six
 
 from .. import base
@@ -44,7 +42,7 @@ DEFAULT_TIMEOUT_SECONDS = docker.constants.DEFAULT_TIMEOUT_SECONDS
 
 
 def response(status_code=200, content='', headers=None, reason=None, elapsed=0,
-             request=None, raw=None):
+             request=None):
     res = requests.Response()
     res.status_code = status_code
     if not isinstance(content, six.binary_type):
@@ -54,7 +52,6 @@ def response(status_code=200, content='', headers=None, reason=None, elapsed=0,
     res.reason = reason
     res.elapsed = datetime.timedelta(elapsed)
     res.request = request
-    res.raw = raw
     return res
 
 
@@ -331,43 +328,6 @@ class DockerApiTest(DockerClientTest):
             TypeError, self.client.create_host_config, security_opt='wrong'
         )
 
-    def test_stream_helper_decoding(self):
-        status_code, content = fake_api.fake_responses[url_prefix + 'events']()
-        content_str = json.dumps(content)
-        if six.PY3:
-            content_str = content_str.encode('utf-8')
-        body = io.BytesIO(content_str)
-
-        # mock a stream interface
-        raw_resp = urllib3.HTTPResponse(body=body)
-        setattr(raw_resp._fp, 'chunked', True)
-        setattr(raw_resp._fp, 'chunk_left', len(body.getvalue())-1)
-
-        # pass `decode=False` to the helper
-        raw_resp._fp.seek(0)
-        resp = response(status_code=status_code, content=content, raw=raw_resp)
-        result = next(self.client._stream_helper(resp))
-        self.assertEqual(result, content_str)
-
-        # pass `decode=True` to the helper
-        raw_resp._fp.seek(0)
-        resp = response(status_code=status_code, content=content, raw=raw_resp)
-        result = next(self.client._stream_helper(resp, decode=True))
-        self.assertEqual(result, content)
-
-        # non-chunked response, pass `decode=False` to the helper
-        setattr(raw_resp._fp, 'chunked', False)
-        raw_resp._fp.seek(0)
-        resp = response(status_code=status_code, content=content, raw=raw_resp)
-        result = next(self.client._stream_helper(resp))
-        self.assertEqual(result, content_str.decode('utf-8'))
-
-        # non-chunked response, pass `decode=True` to the helper
-        raw_resp._fp.seek(0)
-        resp = response(status_code=status_code, content=content, raw=raw_resp)
-        result = next(self.client._stream_helper(resp, decode=True))
-        self.assertEqual(result, content)
-
 
 class StreamTest(base.Cleanup, base.BaseTestCase):
     def setUp(self):
diff --git a/tests/unit/client_test.py b/tests/unit/client_test.py
index b21f1d6a..6ceb8cbb 100644
--- a/tests/unit/client_test.py
+++ b/tests/unit/client_test.py
@@ -25,6 +25,14 @@ class ClientTest(base.BaseTestCase):
         client = Client.from_env()
         self.assertEqual(client.base_url, "https://192.168.59.103:2376")
 
+    def test_from_env_with_version(self):
+        os.environ.update(DOCKER_HOST='tcp://192.168.59.103:2376',
+                          DOCKER_CERT_PATH=TEST_CERT_DIR,
+                          DOCKER_TLS_VERIFY='1')
+        client = Client.from_env(version='2.32')
+        self.assertEqual(client.base_url, "https://192.168.59.103:2376")
+        self.assertEqual(client._version, '2.32')
+
 
 class DisableSocketTest(base.BaseTestCase):
     class DummySocket(object):
diff --git a/tests/unit/container_test.py b/tests/unit/container_test.py
index 3cea42fb..c480462f 100644
--- a/tests/unit/container_test.py
+++ b/tests/unit/container_test.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 import datetime
 import json
 import signal
@@ -1157,24 +1155,6 @@ class CreateContainerTest(DockerClientTest):
             args[1]['timeout'], DEFAULT_TIMEOUT_SECONDS
         )
 
-    def test_create_container_with_unicode_envvars(self):
-        envvars_dict = {
-            'foo': u'☃',
-        }
-
-        expected = [
-            u'foo=☃'
-        ]
-
-        self.client.create_container(
-            'busybox', 'true',
-            environment=envvars_dict,
-        )
-
-        args = fake_request.call_args
-        self.assertEqual(args[0][1], url_prefix + 'containers/create')
-        self.assertEqual(json.loads(args[1]['data'])['Env'], expected)
-
 
 class ContainerTest(DockerClientTest):
     def test_list_containers(self):
diff --git a/tests/unit/utils_test.py b/tests/unit/utils_test.py
index 2a2759d0..3476f041 100644
--- a/tests/unit/utils_test.py
+++ b/tests/unit/utils_test.py
@@ -185,15 +185,6 @@ class HostConfigTest(base.BaseTestCase):
             InvalidVersion, lambda: create_host_config(
                 version='1.20', kernel_memory=67108864))
 
-    def test_create_host_config_with_pids_limit(self):
-        config = create_host_config(version='1.23', pids_limit=1024)
-        self.assertEqual(config.get('PidsLimit'), 1024)
-
-        with pytest.raises(InvalidVersion):
-            create_host_config(version='1.22', pids_limit=1024)
-        with pytest.raises(TypeError):
-            create_host_config(version='1.22', pids_limit='1024')
-
 
 class UlimitTest(base.BaseTestCase):
     def test_create_host_config_dict_ulimit(self):