67

I'm using a service account for G Suite with full domain delegation. I have a script with readonly access to Google Calendar. The script works just fine, but throws an error (on a background thread?) when I "build" the service. Here's the code:

from oauth2client.service_account import ServiceAccountCredentials
from httplib2 import Http
import urllib
import requests
from apiclient.discovery import build

cal_id = "my_calendar_id@group.calendar.google.com"

scopes                = ['https://www.googleapis.com/auth/calendar.readonly']
credentials           = ServiceAccountCredentials.from_json_keyfile_name('my_cal_key.json', scopes=scopes)
delegated_credentials = credentials.create_delegated('me@mydomain.com')
http_auth             = delegated_credentials.authorize(Http())

# This is the line that throws the error
cal_service  = build('calendar','v3',http=http_auth)

#Then everything continues to work normally
request = cal_service.events().list(calendarId=cal_id)
response = request.execute()

# etc...

The error thrown is:

WARNING:googleapiclient.discovery_cache:file_cache is unavailable when using oauth2client >= 4.0.0
Traceback (most recent call last):
  File "/Users/myuseraccount/anaconda3/lib/python3.5/site-packages/googleapiclient/discovery_cache/__init__.py", line 36, in autodetect
    from google.appengine.api import memcache
ImportError: No module named 'google'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/myuseraccount/anaconda3/lib/python3.5/site-packages/googleapiclient/discovery_cache/file_cache.py", line 33, in <module>
    from oauth2client.contrib.locked_file import LockedFile
ImportError: No module named 'oauth2client.contrib.locked_file'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/myuseraccount/anaconda3/lib/python3.5/site-packages/googleapiclient/discovery_cache/file_cache.py", line 37, in <module>
    from oauth2client.locked_file import LockedFile
ImportError: No module named 'oauth2client.locked_file'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/myuseraccount/anaconda3/lib/python3.5/site-packages/googleapiclient/discovery_cache/__init__.py", line 41, in autodetect
    from . import file_cache
  File "/Users/myuseraccount/anaconda3/lib/python3.5/site-packages/googleapiclient/discovery_cache/file_cache.py", line 41, in <module>
    'file_cache is unavailable when using oauth2client >= 4.0.0')
ImportError: file_cache is unavailable when using oauth2client >= 4.0.0

What's going on here and is this something that I can fix? I've tried reinstalling and/or upgrading the google package.

Clay
  • 2,949
  • 3
  • 38
  • 54
  • Please note that this *is not* an error, but a warning. Things are still working just find (without cache). – Guy Mar 25 '18 at 08:18

8 Answers8

141

I am a bit late to the party here but I had a similar problem today and found the answer here

Solution to only the error : file_cache is unavailable when using oauth2client >= 4.0.0

Solution:

change your discovery.build() to have the field cache_discovery=False i.e

discovery.build(api, version, http=http, cache_discovery=False)
Kache
  • 15,647
  • 12
  • 51
  • 79
Tomos Williams
  • 1,988
  • 1
  • 13
  • 20
  • 6
    Note that this disables the cache and might be detrimental to performance. A better workaround was posted here: https://github.com/google/google-api-python-client/issues/325#issuecomment-274349841 – Chronial Sep 07 '18 at 09:14
  • @Chronial I've added this to my answer to give a little more visibility. definitely better to keep the cache enabled when possible. – Tomos Williams Sep 14 '18 at 12:30
  • @Chronial for performance, negotiating the service lookup is costly and subject to rate limiting, so caching the entire service handler ( result of discovery.build(...), after discovery and auth negotiation is the better approach ). Making discovery caching not a significant optimization point, which is why it was removed. – Paul Kenjora Oct 29 '18 at 23:51
  • @PaulKenjora These are two different things. You cannot cache the output of `discovery.build` – I assume that you mean reusing the returned object. That is of course also a good idea, but you need to be aware that these objects are not multithreading-safe. And discovery caching was not removed, it's just broken in many setups. – Chronial Nov 09 '18 at 17:16
  • 1
    @Chronial that workaround just is a more complex way to do the same thing. The cache never gets reused in a single `build()`, so populating an empty dict is the same as not using caching. – Kache Sep 20 '21 at 19:06
11

The code head of module "google-api-python-client" said...

install_requires = [
     'httplib2>=0.9.2,<1dev',
     'oauth2client>=1.5.0,<5.0.0dev',    <<=============
     'six>=1.6.1,<2dev',
     'uritemplate>=3.0.0,<4dev',
]

So, I have uninstalled oauth2client version 4.0.0

Then, I have downloaded oauth2client 1.5.2 in a tar.gz file from offial python site https://pypi.python.org/pypi/oauth2client/1.5.2

I have installed this downloaded file so I have 1.5.2 version of oauth2client

