CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-google-api-python-client

Google API Client Library for Python that provides discovery-based access to hundreds of Google services with authentication, caching, and media upload/download support.

Pending
Overview
Eval results
Files

auth.mddocs/

Authentication Integration

The Google API Python Client provides authentication helper functions that seamlessly integrate with google-auth and oauth2client libraries, enabling credential management, scope handling, and request authentication.

Capabilities

Credential Management

Helper functions for obtaining and managing authentication credentials.

def default_credentials():
    """
    Get default credentials from the environment.
    
    Uses Application Default Credentials (ADC) to find credentials from:
    1. GOOGLE_APPLICATION_CREDENTIALS environment variable
    2. User credentials from gcloud auth application-default login
    3. Service account attached to Google Cloud resource
    4. Google Cloud SDK default credentials
    
    Returns:
        tuple: (credentials, project_id) where credentials is a Credentials 
               object and project_id is the default project ID
               
    Raises:
        DefaultCredentialsError: When no valid credentials are found
    """

def with_scopes(credentials, scopes):
    """
    Add OAuth2 scopes to credentials if the credentials support scoping.
    
    Args:
        credentials: OAuth2 credentials object (google-auth or oauth2client)
        scopes (list or str): List of OAuth2 scope URLs or single scope string
        
    Returns:
        Credentials: Credentials object with scopes applied, or original 
                    credentials if scoping is not supported
    """

def apply_credentials(credentials, headers):
    """
    Apply authentication credentials to HTTP request headers.
    
    Args:
        credentials: OAuth2 credentials object
        headers (dict): HTTP headers dictionary to modify in-place
        
    Raises:
        RefreshError: When credential refresh fails
        TransportError: When credential application fails
    """

Authentication Utilities

Utility functions for working with different authentication flows and credential types.

def refresh_credentials(credentials):
    """
    Refresh expired credentials.
    
    Args:
        credentials: OAuth2 credentials object to refresh
        
    Returns:
        Credentials: Refreshed credentials object
        
    Raises:
        RefreshError: When credential refresh fails
    """

def credentials_from_authorized_user_info(info, scopes=None):
    """
    Create credentials from authorized user info dictionary.
    
    Args:
        info (dict): Dictionary containing authorized user information
        scopes (list, optional): List of OAuth2 scopes to apply
        
    Returns:
        Credentials: OAuth2 credentials object
    """

def credentials_from_service_account_info(info, scopes=None):
    """
    Create credentials from service account info dictionary.
    
    Args:
        info (dict): Dictionary containing service account information
        scopes (list, optional): List of OAuth2 scopes to apply
        
    Returns:
        Credentials: Service account credentials object
    """

Usage Examples

Application Default Credentials

from googleapiclient import discovery
from googleapiclient._auth import default_credentials

# Get default credentials from environment
credentials, project = default_credentials()

# Build service with default credentials
service = discovery.build('gmail', 'v1', credentials=credentials)

# Use the service
messages = service.users().messages().list(userId='me').execute()
print(f"Project: {project}")
print(f"Messages: {len(messages.get('messages', []))}")

Adding Scopes to Credentials

from googleapiclient._auth import default_credentials, with_scopes

# Get default credentials
credentials, project = default_credentials()

# Define required scopes
gmail_scopes = [
    'https://www.googleapis.com/auth/gmail.readonly',
    'https://www.googleapis.com/auth/gmail.send'
]

# Add scopes to credentials
scoped_credentials = with_scopes(credentials, gmail_scopes)

# Build service with scoped credentials
service = discovery.build('gmail', 'v1', credentials=scoped_credentials)

Manual Credential Application

from googleapiclient._auth import apply_credentials
import httplib2

# Get credentials
credentials, _ = default_credentials()

# Create HTTP client
http = httplib2.Http()

# Prepare request headers
headers = {
    'Content-Type': 'application/json',
    'User-Agent': 'MyApp/1.0'
}

# Apply credentials to headers
apply_credentials(credentials, headers)

# Headers now contain Authorization header
print(headers.get('authorization'))  # Bearer <access_token>

Service Account Authentication

from google.oauth2 import service_account
from googleapiclient import discovery
from googleapiclient._auth import with_scopes

# Load service account credentials from file
credentials = service_account.Credentials.from_service_account_file(
    'path/to/service-account-key.json'
)

# Add required scopes
scopes = ['https://www.googleapis.com/auth/gmail.readonly']
scoped_credentials = with_scopes(credentials, scopes)

# Build service
service = discovery.build('gmail', 'v1', credentials=scoped_credentials)

OAuth2 User Credentials

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient import discovery
import os

def get_authenticated_service():
    """Get authenticated Gmail service using OAuth2 flow."""
    scopes = ['https://www.googleapis.com/auth/gmail.readonly']
    creds = None
    
    # Load existing credentials
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', scopes)
    
    # If no valid credentials, run OAuth flow
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', scopes)
            creds = flow.run_local_server(port=0)
        
        # Save credentials for next run
        with open('token.json', 'w') as token:
            token.write(creds.to_json())
    
    return discovery.build('gmail', 'v1', credentials=creds)

# Use the authenticated service
service = get_authenticated_service()

Credential Refresh Handling

from googleapiclient._auth import default_credentials, apply_credentials
from google.auth.exceptions import RefreshError
from googleapiclient.errors import HttpError
import httplib2

