Repository: docker/docker-py

Issue:
Containers.create() cannot handle binds with Windows paths containing a ':'
### Issue
Containers.create() is unable to handle binds with Windows paths containing a ':' due to the string splitting logic in _host_volume_from_bind(bind). Given a bind of the form 'foo:c:/foo:rw', the path is identified as 'c' rather than 'c:/foo'.

### Environment
Windows 10 Desktop 1709
docker==2.6.0
docker-pycreds==0.2.1
Python 2.7.14
Client:
    Version:      17.06.0-dev
    API version:  1.34
    Go version:   go1.8.5
    Git commit:   e2ada66
    Built:        Thu Nov  2 23:37:13 2017
    OS/Arch:      windows/amd64
Server:
    Version:      17.06.0-dev
    API version:  1.34 (minimum version 1.24)
    Go version:   go1.8.5
    Git commit:   462d791
    Built:        Thu Nov  2 23:41:07 2017
    OS/Arch:      windows/amd64
    Experimental: false




Discussion:
@shin Can you please take a look at this one? This is a blocker for us.

Resolving patch:
diff --git a/docker/models/containers.py b/docker/models/containers.py
--- a/docker/models/containers.py
+++ b/docker/models/containers.py
@@ -1,4 +1,5 @@
 import copy
+import ntpath
 from collections import namedtuple
 
 from ..api import APIClient
@@ -995,20 +996,25 @@ def _create_container_args(kwargs):
         # sort to make consistent for tests
         create_kwargs['ports'] = [tuple(p.split('/', 1))
                                   for p in sorted(port_bindings.keys())]
-    binds = create_kwargs['host_config'].get('Binds')
-    if binds:
-        create_kwargs['volumes'] = [_host_volume_from_bind(v) for v in binds]
+    if volumes:
+        if isinstance(volumes, dict):
+            create_kwargs['volumes'] = [
+                v.get('bind') for v in volumes.values()
+            ]
+        else:
+            create_kwargs['volumes'] = [
+                _host_volume_from_bind(v) for v in volumes
+            ]
     return create_kwargs
 
 
 def _host_volume_from_bind(bind):
-    bits = bind.split(':')
-    if len(bits) == 1:
-        return bits[0]
-    elif len(bits) == 2 and bits[1] in ('ro', 'rw'):
-        return bits[0]
+    drive, rest = ntpath.splitdrive(bind)
+    bits = rest.split(':', 1)
+    if len(bits) == 1 or bits[1] in ('ro', 'rw'):
+        return drive + bits[0]
     else:
-        return bits[1]
+        return bits[1].rstrip(':ro').rstrip(':rw')
 
 
 ExecResult = namedtuple('ExecResult', 'exit_code,output')


Test patch:
diff --git a/tests/unit/models_containers_test.py b/tests/unit/models_containers_test.py
--- a/tests/unit/models_containers_test.py
+++ b/tests/unit/models_containers_test.py
@@ -102,6 +102,7 @@ def test_create_container_args(self):
                 'volumename:/mnt/vol3',
                 '/volumewithnohostpath',
                 '/anothervolumewithnohostpath:ro',
+                'C:\\windows\\path:D:\\hello\\world:rw'
             ],
             volumes_from=['container'],
             working_dir='/code'
@@ -120,7 +121,8 @@ def test_create_container_args(self):
                     '/var/www:/mnt/vol1:ro',
                     'volumename:/mnt/vol3',
                     '/volumewithnohostpath',
-                    '/anothervolumewithnohostpath:ro'
+                    '/anothervolumewithnohostpath:ro',
+                    'C:\\windows\\path:D:\\hello\\world:rw'
                 ],
                 'BlkioDeviceReadBps': [{'Path': 'foo', 'Rate': 3}],
                 'BlkioDeviceReadIOps': [{'Path': 'foo', 'Rate': 3}],
@@ -191,7 +193,8 @@ def test_create_container_args(self):
                 '/mnt/vol1',
                 '/mnt/vol3',
                 '/volumewithnohostpath',
-                '/anothervolumewithnohostpath'
+                '/anothervolumewithnohostpath',
+                'D:\\hello\\world'
             ],
             working_dir='/code'
         )