""" API Client Connector ================== Handles client setup and auth for the YouTube API. Requires the following environment variables to be set up and valid: * GOOGLE_API_KEY_FILE * GOOGLE_SERVICE_EMAIL """ from googleapiclient.discovery import build import httplib2 from oauth2client.service_account import ServiceAccountCredentials import os from labelaudit import config class ServiceMapping: """ Google API Service Mapping ================== Thin wrapper around the Google client library. Lazily handles oauth setup and builds the service client for the partner API. """ PARTNER_API_VERSION = 'v1' PARTNER_API_NAME = 'youtubePartner' def __init__(self, service_email, key_file): self.service_email = service_email self.key_file = key_file self._client = None self._youtube_partner = None def authorize(self): """Create and authorize a Google API client. To be called when the client has not been initialized or its access token has expired. """ credentials = ServiceAccountCredentials( self.service_email, self.key_file.contents, scope=['https://www.googleapis.com/auth/youtubepartner']) self._client = credentials.authorize(httplib2.Http()) @property def client(self): """Create and authorize a Google API client. Return: httplib2.Http: httlib2 client object """ if not self._client: self.authorize() return self._client @property def youtube_partner(self): """Lazily initialize the YouTube API discovery resource for the partner API. Return: googleapiclient.discovery.Resource: partner API resource """ if not self._youtube_partner: self._youtube_partner = build( self.PARTNER_API_NAME, self.PARTNER_API_VERSION, http=self.client) return self._youtube_partner class KeyFile: """ Google API key file reader ================== Lazily reads the contents of the given key file from the keys directory. """ def __init__(self, file_name): self.file_name = file_name self._contents = None @property def contents(self): """Reads the contents of the P12 key file specified in the config. Return: bytes: contents of the key file """ if self._contents: return self._contents if not self.file_name: raise Exception('Missing Google API key file name') full_key_path = os.path.join( os.path.realpath(os.path.dirname(__file__) + '/../..'), 'keys', self.file_name) if not os.access(full_key_path, os.R_OK): raise Exception('Cannot read Google API key file ' + full_key_path) key_file = open(full_key_path, 'rb') self._contents = key_file.read() key_file.close() return self._contents # Lazy is the key word here. Lazily read the key file and lazily authorize # the API client. That gives our unit tests a chance to mock this stuff after # importing this module. key_file = KeyFile(config.GOOGLE_API_KEY_FILE) mapping = ServiceMapping( service_email=config.GOOGLE_SERVICE_EMAIL, key_file=key_file)