people.connections.list not returning contacts using Python Client Library
Asked Answered
H

4

12

I'm trying to programmatically access the list of contacts on my own personal Google Account using the Python Client Library

This is a script that will run on a server without user input, so I have it set up to use credentials from a Service Account I set up. My Google API console setup looks like this.

enter image description here

I'm using the following basic script, pulled from the examples provided in the API docs -

import json
from httplib2 import Http

from oauth2client.service_account import ServiceAccountCredentials
from apiclient.discovery import build

# Only need read-only access
scopes = ['https://www.googleapis.com/auth/contacts.readonly']

# JSON file downloaded from Google API Console when creating the service account
credentials = ServiceAccountCredentials.from_json_keyfile_name(
    'keep-in-touch-5d3ebc885d4c.json', scopes)

# Build the API Service
service = build('people', 'v1', credentials=credentials)

# Query for the results
results = service.people().connections().list(resourceName='people/me').execute()

# The result set is a dictionary and should contain the key 'connections'
connections = results.get('connections', [])

print connections  #=> [] - empty!

When I hit the API it returns a result set without any 'connections' key. Specifically it returns -

>>> results
{u'nextSyncToken': u'CNP66PXjKhIBMRj-EioECAAQAQ'}

Is there something pertaining to my setup or code that's incorrect? Is there a way to see the response HTTP status code or get any further detail about what it's trying to do?

Thanks!

Side note: When I try it using the "Try it!" feature in the API docs, it correctly returns my contacts. Although I doubt that uses the client library and instead relies on user authorization via OAuth

Hanselka answered 31/7, 2016 at 2:25 Comment(2)
Hey, I have exactly the same issue. Were you able to solve it? Thanks.Urania
@Urania - I did not, sorry :(Hanselka
H
6

The personFields mask is required. Specify one or more valid paths. Valid paths are documented at https://developers.google.com/people/api/rest/v1/people.connections/list/.

Additionally, use fields mask to specify which fields are included in a partial response.

Instead of:

results = service.people().connections().list(resourceName='people/me').execute() 

... try:

results = service.people().connections().list(resourceName='people/me',personFields='names,emailAddresses',fields='connections,totalItems,nextSyncToken').execute() 
Houchens answered 31/8, 2017 at 20:19 Comment(0)
M
2

Here is a working demo. I just tested it right now. Python 3.5.2

google-api-python-client==1.6.4
httplib2==0.10.3
oauth2client==4.1.2

You can save it to demo.py and then just run it. I left the create_contact function in case you might want to use it and have one more example on the API usage.

CLIENT_ID and CLIENT_SECRET are environment variables so I don't accidentally share that in code.

"""Google API stuff."""

import httplib2
import json
import os

from apiclient.discovery import build
from oauth2client.file import Storage
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run_flow


CLIENT_ID = os.environ['CLIENT_ID']
CLIENT_SECRET = os.environ['CLIENT_SECRET']
SCOPE = 'https://www.googleapis.com/auth/contacts'
USER_AGENT = 'JugDemoStackOverflow/v0.1'

def make_flow():
    """Make flow."""
    flow = OAuth2WebServerFlow(
        client_id=CLIENT_ID,
        client_secret=CLIENT_SECRET,
        scope=SCOPE,
        user_agent=USER_AGENT,
    )
    return flow


def get_people():
    """Return a people_service."""
    flow = make_flow()
    storage = Storage('info.dat')
    credentials = storage.get()
    if credentials is None or credentials.invalid:
        credentials = run_flow(flow, storage)

    http = httplib2.Http()
    http = credentials.authorize(http)
    people_service = build(serviceName='people', version='v1', http=http)
    return people_service


def create_contact(people, user):
    """Create a Google Contact."""
    request = people.createContact(
        body={
            'names': [{'givenName': user.name}],
            'phoneNumbers': [
                {'canonicalForm': user.phone, 'value': user.phone}],
        }
    )
    return request.execute()


def demo():
    """Demonstrate getting contacts from Google People."""
    people_service = get_people()
    people = people_service.people()
    connections = people.connections().list(
        resourceName='people/me',
        personFields='names,emailAddresses,phoneNumbers',
        pageSize=2000,
    )
    result = connections.execute()
    s = json.dumps(result)
    # with open('contacts.json', 'w') as f:
    #     f.write(s)
    return s


if __name__ == '__main__':
    print(demo())
Masonry answered 18/11, 2017 at 20:54 Comment(0)
A
0

With service account, in DwD - G Suite Domain-wide Delegation, is necessary impersonate or delegate user in this way

delegate = credentials.create_delegated('[email protected]')
Abandon answered 18/11, 2017 at 9:54 Comment(0)
C
0

For fellow googlers: I have the same problem using the JS API.

I succeded on my personal gmail address, but not on my work one (g-suite) neither on my secondary gmail address.

Can't see the pattern. It's possible that the work one has contact listing deactivated.

Chemotropism answered 9/5, 2018 at 7:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.