def make_authenticated_request(uri, method='GET', body=None):
    """Make an authenticated HTTP request with automatic credential refresh."""
    credentials, _ = default_credentials()
    
    try:
        # Prepare headers
        headers = {'Content-Type': 'application/json'}
        apply_credentials(credentials, headers)
        
        # Make request
        http = httplib2.Http()
        response, content = http.request(
            uri, method=method, body=body, headers=headers
        )
        
        return response, content
        
    except RefreshError as e:
        print(f"Credential refresh failed: {e}")
        raise
    except HttpError as e:
        if e.status_code == 401:
            print("Authentication failed - credentials may be invalid")
        raise

# Usage
response, content = make_authenticated_request(
    'https://gmail.googleapis.com/gmail/v1/users/me/messages'
)

Multi-Credential Management

from googleapiclient import discovery
from googleapiclient._auth import with_scopes
from google.oauth2 import service_account
import google.auth

class CredentialManager:
    """Manage multiple credential types for different services."""
    
    def __init__(self):
        self.credentials = {}
        self.services = {}
    
    def add_default_credentials(self, name, scopes=None):
        """Add Application Default Credentials."""
        creds, project = google.auth.default()
        if scopes:
            creds = with_scopes(creds, scopes)
        self.credentials[name] = creds
        return creds
    
    def add_service_account(self, name, key_file, scopes=None):
        """Add service account credentials."""
        creds = service_account.Credentials.from_service_account_file(key_file)
        if scopes:
            creds = with_scopes(creds, scopes)
        self.credentials[name] = creds
        return creds
    
    def get_service(self, cred_name, service_name, version):
        """Get an authenticated service using named credentials."""
        if cred_name not in self.credentials:
            raise ValueError(f"No credentials found for {cred_name}")
        
        service_key = f"{cred_name}:{service_name}:{version}"
        if service_key not in self.services:
            self.services[service_key] = discovery.build(
                service_name, version, 
                credentials=self.credentials[cred_name]
            )
        
        return self.services[service_key]

# Usage
cred_manager = CredentialManager()

# Add different credential types
cred_manager.add_default_credentials(
    'user_gmail', 
    ['https://www.googleapis.com/auth/gmail.readonly']
)

cred_manager.add_service_account(
    'service_drive',
    'service-account.json',
    ['https://www.googleapis.com/auth/drive']
)

# Get services with different credentials
gmail_service = cred_manager.get_service('user_gmail', 'gmail', 'v1')
drive_service = cred_manager.get_service('service_drive', 'drive', 'v3')

Testing with Mock Credentials

from googleapiclient import discovery
from googleapiclient._auth import apply_credentials
import unittest.mock

class MockCredentials:
    """Mock credentials for testing."""
    
    def __init__(self, token='mock_token'):
        self.token = token
        self.expired = False
    
    def refresh(self, request):
        """Mock credential refresh."""
        pass
    
    def apply(self, headers, token=None):
        """Apply mock token to headers."""
        headers['authorization'] = f'Bearer {self.token}'

def test_service_with_mock_credentials():
    """Test service creation with mock credentials."""
    mock_creds = MockCredentials('test_token')
    
    # Test header application
    headers = {}
    mock_creds.apply(headers)
    assert headers['authorization'] == 'Bearer test_token'
    
    # Test service building (with HTTP mock)
    from googleapiclient.http import HttpMock
    http_mock = HttpMock()
    
    with unittest.mock.patch('googleapiclient._auth.default_credentials') as mock_default:
        mock_default.return_value = (mock_creds, 'test-project')
        
        service = discovery.build('gmail', 'v1', http=http_mock)
        # Service created successfully with mock credentials

# Run test
test_service_with_mock_credentials()
print("Mock credential test passed")

Credential Storage and Persistence

from googleapiclient._auth import default_credentials
from google.oauth2.credentials import Credentials
import json
import os

class CredentialStore:
    """Store and retrieve credentials securely."""
    
    def __init__(self, store_path='credentials_store.json'):
        self.store_path = store_path
        self.credentials = {}
        self.load_credentials()
    
    def load_credentials(self):
        """Load credentials from storage."""
        if os.path.exists(self.store_path):
            try:
                with open(self.store_path, 'r') as f:
                    data = json.load(f)
                    
                for name, cred_data in data.items():
                    if cred_data['type'] == 'authorized_user':
                        self.credentials[name] = Credentials.from_authorized_user_info(
                            cred_data['info']
                        )
            except (json.JSONDecodeError, KeyError, ValueError):
                print("Warning: Could not load stored credentials")
    
    def save_credentials(self):
        """Save credentials to storage."""
        data = {}
        for name, creds in self.credentials.items():
            if hasattr(creds, 'to_json'):
                data[name] = {
                    'type': 'authorized_user',
                    'info': json.loads(creds.to_json())
                }
        
        with open(self.store_path, 'w') as f:
            json.dump(data, f, indent=2)
    
    def add_credentials(self, name, credentials):
        """Add credentials to store."""
        self.credentials[name] = credentials
        self.save_credentials()
    
    def get_credentials(self, name):
        """Get credentials by name."""
        return self.credentials.get(name)

# Usage
store = CredentialStore()

# Add default credentials
creds, _ = default_credentials()
store.add_credentials('default', creds)

# Retrieve later
stored_creds = store.get_credentials('default')
service = discovery.build('gmail', 'v1', credentials=stored_creds)

Install with Tessl CLI

npx tessl i tessl/pypi-google-api-python-client

docs

auth.md

channel.md

discovery.md

errors.md

http.md

index.md

media.md

mimeparse.md

model.md

schema.md

testing.md

tile.json