Repository: googleapis/google-api-python-client

Issue:
oauth2client removed from setup.py deps but still imported
Building on #521, dropping `oauth2client` from `setup.py` in #499 is causing problems importing `apiclient.discovery`:

```
Python 3.6.5 (default, Mar 31 2018, 13:05:03)
[GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from apiclient import discovery
Traceback (most recent call last):
  File "/Users/eric/projects/google-api-python-client/googleapiclient/sample_tools.py", line 32, in <module>
    from oauth2client import client
ModuleNotFoundError: No module named 'oauth2client'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/eric/projects/google-api-python-client/apiclient/__init__.py", line 13, in <module>
    from googleapiclient import sample_tools
  File "/Users/eric/projects/google-api-python-client/googleapiclient/sample_tools.py", line 36, in <module>
    raise ImportError('googleapiclient.sample_tools requires oauth2client. Please install oauth2client and try again.')
ImportError: googleapiclient.sample_tools requires oauth2client. Please install oauth2client and try again.
```

```
$ git grep oauth2client | grep -v -e docs\/ -e CHANGELO
.travis.yml:    env: TOXENV=py27-oauth2client1
.travis.yml:    env: TOXENV=py27-oauth2client2
.travis.yml:    env: TOXENV=py27-oauth2client3
.travis.yml:    env: TOXENV=py27-oauth2client4
.travis.yml:    env: TOXENV=py34-oauth2client1
.travis.yml:    env: TOXENV=py34-oauth2client2
.travis.yml:    env: TOXENV=py34-oauth2client3
.travis.yml:    env: TOXENV=py34-oauth2client4
.travis.yml:    env: TOXENV=py35-oauth2client1
.travis.yml:    env: TOXENV=py35-oauth2client2
.travis.yml:    env: TOXENV=py35-oauth2client3
.travis.yml:    env: TOXENV=py35-oauth2client4
.travis.yml:    env: TOXENV=py36-oauth2client1
.travis.yml:    env: TOXENV=py36-oauth2client2
.travis.yml:    env: TOXENV=py36-oauth2client3
.travis.yml:    env: TOXENV=py36-oauth2client4
expandsymlinks.py:IGNORE_IN_SAMPLES = set(['googleapiclient', 'oauth2client', 'uritemplate'])
googleapiclient/_auth.py:"""Helpers for authentication using oauth2client or google-auth."""
googleapiclient/_auth.py:    import oauth2client
googleapiclient/_auth.py:    import oauth2client.client
googleapiclient/_auth.py:        return oauth2client.client.GoogleCredentials.get_application_default()
googleapiclient/_auth.py:            'google-auth or oauth2client.')
googleapiclient/_auth.py:            oauth2client.client.Credentials]): The credentials to scope.
googleapiclient/_auth.py:            oauth2client.client.Credentials]: The scoped credentials.
googleapiclient/_auth.py:            oauth2client.client.Credentials]): The credentials to use.
googleapiclient/_auth.py:    # credentials could be a AuthorizedHttp or an oauth2client-decorated
googleapiclient/_auth.py:    # oauth2client and google-auth have the same interface for this.
googleapiclient/discovery.py:    credentials: oauth2client.Credentials or
googleapiclient/discovery.py:    credentials: oauth2client.Credentials or
googleapiclient/discovery_cache/file_cache.py:  from oauth2client.contrib.locked_file import LockedFile
googleapiclient/discovery_cache/file_cache.py:  # oauth2client < 2.0.0
googleapiclient/discovery_cache/file_cache.py:    from oauth2client.locked_file import LockedFile
googleapiclient/discovery_cache/file_cache.py:    # oauth2client > 4.0.0 or google-auth
googleapiclient/discovery_cache/file_cache.py:      'file_cache is unavailable when using oauth2client >= 4.0.0 or google-auth')
googleapiclient/sample_tools.py:    from oauth2client import client
googleapiclient/sample_tools.py:    from oauth2client import file
googleapiclient/sample_tools.py:    from oauth2client import tools
googleapiclient/sample_tools.py:    raise ImportError('googleapiclient.sample_tools requires oauth2client. Please install oauth2client and try again.')
samples/README.md:    <td>Demonstrates oauth2client and the Google+ API from Django</td>
samples/README.md:    <td>Demonstrates oauth2client and the Google+ API from Django</td>
samples/README.md:    <td>Demonstrates oauth2client and the Google+ API from Django</td>
samples/adexchangeseller/generate_report.py:from oauth2client import client
samples/adexchangeseller/generate_report_with_paging.py:from oauth2client import client
samples/adexchangeseller/get_all_ad_clients.py:from oauth2client import client
samples/adexchangeseller/get_all_ad_units.py:from oauth2client import client
samples/adexchangeseller/get_all_ad_units_for_custom_channel.py:from oauth2client import client
samples/adexchangeseller/get_all_alerts.py:from oauth2client import client
samples/adexchangeseller/get_all_custom_channels.py:from oauth2client import client
samples/adexchangeseller/get_all_custom_channels_for_ad_unit.py:from oauth2client import client
samples/adexchangeseller/get_all_dimensions.py:from oauth2client import client
samples/adexchangeseller/get_all_metrics.py:from oauth2client import client
samples/adexchangeseller/get_all_preferred_deals.py:from oauth2client import client
samples/adexchangeseller/get_all_saved_reports.py:from oauth2client import client
samples/adexchangeseller/get_all_url_channels.py:from oauth2client import client
samples/analytics/core_reporting_v3_reference.py:from oauth2client.client import AccessTokenRefreshError
samples/analytics/hello_analytics_api_v3.py:from oauth2client.client import AccessTokenRefreshError
samples/analytics/management_v3_reference.py:from oauth2client.client import AccessTokenRefreshError
samples/appengine/main.py:from oauth2client import client
samples/appengine/main.py:from oauth2client.contrib import appengine
samples/audit/audit.py:from oauth2client import client
samples/blogger/blogger.py:from oauth2client import client
samples/calendar_api/calendar_sample.py:from oauth2client import client
samples/coordinate/coordinate.py:from oauth2client import client
samples/django_sample/README:Sample app demonstrating using oauth2client and the Google+ API from Django.
samples/django_sample/plus/models.py:from oauth2client.contrib.django_util.models import CredentialsField
samples/django_sample/plus/views.py:from oauth2client.contrib import xsrfutil
samples/django_sample/plus/views.py:from oauth2client.client import flow_from_clientsecrets
samples/django_sample/plus/views.py:from oauth2client.contrib.django_util.storage import DjangoORMStorage
samples/django_sample/requirements.txt:oauth2client==4.1.2
samples/groupssettings/groupsettings.py:from oauth2client.client import flow_from_clientsecrets
samples/groupssettings/groupsettings.py:from oauth2client.file import Storage
samples/groupssettings/groupsettings.py:from oauth2client.tools import run
samples/plus/plus.py:from oauth2client import client
samples/prediction/prediction.py:from oauth2client import client
samples/service_account/tasks.py:from oauth2client.service_account import ServiceAccountCredentials
samples/storage_serviceaccount_appengine/main.py:from oauth2client.contrib.appengine import AppAssertionCredentials
samples/tasks_appengine/main.py:from oauth2client.contrib.appengine import OAuth2Decorator
samples/urlshortener/urlshortener.py:from oauth2client import client
tests/test__auth.py:import oauth2client.client
tests/test__auth.py:            'oauth2client.client.GoogleCredentials.get_application_default')
tests/test__auth.py:        credentials = mock.Mock(spec=oauth2client.client.Credentials)
tests/test__auth.py:        credentials = mock.Mock(spec=oauth2client.client.GoogleCredentials)
tests/test__auth.py:        credentials = mock.Mock(spec=oauth2client.client.Credentials)
tests/test_discovery.py:from oauth2client import GOOGLE_TOKEN_URI
tests/test_discovery.py:from oauth2client.client import OAuth2Credentials, GoogleCredentials
tests/test_discovery.py:  def test_oauth2client_credentials(self):
tests/test_http.py:from oauth2client.client import Credentials
tools/gae-zip-creator.sh:export SANITY_MODS="httplib2 apiclient uritemplate oauth2client"
tox.ini:envlist = py{27,34,35,36}-oauth2client{1,2,3,4}
tox.ini:       oauth2client1: oauth2client<2dev
tox.ini:       oauth2client2: oauth2client>=2,<=3dev
tox.ini:       oauth2client3: oauth2client>=3,<=4dev
tox.ini:       oauth2client4: oauth2client>=4,<=5dev
```



