Repository: rasterio/rasterio

Issue:
VFS tests fail on Windows due to path strings
Running `py.test -v tests\test_rio_options.py` on Windows fails because of UNIX-style paths in tests.  Specifically, two tests fail:

```
tests\test_rio_options.py::test_file_in_handler_with_vfs FAILED
tests\test_rio_options.py::test_file_in_handler_with_vfs_file FAILED
```

For `test_file_in_handler_with_vfs_file`, I think it can be fixed with:

```
assert retval.endswith(os.path.normpath('tests/data/RGB.byte.tif'))
```

but not sure what to do about `test_file_in_handler_with_vfs`.  My `retval` from line 54 is:

```
'zip://D:\\matt\\rasterio\\tests\\data\\files.zip!/inputs/RGB.byte.tif'
```

so the path to the zip file is Windows, path inside the zip is UNIX.  Both asserts fail here.  Hopefully an easy one ...



Discussion:
For the `test_file_in_handler_with_vfs_file` fix, can you submit a PR for that? sounds like a good idea.

For the `zip://` paths I really don't have a good answer and no way to test for one. Can you confirm that using vfs zip files even works at all on windows? If not, then the issue is beyond testing and we should xfail that test on the windows platform.

@perrygeo, yep I'll submit a PR for the first.  Might kickstart me into being something other than a complainer!

I'll test zip files on Windows as well and let you know if we should xfail the test

@perrygeo, @sgillies: here's what I think I know ... GDAL VSI is really expecting Unix paths throughout, even on Windows systems.  So, when using `gdalinfo`, these two paths work:

```
gdalinfo /vsizip/tests/data/files.zip/RGB.byte.tif
gdalinfo /vsizip/C:/path/to/rasterio/tests/data/files.zip/RGB.byte.tif
```

In https://github.com/mapbox/rasterio/blob/master/rasterio/vfs.py#L61-64, using `os.path.sep` is actually messing up the path for Windows such that it's not readable by GDAL anymore.  For example, with these inputs:

```
path='/RGB.btye.tif', archive='tests/data/files.zip', scheme='zip'
```

the result of vsi_path is:

```
'/vsizip\tests/data/files.zip\/RGB.byte.tif'
```

which is failing.  

I think we're OK, just using:

```
path = path.strip('/')
result = '/'.join(
    ['/vsi{0}'.format(scheme), archive, path])
```

which works on Windows.  Are there OS's that this wouldn't work?  If this looks OK, I can make this change.  This would also need to be addressed in some of the tests

Again with `rasterio/rio/options.py::file_in_handler`, it seems like forcing to forward slashes solves the issues again, e.g. instead of:

```
def file_in_handler(ctx, param, value):
    ...
    if archive and scheme:
        archive = os.path.abspath(archive)
        path = "{0}://{1}!{2}".format(scheme, archive, path)
    ...
    else:
        path = os.path.abspath(path)
    return path
```

we could force forward slashes using:

```
def forward_slashify_abspath(path):
    return '/'.join(os.path.abspath(path).split(os.path.sep))

def file_in_handler(ctx, param, value):
    ...
    if archive and scheme:
        archive = forward_slashify_abspath(archive)
        path = "{0}://{1}!{2}".format(scheme, archive, path)
    ...
    else:
        path = forward_slashify_abspath(path)
    return path
```

This is working correctly with `rio info` with file paths like:

```
rio info zip://C:/path/to/rasterio/tests/data/files.zip!/RGB.byte.tif
rio info zip://tests/data/files.zip!/RGB.byte.tif
rio info zip://./tests/data/files.zip!/RGB.byte.tif
rio info C:/path/to/rasterio/tests/data/RGB.byte.tif
rio info tests/data/RGB.byte.tif
rio info ./tests/data/RGB.byte.tif
rio info C:\path\to\rasterio\tests\data\RGB.byte.tif
rio info .\tests\data\RGB.byte.tif
```

### Tests

This would create some problems with current tests ...

In `tests/test_rio_options::test_file_in_handler_with_vfs`, I think

```
assert retval.startswith('zip:///')
```

will always fail on Windows (unless possibly dealing with UNC pathnames).

In `tests/test_rio_options::test_file_in_handler_no_vfs`, if we do the same fix to force forward slashes, the test will pass:

```
from rasterio.rio.options import forward_slashify_abspath
assert retval == forward_slashify_abspath('tests/data/RGB.byte.tif')
```

I'm getting all tests to pass with these modifications.


Resolving patch:
diff --git a/rasterio/rio/options.py b/rasterio/rio/options.py
--- a/rasterio/rio/options.py
+++ b/rasterio/rio/options.py
@@ -83,6 +83,9 @@ def _cb_key_val(ctx, param, value):
                 out[k] = v
         return out
 
+def abspath_forward_slashes(path):
+    """Return forward-slashed version of os.path.abspath"""
+    return '/'.join(os.path.abspath(path).split(os.path.sep))
 
 def file_in_handler(ctx, param, value):
     """Normalize ordinary filesystem and VFS paths"""
@@ -95,14 +98,14 @@ def file_in_handler(ctx, param, value):
         raise click.BadParameter(
             "Input file {0} does not exist".format(path_to_check))
     if archive and scheme:
-        archive = os.path.abspath(archive)
+        archive = abspath_forward_slashes(archive)
         path = "{0}://{1}!{2}".format(scheme, archive, path)
     elif scheme and scheme.startswith('http'):
         path = "{0}://{1}".format(scheme, path)
     elif scheme == 's3':
         path = "{0}://{1}".format(scheme, path)
     else:
-        path = os.path.abspath(path)
+        path = abspath_forward_slashes(path)
     return path
 
 
diff --git a/rasterio/vfs.py b/rasterio/vfs.py
--- a/rasterio/vfs.py
+++ b/rasterio/vfs.py
@@ -59,8 +59,8 @@ def vsi_path(path, archive=None, scheme=None):
     elif scheme and scheme == 's3':
         result = "/vsis3/{0}".format(path)
     elif scheme and scheme != 'file':
-        path = path.strip(os.path.sep)
-        result = os.path.sep.join(
+        path = path.strip('/')
+        result = '/'.join(
             ['/vsi{0}'.format(scheme), archive, path])
     else:
         result = path


Test patch:
diff --git a/tests/test_rio_options.py b/tests/test_rio_options.py
--- a/tests/test_rio_options.py
+++ b/tests/test_rio_options.py
@@ -28,9 +28,10 @@ def test_file_in_handler_no_vfs_nonexistent():
 
 def test_file_in_handler_no_vfs():
     """file path is expanded to abspath"""
+    from rasterio.rio.options import abspath_forward_slashes
     ctx = MockContext()
     retval = file_in_handler(ctx, 'INPUT', 'tests/data/RGB.byte.tif')
-    assert retval == os.path.abspath('tests/data/RGB.byte.tif')
+    assert retval == abspath_forward_slashes('tests/data/RGB.byte.tif')
 
 
 def test_file_in_handler_bad_scheme():
@@ -52,7 +53,6 @@ def test_file_in_handler_with_vfs():
     """vfs file path path is expanded"""
     ctx = MockContext()
     retval = file_in_handler(ctx, 'INPUT', 'zip://tests/data/files.zip!/inputs/RGB.byte.tif')
-    assert retval.startswith('zip:///')
     assert retval.endswith('tests/data/files.zip!/inputs/RGB.byte.tif')