Repository: rasterio/rasterio

Issue:
aws profile not passed to Env
We take the `--aws-profile` argument to the main `rio` function [here](https://github.com/mapbox/rasterio/blob/master/rasterio/rio/main.py#L77) and save it to the  command context as `ctx.obj['aws_profile']`.

But as far as I can tell, we never pass the parameter into the environment constructor `Env(profile_name=...)`. We could do something like this in `rio info` at https://github.com/mapbox/rasterio/blob/master/rasterio/rio/info.py#L67

```
aws_profile = ctx.obj.get('aws_profile', None)
...
with rasterio.Env(CPL_DEBUG=(verbosity > 2), profile_name=aws_profile):
```
- [ ] Not sure the best way to test this.
- [ ] What other commands need the same treatment? Do we have an explicit list of s3/http-capable rio commands? 

cc @jacquestardie 



Discussion:
Thanks for tracking this @perrygeo 🙏 


Resolving patch:
diff --git a/rasterio/rio/env.py b/rasterio/rio/env.py
--- a/rasterio/rio/env.py
+++ b/rasterio/rio/env.py
@@ -1,5 +1,6 @@
 """Fetch and edit raster dataset metadata from the command line."""
 
+import json
 import logging
 
 import click
@@ -7,18 +8,21 @@
 import rasterio
 
 
-@click.command(short_help="Print information about the rio environment.")
+@click.command(short_help="Print information about the Rasterio environment.")
 @click.option('--formats', 'key', flag_value='formats', default=True,
               help="Enumerate the available formats.")
+@click.option('--credentials', 'key', flag_value='credentials', default=False,
+              help="Print AWS credentials.")
 @click.pass_context
 def env(ctx, key):
-    """Print information about the Rasterio environment: available
-    formats, etc.
-    """
-    verbosity = (ctx.obj and ctx.obj.get('verbosity')) or 1
-    stdout = click.get_text_stream('stdout')
-    with rasterio.Env(CPL_DEBUG=(verbosity > 2)) as env:
+    """Print information about the Rasterio environment."""
+    with ctx.obj['env'] as env:
         if key == 'formats':
             for k, v in sorted(env.drivers().items()):
-                stdout.write("%s: %s\n" % (k, v))
-            stdout.write('\n')
+                click.echo("{0}: {1}".format(k, v))
+        elif key == 'credentials':
+            env.get_aws_credentials()
+            click.echo(json.dumps({
+                'aws_access_key_id': env._creds.access_key,
+                'aws_secret_access_key': env._creds.secret_key,
+                'aws_session_token': env._creds.token}))
diff --git a/rasterio/rio/info.py b/rasterio/rio/info.py
--- a/rasterio/rio/info.py
+++ b/rasterio/rio/info.py
@@ -1,4 +1,4 @@
-"""$ rio info"""
+"""Command access to dataset metadata, stats, and more."""
 
 
 import json
@@ -61,48 +61,45 @@ def info(ctx, input, aspect, indent, namespace, meta_member, verbose, bidx,
 
     Optionally print a single metadata item as a string.
     """
-    verbosity = ctx.obj.get('verbosity')
-    mode = 'r' if (verbose or meta_member == 'stats') else 'r-'
     try:
-        with rasterio.Env(CPL_DEBUG=(verbosity > 2)):
-            with rasterio.open(input, mode) as src:
-                info = dict(src.profile)
-                info['shape'] = info['height'], info['width']
-                info['bounds'] = src.bounds
-                proj4 = src.crs.to_string()
-                if proj4.startswith('+init=epsg'):
-                    proj4 = proj4.split('=')[1].upper()
-                info['crs'] = proj4
-                info['res'] = src.res
-                info['colorinterp'] = [src.colorinterp(i).name
-                                       for i in src.indexes]
-                if proj4 != '':
-                    info['lnglat'] = src.lnglat()
-                if verbose:
-                    stats = [{'min': float(b.min()),
-                              'max': float(b.max()),
-                              'mean': float(b.mean())
-                              } for b in src.read(masked=masked)]
-                    info['stats'] = stats
-                    info['checksum'] = [src.checksum(i) for i in src.indexes]
-                if aspect == 'meta':
-                    if meta_member == 'stats':
-                        band = src.read(bidx, masked=masked)
-                        click.echo('%f %f %f' % (
-                            float(band.min()),
-                            float(band.max()),
-                            float(band.mean())))
-                    elif meta_member == 'checksum':
-                        click.echo(str(src.checksum(bidx)))
-                    elif meta_member:
-                        if isinstance(info[meta_member], (list, tuple)):
-                            click.echo(" ".join(map(str, info[meta_member])))
-                        else:
-                            click.echo(info[meta_member])
+        with ctx.obj['env'], rasterio.open(input) as src:
+            info = dict(src.profile)
+            info['shape'] = info['height'], info['width']
+            info['bounds'] = src.bounds
+            proj4 = src.crs.to_string()
+            if proj4.startswith('+init=epsg'):
+                proj4 = proj4.split('=')[1].upper()
+            info['crs'] = proj4
+            info['res'] = src.res
+            info['colorinterp'] = [src.colorinterp(i).name
+                                   for i in src.indexes]
+            if proj4 != '':
+                info['lnglat'] = src.lnglat()
+            if verbose:
+                stats = [{'min': float(b.min()),
+                          'max': float(b.max()),
+                          'mean': float(b.mean())
+                          } for b in src.read(masked=masked)]
+                info['stats'] = stats
+                info['checksum'] = [src.checksum(i) for i in src.indexes]
+            if aspect == 'meta':
+                if meta_member == 'stats':
+                    band = src.read(bidx, masked=masked)
+                    click.echo('%f %f %f' % (
+                        float(band.min()),
+                        float(band.max()),
+                        float(band.mean())))
+                elif meta_member == 'checksum':
+                    click.echo(str(src.checksum(bidx)))
+                elif meta_member:
+                    if isinstance(info[meta_member], (list, tuple)):
+                        click.echo(" ".join(map(str, info[meta_member])))
                     else:
-                        click.echo(json.dumps(info, indent=indent))
-                elif aspect == 'tags':
-                    click.echo(
-                        json.dumps(src.tags(ns=namespace), indent=indent))
+                        click.echo(info[meta_member])
+                else:
+                    click.echo(json.dumps(info, indent=indent))
+            elif aspect == 'tags':
+                click.echo(
+                    json.dumps(src.tags(ns=namespace), indent=indent))
     except Exception:
         raise click.Abort()
diff --git a/rasterio/rio/main.py b/rasterio/rio/main.py
--- a/rasterio/rio/main.py
+++ b/rasterio/rio/main.py
@@ -60,12 +60,11 @@ def gdal_version_cb(ctx, param, value):
 @click.group()
 @cligj.verbose_opt
 @cligj.quiet_opt
-@click.option(
-    '--aws-profile',
-    help="Use a specific profile from your shared AWS credentials file")
+@click.option('--aws-profile',
+              help="Selects a profile from your shared AWS credentials file")
 @click.version_option(version=rasterio.__version__, message='%(version)s')
-@click.option(
-    '--gdal-version', is_eager=True, is_flag=True, callback=gdal_version_cb)
+@click.option('--gdal-version', is_eager=True, is_flag=True,
+              callback=gdal_version_cb)
 @click.pass_context
 def main_group(ctx, verbose, quiet, aws_profile, gdal_version):
     """Rasterio command line interface.
@@ -75,3 +74,5 @@ def main_group(ctx, verbose, quiet, aws_profile, gdal_version):
     ctx.obj = {}
     ctx.obj['verbosity'] = verbosity
     ctx.obj['aws_profile'] = aws_profile
+    ctx.obj['env'] = rasterio.Env(CPL_DEBUG=(verbosity > 2),
+                                  profile_name=aws_profile)


Test patch:
diff --git a/tests/test_env.py b/tests/test_env.py
--- a/tests/test_env.py
+++ b/tests/test_env.py
@@ -126,8 +126,9 @@ def test_aws_session_credentials(gdalenv):
 
 def test_with_aws_session_credentials(gdalenv):
     """Create an Env with a boto3 session."""
-    with rasterio.Env(aws_access_key_id='id', aws_secret_access_key='key',
-             aws_session_token='token', region_name='null-island-1') as s:
+    with rasterio.Env(
+            aws_access_key_id='id', aws_secret_access_key='key',
+            aws_session_token='token', region_name='null-island-1') as s:
         expected = default_options.copy()
         assert getenv() == rasterio.env._env.options == expected
         s.get_aws_credentials()
@@ -211,3 +212,21 @@ def test_https_rio_info(runner):
     result = runner.invoke(main_group, ['info', httpstif])
     assert result.exit_code == 0
     assert '"crs": "EPSG:32645"' in result.output
+
+
+def test_rio_env_credentials_options(tmpdir, monkeypatch, runner):
+    """Confirm that --aws-profile option works."""
+    credentials_file = tmpdir.join('credentials')
+    credentials_file.write("[testing]\n"
+                           "aws_access_key_id = foo\n"
+                           "aws_secret_access_key = bar\n"
+                           "aws_session_token = baz")
+    monkeypatch.setenv('AWS_SHARED_CREDENTIALS_FILE', str(credentials_file))
+    monkeypatch.setenv('AWS_SESSION_TOKEN', 'ignore_me')
+    result = runner.invoke(
+        main_group, ['--aws-profile', 'testing', 'env', '--credentials'])
+    assert result.exit_code == 0
+    assert '"aws_access_key_id": "foo"' in result.output
+    assert '"aws_secret_access_key": "bar"' in result.output
+    assert '"aws_session_token": "baz"' in result.output
+    monkeypatch.undo()