Discussion:
It looks like [googleapiclient/sample_tools.py](https://github.com/google/google-api-python-client/blob/master/googleapiclient/sample_tools.py) is rife with dependence on `oauth2client`, and it gets imported unconditionally into `apiclient`. I'm not sure how best to remedy this.
Thanks for this. `sample_tools` already sends a helpful message about oauth2client, but it seems the old alias package try to import it without checking. I would definitely recommend using `googleapiclient` over `apiclient` as the later is a deprecated alias, but we should certainly fix it to work.
Thanks for the tip on switching to `googleapiclient`. I copypasted the [quickstart code for the Sheets API](https://developers.google.com/sheets/api/quickstart/python), which uses `oauth2client` directly and imports `apiclient`. I reported this as Documentation Feedback over there.

Resolving patch:
diff --git a/googleapiclient/sample_tools.py b/googleapiclient/sample_tools.py
--- a/googleapiclient/sample_tools.py
+++ b/googleapiclient/sample_tools.py
@@ -28,14 +28,6 @@
 from googleapiclient import discovery
 from googleapiclient.http import build_http
 
-try:
-    from oauth2client import client
-    from oauth2client import file
-    from oauth2client import tools
-except ImportError:
-    raise ImportError('googleapiclient.sample_tools requires oauth2client. Please install oauth2client and try again.')
-
-
 def init(argv, name, version, doc, filename, scope=None, parents=[], discovery_filename=None):
   """A common initialization routine for samples.
 
@@ -60,6 +52,13 @@ def init(argv, name, version, doc, filename, scope=None, parents=[], discovery_f
     A tuple of (service, flags), where service is the service object and flags
     is the parsed command-line flags.
   """
+  try:
+      from oauth2client import client
+      from oauth2client import file
+      from oauth2client import tools
+  except ImportError:
+      raise ImportError('googleapiclient.sample_tools requires oauth2client. Please install oauth2client and try again.')
+
   if scope is None:
     scope = 'https://www.googleapis.com/auth/' + name
 
diff --git a/samples/maps_engine/maps_engine.py b/samples/maps_engine/maps_engine.py
--- a/samples/maps_engine/maps_engine.py
+++ b/samples/maps_engine/maps_engine.py
@@ -47,8 +47,8 @@
 import sys
 import time
 
-from apiclient import sample_tools
-from apiclient.http import MediaFileUpload
+from googleapiclient import sample_tools
+from googleapiclient.http import MediaFileUpload
 
 logging.basicConfig(level=logging.INFO)
 
diff --git a/samples/prediction/prediction.py b/samples/prediction/prediction.py
--- a/samples/prediction/prediction.py
+++ b/samples/prediction/prediction.py
@@ -39,12 +39,10 @@
               'marccohen@google.com (Marc Cohen)')
 
 import argparse
-import os
 import pprint
 import sys
 import time
 
-from apiclient import discovery
 from apiclient import sample_tools
 from oauth2client import client
 


Test patch: