_default.default() now handles ImportErrors for optional dependencies. (#313)

* _default.default() now handles ImportErrors for optional dependencies.
diff --git a/google/auth/_default.py b/google/auth/_default.py
index c93b489..27de58d 100644
--- a/google/auth/_default.py
+++ b/google/auth/_default.py
@@ -172,7 +172,12 @@
 
 def _get_gae_credentials():
     """Gets Google App Engine App Identity credentials and project ID."""
-    from google.auth import app_engine
+    # While this library is normally bundled with app_engine, there are
+    # some cases where it's not available, so we tolerate ImportError.
+    try:
+        import google.auth.app_engine as app_engine
+    except ImportError:
+        return None, None
 
     try:
         credentials = app_engine.Credentials()
@@ -188,8 +193,14 @@
     # to require no arguments. So, we'll use the _http_client transport which
     # uses http.client. This is only acceptable because the metadata server
     # doesn't do SSL and never requires proxies.
-    from google.auth import compute_engine
-    from google.auth.compute_engine import _metadata
+
+    # While this library is normally bundled with compute_engine, there are
+    # some cases where it's not available, so we tolerate ImportError.
+    try:
+        from google.auth import compute_engine
+        from google.auth.compute_engine import _metadata
+    except ImportError:
+        return None, None
 
     if request is None:
         request = google.auth.transport._http_client.Request()
diff --git a/tests/test__default.py b/tests/test__default.py
index d7d537c..3fb0fa1 100644
--- a/tests/test__default.py
+++ b/tests/test__default.py
@@ -235,6 +235,15 @@
     assert project_id == mock.sentinel.project
 
 
+def test__get_gae_credentials_no_app_engine():
+    import sys
+    with mock.patch.dict('sys.modules'):
+        sys.modules['google.auth.app_engine'] = None
+        credentials, project_id = _default._get_gae_credentials()
+        assert credentials is None
+        assert project_id is None
+
+
 def test__get_gae_credentials_no_apis():
     assert _default._get_gae_credentials() == (None, None)
 
@@ -275,6 +284,15 @@
     assert project_id is None
 
 
+def test__get_gce_credentials_no_compute_engine():
+    import sys
+    with mock.patch.dict('sys.modules'):
+        sys.modules['google.auth.compute_engine'] = None
+        credentials, project_id = _default._get_gce_credentials()
+        assert credentials is None
+        assert project_id is None
+
+
 @mock.patch(
     'google.auth.compute_engine._metadata.ping', return_value=False,
     autospec=True)
@@ -366,3 +384,21 @@
     assert project_id == mock.sentinel.project_id
     with_scopes.assert_called_once_with(
         mock.sentinel.credentials, scopes)
+
+
+@mock.patch(
+    'google.auth._default._get_explicit_environ_credentials',
+    return_value=(mock.sentinel.credentials, mock.sentinel.project_id),
+    autospec=True)
+def test_default_no_app_engine_compute_engine_module(unused_get):
+    """
+    google.auth.compute_engine and google.auth.app_engine are both optional
+    to allow not including them when using this package. This verifies
+    that default fails gracefully if these modules are absent
+    """
+    import sys
+    with mock.patch.dict('sys.modules'):
+        sys.modules['google.auth.compute_engine'] = None
+        sys.modules['google.auth.app_engine'] = None
+        assert _default.default() == (
+            mock.sentinel.credentials, mock.sentinel.project_id)