earthengine-api/python/ee/_helpers.py
Michael DeWitt 6c251b3aae v0.1.192
2019-08-22 14:46:22 -07:00

129 lines
4.0 KiB
Python

#!/usr/bin/env python
"""Convenience functions and code used by ee/__init__.py.
These functions are in general re-exported from the "ee" module and should be
referenced from there (e.g. "ee.profilePrinting").
"""
# Using lowercase function naming to match the JavaScript names.
# pylint: disable=g-bad-name
import contextlib
import json
import sys
# pylint: disable=g-importing-member
from . import data
from . import oauth
from .apifunction import ApiFunction
# pylint: enable=g-importing-member
import six
from google.auth import crypt
from google.oauth2 import service_account
def ServiceAccountCredentials(email, key_file=None, key_data=None):
"""Configure OAuth2 credentials for a Google Service Account.
Args:
email: The email address of the account for which to configure credentials.
Ignored if key_file or key_data represents a JSON service account key.
key_file: The path to a file containing the private key associated with
the service account. Both JSON and PEM files are supported.
key_data: Raw key data to use, if key_file is not specified.
Returns:
An OAuth2 credentials object.
"""
# Assume anything that doesn't end in '.pem' is a JSON key.
if key_file and not key_file.endswith('.pem'):
return service_account.Credentials.from_service_account_file(
key_file, scopes=oauth.SCOPES)
# If 'key_data' can be decoded as JSON, it's probably a raw JSON key.
if key_data:
try:
key_data = json.loads(key_data)
return service_account.Credentials.from_service_account_info(
key_data, scopes=oauth.SCOPES)
except ValueError:
# It may actually be a raw PEM string, we'll try that below.
pass
# Probably a PEM key - just read the file into 'key_data'.
if key_file:
with open(key_file, 'r') as file_:
key_data = file_.read()
# Raw PEM key.
signer = crypt.RSASigner.from_string(key_data)
return service_account.Credentials(
signer, email, oauth.TOKEN_URI, scopes=oauth.SCOPES)
def call(func, *args, **kwargs):
"""Invoke the given algorithm with the specified args.
Args:
func: The function to call. Either an ee.Function object or the name of
an API function.
*args: The positional arguments to pass to the function.
**kwargs: The named arguments to pass to the function.
Returns:
A ComputedObject representing the called function. If the signature
specifies a recognized return type, the returned value will be cast
to that type.
"""
if isinstance(func, six.string_types):
func = ApiFunction.lookup(func)
return func.call(*args, **kwargs)
def apply(func, named_args): # pylint: disable=redefined-builtin
"""Call a function with a dictionary of named arguments.
Args:
func: The function to call. Either an ee.Function object or the name of
an API function.
named_args: A dictionary of arguments to the function.
Returns:
A ComputedObject representing the called function. If the signature
specifies a recognized return type, the returned value will be cast
to that type.
"""
if isinstance(func, six.string_types):
func = ApiFunction.lookup(func)
return func.apply(named_args)
@contextlib.contextmanager
def profilePrinting(destination=sys.stderr):
# pylint: disable=g-doc-return-or-yield
"""Returns a context manager that prints a profile of enclosed API calls.
The profile will be printed when the context ends, whether or not any error
occurred within the context.
# Simple example:
with ee.profilePrinting():
print ee.Number(1).add(1).getInfo()
Args:
destination: A file-like object to which the profile text is written.
Defaults to sys.stderr.
"""
# TODO(user): Figure out why ee.Profile.getProfiles isn't generated and fix
# that.
getProfiles = ApiFunction.lookup('Profile.getProfiles')
profile_ids = []
try:
with data.profiling(profile_ids.append):
yield
finally:
profile_text = getProfiles.call(ids=profile_ids).getInfo()
destination.write(profile_text)