Package                  Version
------------------------ ---------
certifi                  2016.9.26
discovery                0.0.4
distribute               0.7.3
future                   0.16.0
google-api-python-client 1.5.5
httplib2                 0.9.2
oauth2client             1.5.2
pefile                   2016.3.28
pip                      9.0.1
pyasn1                   0.1.9
pyasn1-modules           0.0.8
PyInstaller              3.2
pypiwin32                219
requests                 2.11.1
rsa                      3.4.2
setuptools               28.8.0
six                      1.10.0
uritemplate              3.0.0

After that, ALL is working OK again and there is no warning message.

Ángel
  • 127
  • 2
  • Given the requirements specified, that's a bug with the module then, right? – Clay Nov 15 '16 at 16:41
  • 5
    Ftr: after uninstalling v4.0.0 you can install an older version directly through pip: `$ pip install oauth2client==3.0.0`. Cf [releases](https://github.com/google/oauth2client/releases). – dtk Dec 01 '16 at 15:07
  • 1
    this comand for those who don't know command to uninstall a package: `pip uninstall oauth2client` – Huy - Logarit Mar 06 '17 at 13:22
  • This helps. Thanks! – Akshay Maldhure Sep 21 '17 at 12:29
  • 1
    Tomos's answer is a simple code fix which doesn't require severely downgrading a package https://stackoverflow.com/a/44518587/4047679 – raphael Oct 14 '17 at 21:24
4

Tried all the solutions that were listed, but none of them worked. Until I tried the (simple) suggestion from @dtk that was listed somewhere in the comments :

Install an older version of oauth2client by running:

pip install oauth2client==3.0.0

Now everything works fine for me. Thank you @dtk !

Jérémy
  • 405
  • 1
  • 4
  • 22
1

I did not want to downgrade my oauth2client. You can use oauth2client 4.1.2 when you set cache_discovery=False for apiclient.discovery.build. This simple solution silenced the error:

service = discovery.build(api_name, 
                          api_version, 
                          credentials=credentials, 
                          cache_discovery=False)

Source

Cloudkollektiv
  • 11,852
  • 3
  • 44
  • 71
0

To use the Google API for Python client, you need to install it first as Google API is not built-in within the Python modules. The instruction is found in Install the Library.

Installation

You can either use a package manager or download and install the Python client library manually:

Managed installation

Use pip or setuptools to manage your installation (you might need to run sudo first):

pip (preferred):

$ pip install --upgrade google-api-python-client

Setuptools: Use the easy_install tool included in the setuptools package:

$ easy_install --upgrade google-api-python-client

ReyAnthonyRenacia
  • 17,219
  • 5
  • 37
  • 56
  • Thanks, but I've already done that. Like I said, the script works just fine -- it's only the one line that triggers something to throw an error on a background thread. – Clay Oct 21 '16 at 12:47
  • Kindly check if this was the one mentioned in this [No module named locked_file #414](https://github.com/google/oauth2client/issues/414) which seems to be resolved in [Fix incompatibility with oauth2client v2.0.0 #182](https://github.com/google/google-api-python-client/pull/182). – ReyAnthonyRenacia Oct 21 '16 at 12:52
  • 1
    To be honest, I can't tell. I installed with pip using the instructions from the GitHub page: `pip install --upgrade google-api-python-client`, so I have version 1.5.4 of the package. There's a contrib submodule, but I don't see a `locked_file` submodule anywhere in the package directory. – Clay Oct 21 '16 at 15:11
  • 1
    @Clay: See here: https://github.com/google/google-api-python-client/blob/master/googleapiclient/discovery_cache/file_cache.py#L41 – Steve D Nov 14 '16 at 18:28
0

Fwiw this is a reposting of my answer here

Since they are technically warnings (not errors), if you don't have direct access to the call, you can do this wherever you instantiate the service to suppress them:

import logging logging.getLogger('googleapiclient.discovery_cache').setLevel(logging.ERROR)

With thanks to theacodes who gave that answer here (but with a missing 'n' in 'client' that seems to have led to a lot of downvotes there).

See also the discussion here

scharfmn
  • 3,561
  • 7
  • 38
  • 53
0

to add to the selected answer, if the build function is called by a dependency, and there is no easy way to update it's code, this code can be used to force cache_discovery to be False:

import googleapiclient.discovery

_build = googleapiclient.discovery.build


def no_cache_build(*args, **kw):
    kw["cache_discovery"] = False
    return _build(*args, **kw)


googleapiclient.discovery.build = no_cache_build
lev
  • 3,986
  • 4
  • 33
  • 46
-1

Here is how I use google-api-python-client to build a service on Cloud Functions.

# for Cloud Functions use
def get_service():
    import googleapiclient.discovery
    return googleapiclient.discovery.build('compute', 'v1',  cache_discovery=False)

And finally it worked.

Thai Boy
  • 141
  • 2
  • 5