Repository: docker/docker-py

Issue:
using private image in FROM during build is broken
Example:
```
import docker
from io import BytesIO

dockerfile="""
FROM <some-private-image-on-docker-hub>
CMD ["ls"]
"""

f = BytesIO(dockerfile.encode('utf-8'))

client = docker.APIClient(version='auto')
client.login(username='<user>', password='<pass>')

for l in client.build(fileobj=f, rm=True, tag='test', stream=True, pull=True):
  print(l)
```

This example will error saying that it failed to find the image in FROM. If you add the full registry:

```
client = docker.APIClient(version='auto')
client.login(username='<user>', password='<pass>', registry='https://index.docker.io/v1/')
```

It will succeed. If you leave off the trailing slash on the registry url, it will fail.

python 3.5.2
docker-py 2.4.2

Comments:

Patch:
diff --git a/README.md b/README.md
index 747b98b2..3ff124d7 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,10 @@ The latest stable version [is available on PyPI](https://pypi.python.org/pypi/do
 
     pip install docker
 
+If you are intending to connect to a docker host via TLS, add `docker[tls]` to your requirements instead, or install with pip:
+
+    pip install docker[tls]
+
 ## Usage
 
 Connect to Docker using the default socket or the configuration in your environment:
diff --git a/appveyor.yml b/appveyor.yml
index 1fc67cc0..41cde625 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -3,7 +3,7 @@ version: '{branch}-{build}'
 install:
   - "SET PATH=C:\\Python27-x64;C:\\Python27-x64\\Scripts;%PATH%"
   - "python --version"
-  - "pip install tox==2.1.1 virtualenv==13.1.2"
+  - "pip install tox==2.7.0 virtualenv==15.1.0"
 
 # Build the binary after tests
 build: false
diff --git a/docker/api/build.py b/docker/api/build.py
index cbef4a8b..5d4e7720 100644
--- a/docker/api/build.py
+++ b/docker/api/build.py
@@ -274,7 +274,10 @@ class BuildApiMixin(object):
                         self._auth_configs, registry
                     )
             else:
-                auth_data = self._auth_configs
+                auth_data = self._auth_configs.copy()
+                # See https://github.com/docker/docker-py/issues/1683
+                if auth.INDEX_NAME in auth_data:
+                    auth_data[auth.INDEX_URL] = auth_data[auth.INDEX_NAME]
 
             log.debug(
                 'Sending auth config ({0})'.format(
diff --git a/docker/auth.py b/docker/auth.py
index ec9c45b9..c3fb062e 100644
--- a/docker/auth.py
+++ b/docker/auth.py
@@ -10,7 +10,7 @@ from . import errors
 from .constants import IS_WINDOWS_PLATFORM
 
 INDEX_NAME = 'docker.io'
-INDEX_URL = 'https://{0}/v1/'.format(INDEX_NAME)
+INDEX_URL = 'https://index.{0}/v1/'.format(INDEX_NAME)
 DOCKER_CONFIG_FILENAME = os.path.join('.docker', 'config.json')
 LEGACY_DOCKER_CONFIG_FILENAME = '.dockercfg'
 TOKEN_USERNAME = '<token>'
@@ -118,7 +118,7 @@ def _resolve_authconfig_credstore(authconfig, registry, credstore_name):
     if not registry or registry == INDEX_NAME:
         # The ecosystem is a little schizophrenic with index.docker.io VS
         # docker.io - in that case, it seems the full URL is necessary.
-        registry = 'https://index.docker.io/v1/'
+        registry = INDEX_URL
     log.debug("Looking for auth entry for {0}".format(repr(registry)))
     store = dockerpycreds.Store(credstore_name)
     try:
diff --git a/docker/utils/build.py b/docker/utils/build.py
index 79b72495..d4223e74 100644
--- a/docker/utils/build.py
+++ b/docker/utils/build.py
@@ -26,6 +26,7 @@ def exclude_paths(root, patterns, dockerfile=None):
     if dockerfile is None:
         dockerfile = 'Dockerfile'
 
+    patterns = [p.lstrip('/') for p in patterns]
     exceptions = [p for p in patterns if p.startswith('!')]
 
     include_patterns = [p[1:] for p in exceptions]
diff --git a/requirements.txt b/requirements.txt
index 37541312..f3c61e79 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,16 @@
-requests==2.11.1
-six>=1.4.0
-websocket-client==0.32.0
-backports.ssl_match_hostname>=3.5 ; python_version < '3.5'
-ipaddress==1.0.16 ; python_version < '3.3'
+appdirs==1.4.3
+asn1crypto==0.22.0
+backports.ssl-match-hostname==3.5.0.1
+cffi==1.10.0
+cryptography==1.9
 docker-pycreds==0.2.1
+enum34==1.1.6
+idna==2.5
+ipaddress==1.0.18
+packaging==16.8
+pycparser==2.17
+pyOpenSSL==17.0.0
+pyparsing==2.2.0
+requests==2.14.2
+six==1.10.0
+websocket-client==0.40.0
diff --git a/setup.py b/setup.py
index 31180d23..4a33c8df 100644
--- a/setup.py
+++ b/setup.py
@@ -35,6 +35,16 @@ extras_require = {
     # ssl_match_hostname to verify hosts match with certificates via
     # ServerAltname: https://pypi.python.org/pypi/backports.ssl_match_hostname
     ':python_version < "3.3"': 'ipaddress >= 1.0.16',
+
+    # If using docker-py over TLS, highly recommend this option is
+    # pip-installed or pinned.
+
+    # TODO: if pip installing both "requests" and "requests[security]", the
+    # extra package from the "security" option are not installed (see
+    # https://github.com/pypa/pip/issues/4391).  Once that's fixed, instead of
+    # installing the extra dependencies, install the following instead:
+    # 'requests[security] >= 2.5.2, != 2.11.0, != 2.12.2'
+    'tls': ['pyOpenSSL>=0.14', 'cryptography>=1.3.4', 'idna>=2.0.0'],
 }
 
 version = None


Test patch:
diff --git a/tests/unit/utils_test.py b/tests/unit/utils_test.py
index 7045d23c..4a391fac 100644
--- a/tests/unit/utils_test.py
+++ b/tests/unit/utils_test.py
@@ -768,6 +768,11 @@ class ExcludePathsTest(unittest.TestCase):
             self.all_paths - set(['foo/a.py'])
         )
 
+    def test_single_subdir_single_filename_leading_slash(self):
+        assert self.exclude(['/foo/a.py']) == convert_paths(
+            self.all_paths - set(['foo/a.py'])
+        )
+
     def test_single_subdir_with_path_traversal(self):
         assert self.exclude(['foo/whoops/../a.py']) == convert_paths(
             self.all_paths - set(['foo/a.py'])