Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(294)

Side by Side Diff: third_party/oauth2client/appengine.py

Issue 1094533003: Revert of Upgrade 3rd packages (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/oauth2client/anyjson.py ('k') | third_party/oauth2client/client.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2014 Google Inc. All rights reserved. 1 # Copyright (C) 2010 Google Inc.
2 # 2 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); 3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License. 4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at 5 # You may obtain a copy of the License at
6 # 6 #
7 # http://www.apache.org/licenses/LICENSE-2.0 7 # http://www.apache.org/licenses/LICENSE-2.0
8 # 8 #
9 # Unless required by applicable law or agreed to in writing, software 9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, 10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and 12 # See the License for the specific language governing permissions and
13 # limitations under the License. 13 # limitations under the License.
14 14
15 """Utilities for Google App Engine 15 """Utilities for Google App Engine
16 16
17 Utilities for making it easier to use OAuth 2.0 on Google App Engine. 17 Utilities for making it easier to use OAuth 2.0 on Google App Engine.
18 """ 18 """
19 19
20 __author__ = 'jcgregorio@google.com (Joe Gregorio)' 20 __author__ = 'jcgregorio@google.com (Joe Gregorio)'
21 21
22 import base64
22 import cgi 23 import cgi
23 import json 24 import httplib2
24 import logging 25 import logging
25 import os 26 import os
26 import pickle 27 import pickle
27 import threading 28 import threading
28 29 import time
29 import httplib2
30 30
31 from google.appengine.api import app_identity 31 from google.appengine.api import app_identity
32 from google.appengine.api import memcache 32 from google.appengine.api import memcache
33 from google.appengine.api import users 33 from google.appengine.api import users
34 from google.appengine.ext import db 34 from google.appengine.ext import db
35 from google.appengine.ext import webapp 35 from google.appengine.ext import webapp
36 from google.appengine.ext.webapp.util import login_required 36 from google.appengine.ext.webapp.util import login_required
37 from google.appengine.ext.webapp.util import run_wsgi_app 37 from google.appengine.ext.webapp.util import run_wsgi_app
38 from oauth2client import GOOGLE_AUTH_URI 38 from oauth2client import GOOGLE_AUTH_URI
39 from oauth2client import GOOGLE_REVOKE_URI 39 from oauth2client import GOOGLE_REVOKE_URI
40 from oauth2client import GOOGLE_TOKEN_URI 40 from oauth2client import GOOGLE_TOKEN_URI
41 from oauth2client import clientsecrets 41 from oauth2client import clientsecrets
42 from oauth2client import util 42 from oauth2client import util
43 from oauth2client import xsrfutil 43 from oauth2client import xsrfutil
44 from oauth2client.anyjson import simplejson
44 from oauth2client.client import AccessTokenRefreshError 45 from oauth2client.client import AccessTokenRefreshError
45 from oauth2client.client import AssertionCredentials 46 from oauth2client.client import AssertionCredentials
46 from oauth2client.client import Credentials 47 from oauth2client.client import Credentials
47 from oauth2client.client import Flow 48 from oauth2client.client import Flow
48 from oauth2client.client import OAuth2WebServerFlow 49 from oauth2client.client import OAuth2WebServerFlow
49 from oauth2client.client import Storage 50 from oauth2client.client import Storage
50 51
51 # TODO(dhermes): Resolve import issue. 52 # TODO(dhermes): Resolve import issue.
52 # This is a temporary fix for a Google internal issue. 53 # This is a temporary fix for a Google internal issue.
53 try: 54 try:
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 generate and refresh its own access tokens. 152 generate and refresh its own access tokens.
152 """ 153 """
153 154
154 @util.positional(2) 155 @util.positional(2)
155 def __init__(self, scope, **kwargs): 156 def __init__(self, scope, **kwargs):
156 """Constructor for AppAssertionCredentials 157 """Constructor for AppAssertionCredentials
157 158
158 Args: 159 Args:
159 scope: string or iterable of strings, scope(s) of the credentials being 160 scope: string or iterable of strings, scope(s) of the credentials being
160 requested. 161 requested.
161 **kwargs: optional keyword args, including:
162 service_account_id: service account id of the application. If None or
163 unspecified, the default service account for the app is used.
164 """ 162 """
165 self.scope = util.scopes_to_string(scope) 163 self.scope = util.scopes_to_string(scope)
166 self._kwargs = kwargs
167 self.service_account_id = kwargs.get('service_account_id', None)
168 164
169 # Assertion type is no longer used, but still in the parent class signature. 165 # Assertion type is no longer used, but still in the parent class signature.
170 super(AppAssertionCredentials, self).__init__(None) 166 super(AppAssertionCredentials, self).__init__(None)
171 167
172 @classmethod 168 @classmethod
173 def from_json(cls, json_data): 169 def from_json(cls, json):
174 data = json.loads(json_data) 170 data = simplejson.loads(json)
175 return AppAssertionCredentials(data['scope']) 171 return AppAssertionCredentials(data['scope'])
176 172
177 def _refresh(self, http_request): 173 def _refresh(self, http_request):
178 """Refreshes the access_token. 174 """Refreshes the access_token.
179 175
180 Since the underlying App Engine app_identity implementation does its own 176 Since the underlying App Engine app_identity implementation does its own
181 caching we can skip all the storage hoops and just to a refresh using the 177 caching we can skip all the storage hoops and just to a refresh using the
182 API. 178 API.
183 179
184 Args: 180 Args:
185 http_request: callable, a callable that matches the method signature of 181 http_request: callable, a callable that matches the method signature of
186 httplib2.Http.request, used to make the refresh request. 182 httplib2.Http.request, used to make the refresh request.
187 183
188 Raises: 184 Raises:
189 AccessTokenRefreshError: When the refresh fails. 185 AccessTokenRefreshError: When the refresh fails.
190 """ 186 """
191 try: 187 try:
192 scopes = self.scope.split() 188 scopes = self.scope.split()
193 (token, _) = app_identity.get_access_token( 189 (token, _) = app_identity.get_access_token(scopes)
194 scopes, service_account_id=self.service_account_id) 190 except app_identity.Error, e:
195 except app_identity.Error as e:
196 raise AccessTokenRefreshError(str(e)) 191 raise AccessTokenRefreshError(str(e))
197 self.access_token = token 192 self.access_token = token
198 193
199 @property
200 def serialization_data(self):
201 raise NotImplementedError('Cannot serialize credentials for AppEngine.')
202
203 def create_scoped_required(self):
204 return not self.scope
205
206 def create_scoped(self, scopes):
207 return AppAssertionCredentials(scopes, **self._kwargs)
208
209 194
210 class FlowProperty(db.Property): 195 class FlowProperty(db.Property):
211 """App Engine datastore Property for Flow. 196 """App Engine datastore Property for Flow.
212 197
213 Utility property that allows easy storage and retrieval of an 198 Utility property that allows easy storage and retrieval of an
214 oauth2client.Flow""" 199 oauth2client.Flow"""
215 200
216 # Tell what the user type is. 201 # Tell what the user type is.
217 data_type = Flow 202 data_type = Flow
218 203
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 427
443 Attempts to delete using the key_name stored on the object, whether or not 428 Attempts to delete using the key_name stored on the object, whether or not
444 the given key is in the datastore. 429 the given key is in the datastore.
445 """ 430 """
446 if self._is_ndb(): 431 if self._is_ndb():
447 ndb.Key(self._model, self._key_name).delete() 432 ndb.Key(self._model, self._key_name).delete()
448 else: 433 else:
449 entity_key = db.Key.from_path(self._model.kind(), self._key_name) 434 entity_key = db.Key.from_path(self._model.kind(), self._key_name)
450 db.delete(entity_key) 435 db.delete(entity_key)
451 436
452 @db.non_transactional(allow_existing=True)
453 def locked_get(self): 437 def locked_get(self):
454 """Retrieve Credential from datastore. 438 """Retrieve Credential from datastore.
455 439
456 Returns: 440 Returns:
457 oauth2client.Credentials 441 oauth2client.Credentials
458 """ 442 """
459 credentials = None 443 credentials = None
460 if self._cache: 444 if self._cache:
461 json = self._cache.get(self._key_name) 445 json = self._cache.get(self._key_name)
462 if json: 446 if json:
463 credentials = Credentials.new_from_json(json) 447 credentials = Credentials.new_from_json(json)
464 if credentials is None: 448 if credentials is None:
465 entity = self._get_entity() 449 entity = self._get_entity()
466 if entity is not None: 450 if entity is not None:
467 credentials = getattr(entity, self._property_name) 451 credentials = getattr(entity, self._property_name)
468 if self._cache: 452 if self._cache:
469 self._cache.set(self._key_name, credentials.to_json()) 453 self._cache.set(self._key_name, credentials.to_json())
470 454
471 if credentials and hasattr(credentials, 'set_store'): 455 if credentials and hasattr(credentials, 'set_store'):
472 credentials.set_store(self) 456 credentials.set_store(self)
473 return credentials 457 return credentials
474 458
475 @db.non_transactional(allow_existing=True)
476 def locked_put(self, credentials): 459 def locked_put(self, credentials):
477 """Write a Credentials to the datastore. 460 """Write a Credentials to the datastore.
478 461
479 Args: 462 Args:
480 credentials: Credentials, the credentials to store. 463 credentials: Credentials, the credentials to store.
481 """ 464 """
482 entity = self._model.get_or_insert(self._key_name) 465 entity = self._model.get_or_insert(self._key_name)
483 setattr(entity, self._property_name, credentials) 466 setattr(entity, self._property_name, credentials)
484 entity.put() 467 entity.put()
485 if self._cache: 468 if self._cache:
486 self._cache.set(self._key_name, credentials.to_json()) 469 self._cache.set(self._key_name, credentials.to_json())
487 470
488 @db.non_transactional(allow_existing=True)
489 def locked_delete(self): 471 def locked_delete(self):
490 """Delete Credential from datastore.""" 472 """Delete Credential from datastore."""
491 473
492 if self._cache: 474 if self._cache:
493 self._cache.delete(self._key_name) 475 self._cache.delete(self._key_name)
494 476
495 self._delete_entity() 477 self._delete_entity()
496 478
497 479
498 class CredentialsModel(db.Model): 480 class CredentialsModel(db.Model):
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
564 546
565 return uri 547 return uri
566 548
567 549
568 class OAuth2Decorator(object): 550 class OAuth2Decorator(object):
569 """Utility for making OAuth 2.0 easier. 551 """Utility for making OAuth 2.0 easier.
570 552
571 Instantiate and then use with oauth_required or oauth_aware 553 Instantiate and then use with oauth_required or oauth_aware
572 as decorators on webapp.RequestHandler methods. 554 as decorators on webapp.RequestHandler methods.
573 555
574 :: 556 Example:
575 557
576 decorator = OAuth2Decorator( 558 decorator = OAuth2Decorator(
577 client_id='837...ent.com', 559 client_id='837...ent.com',
578 client_secret='Qh...wwI', 560 client_secret='Qh...wwI',
579 scope='https://www.googleapis.com/auth/plus') 561 scope='https://www.googleapis.com/auth/plus')
580 562
563
581 class MainHandler(webapp.RequestHandler): 564 class MainHandler(webapp.RequestHandler):
565
582 @decorator.oauth_required 566 @decorator.oauth_required
583 def get(self): 567 def get(self):
584 http = decorator.http() 568 http = decorator.http()
585 # http is authorized with the user's Credentials and can be used 569 # http is authorized with the user's Credentials and can be used
586 # in API calls 570 # in API calls
587 571
588 """ 572 """
589 573
590 def set_credentials(self, credentials): 574 def set_credentials(self, credentials):
591 self._tls.credentials = credentials 575 self._tls.credentials = credentials
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 _storage_class: "Protected" keyword argument not typically provided to 643 _storage_class: "Protected" keyword argument not typically provided to
660 this constructor. A storage class to aid in storing a Credentials object 644 this constructor. A storage class to aid in storing a Credentials object
661 for a user in the datastore. Defaults to StorageByKeyName. 645 for a user in the datastore. Defaults to StorageByKeyName.
662 _credentials_class: "Protected" keyword argument not typically provided to 646 _credentials_class: "Protected" keyword argument not typically provided to
663 this constructor. A db or ndb Model class to hold credentials. Defaults 647 this constructor. A db or ndb Model class to hold credentials. Defaults
664 to CredentialsModel. 648 to CredentialsModel.
665 _credentials_property_name: "Protected" keyword argument not typically 649 _credentials_property_name: "Protected" keyword argument not typically
666 provided to this constructor. A string indicating the name of the field 650 provided to this constructor. A string indicating the name of the field
667 on the _credentials_class where a Credentials object will be stored. 651 on the _credentials_class where a Credentials object will be stored.
668 Defaults to 'credentials'. 652 Defaults to 'credentials'.
669 **kwargs: dict, Keyword arguments are passed along as kwargs to 653 **kwargs: dict, Keyword arguments are be passed along as kwargs to the
670 the OAuth2WebServerFlow constructor. 654 OAuth2WebServerFlow constructor.
671
672 """ 655 """
673 self._tls = threading.local() 656 self._tls = threading.local()
674 self.flow = None 657 self.flow = None
675 self.credentials = None 658 self.credentials = None
676 self._client_id = client_id 659 self._client_id = client_id
677 self._client_secret = client_secret 660 self._client_secret = client_secret
678 self._scope = util.scopes_to_string(scope) 661 self._scope = util.scopes_to_string(scope)
679 self._auth_uri = auth_uri 662 self._auth_uri = auth_uri
680 self._token_uri = token_uri 663 self._token_uri = token_uri
681 self._revoke_uri = revoke_uri 664 self._revoke_uri = revoke_uri
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
808 791
809 def authorize_url(self): 792 def authorize_url(self):
810 """Returns the URL to start the OAuth dance. 793 """Returns the URL to start the OAuth dance.
811 794
812 Must only be called from with a webapp.RequestHandler subclassed method 795 Must only be called from with a webapp.RequestHandler subclassed method
813 that had been decorated with either @oauth_required or @oauth_aware. 796 that had been decorated with either @oauth_required or @oauth_aware.
814 """ 797 """
815 url = self.flow.step1_get_authorize_url() 798 url = self.flow.step1_get_authorize_url()
816 return str(url) 799 return str(url)
817 800
818 def http(self, *args, **kwargs): 801 def http(self):
819 """Returns an authorized http instance. 802 """Returns an authorized http instance.
820 803
821 Must only be called from within an @oauth_required decorated method, or 804 Must only be called from within an @oauth_required decorated method, or
822 from within an @oauth_aware decorated method where has_credentials() 805 from within an @oauth_aware decorated method where has_credentials()
823 returns True. 806 returns True.
824
825 Args:
826 *args: Positional arguments passed to httplib2.Http constructor.
827 **kwargs: Positional arguments passed to httplib2.Http constructor.
828 """ 807 """
829 return self.credentials.authorize(httplib2.Http(*args, **kwargs)) 808 return self.credentials.authorize(httplib2.Http())
830 809
831 @property 810 @property
832 def callback_path(self): 811 def callback_path(self):
833 """The absolute path where the callback will occur. 812 """The absolute path where the callback will occur.
834 813
835 Note this is the absolute path, not the absolute URI, that will be 814 Note this is the absolute path, not the absolute URI, that will be
836 calculated by the decorator at runtime. See callback_handler() for how this 815 calculated by the decorator at runtime. See callback_handler() for how this
837 should be used. 816 should be used.
838 817
839 Returns: 818 Returns:
840 The callback path as a string. 819 The callback path as a string.
841 """ 820 """
842 return self._callback_path 821 return self._callback_path
843 822
844 823
845 def callback_handler(self): 824 def callback_handler(self):
846 """RequestHandler for the OAuth 2.0 redirect callback. 825 """RequestHandler for the OAuth 2.0 redirect callback.
847 826
848 Usage:: 827 Usage:
849
850 app = webapp.WSGIApplication([ 828 app = webapp.WSGIApplication([
851 ('/index', MyIndexHandler), 829 ('/index', MyIndexHandler),
852 ..., 830 ...,
853 (decorator.callback_path, decorator.callback_handler()) 831 (decorator.callback_path, decorator.callback_handler())
854 ]) 832 ])
855 833
856 Returns: 834 Returns:
857 A webapp.RequestHandler that handles the redirect back from the 835 A webapp.RequestHandler that handles the redirect back from the
858 server during the OAuth 2.0 dance. 836 server during the OAuth 2.0 dance.
859 """ 837 """
(...skipping 13 matching lines...) Expand all
873 user = users.get_current_user() 851 user = users.get_current_user()
874 decorator._create_flow(self) 852 decorator._create_flow(self)
875 credentials = decorator.flow.step2_exchange(self.request.params) 853 credentials = decorator.flow.step2_exchange(self.request.params)
876 decorator._storage_class( 854 decorator._storage_class(
877 decorator._credentials_class, None, 855 decorator._credentials_class, None,
878 decorator._credentials_property_name, user=user).put(credentials) 856 decorator._credentials_property_name, user=user).put(credentials)
879 redirect_uri = _parse_state_value(str(self.request.get('state')), 857 redirect_uri = _parse_state_value(str(self.request.get('state')),
880 user) 858 user)
881 859
882 if decorator._token_response_param and credentials.token_response: 860 if decorator._token_response_param and credentials.token_response:
883 resp_json = json.dumps(credentials.token_response) 861 resp_json = simplejson.dumps(credentials.token_response)
884 redirect_uri = util._add_query_parameter( 862 redirect_uri = util._add_query_parameter(
885 redirect_uri, decorator._token_response_param, resp_json) 863 redirect_uri, decorator._token_response_param, resp_json)
886 864
887 self.redirect(redirect_uri) 865 self.redirect(redirect_uri)
888 866
889 return OAuth2Handler 867 return OAuth2Handler
890 868
891 def callback_application(self): 869 def callback_application(self):
892 """WSGI application for handling the OAuth 2.0 redirect callback. 870 """WSGI application for handling the OAuth 2.0 redirect callback.
893 871
894 If you need finer grained control use `callback_handler` which returns just 872 If you need finer grained control use `callback_handler` which returns just
895 the webapp.RequestHandler. 873 the webapp.RequestHandler.
896 874
897 Returns: 875 Returns:
898 A webapp.WSGIApplication that handles the redirect back from the 876 A webapp.WSGIApplication that handles the redirect back from the
899 server during the OAuth 2.0 dance. 877 server during the OAuth 2.0 dance.
900 """ 878 """
901 return webapp.WSGIApplication([ 879 return webapp.WSGIApplication([
902 (self.callback_path, self.callback_handler()) 880 (self.callback_path, self.callback_handler())
903 ]) 881 ])
904 882
905 883
906 class OAuth2DecoratorFromClientSecrets(OAuth2Decorator): 884 class OAuth2DecoratorFromClientSecrets(OAuth2Decorator):
907 """An OAuth2Decorator that builds from a clientsecrets file. 885 """An OAuth2Decorator that builds from a clientsecrets file.
908 886
909 Uses a clientsecrets file as the source for all the information when 887 Uses a clientsecrets file as the source for all the information when
910 constructing an OAuth2Decorator. 888 constructing an OAuth2Decorator.
911 889
912 :: 890 Example:
913 891
914 decorator = OAuth2DecoratorFromClientSecrets( 892 decorator = OAuth2DecoratorFromClientSecrets(
915 os.path.join(os.path.dirname(__file__), 'client_secrets.json') 893 os.path.join(os.path.dirname(__file__), 'client_secrets.json')
916 scope='https://www.googleapis.com/auth/plus') 894 scope='https://www.googleapis.com/auth/plus')
917 895
896
918 class MainHandler(webapp.RequestHandler): 897 class MainHandler(webapp.RequestHandler):
898
919 @decorator.oauth_required 899 @decorator.oauth_required
920 def get(self): 900 def get(self):
921 http = decorator.http() 901 http = decorator.http()
922 # http is authorized with the user's Credentials and can be used 902 # http is authorized with the user's Credentials and can be used
923 # in API calls 903 # in API calls
924
925 """ 904 """
926 905
927 @util.positional(3) 906 @util.positional(3)
928 def __init__(self, filename, scope, message=None, cache=None, **kwargs): 907 def __init__(self, filename, scope, message=None, cache=None):
929 """Constructor 908 """Constructor
930 909
931 Args: 910 Args:
932 filename: string, File name of client secrets. 911 filename: string, File name of client secrets.
933 scope: string or iterable of strings, scope(s) of the credentials being 912 scope: string or iterable of strings, scope(s) of the credentials being
934 requested. 913 requested.
935 message: string, A friendly string to display to the user if the 914 message: string, A friendly string to display to the user if the
936 clientsecrets file is missing or invalid. The message may contain HTML 915 clientsecrets file is missing or invalid. The message may contain HTML
937 and will be presented on the web interface for any method that uses the 916 and will be presented on the web interface for any method that uses the
938 decorator. 917 decorator.
939 cache: An optional cache service client that implements get() and set() 918 cache: An optional cache service client that implements get() and set()
940 methods. See clientsecrets.loadfile() for details. 919 methods. See clientsecrets.loadfile() for details.
941 **kwargs: dict, Keyword arguments are passed along as kwargs to
942 the OAuth2WebServerFlow constructor.
943 """ 920 """
944 client_type, client_info = clientsecrets.loadfile(filename, cache=cache) 921 client_type, client_info = clientsecrets.loadfile(filename, cache=cache)
945 if client_type not in [ 922 if client_type not in [
946 clientsecrets.TYPE_WEB, clientsecrets.TYPE_INSTALLED]: 923 clientsecrets.TYPE_WEB, clientsecrets.TYPE_INSTALLED]:
947 raise InvalidClientSecretsError( 924 raise InvalidClientSecretsError(
948 "OAuth2Decorator doesn't support this OAuth 2.0 flow.") 925 'OAuth2Decorator doesn\'t support this OAuth 2.0 flow.')
949 constructor_kwargs = dict(kwargs) 926 constructor_kwargs = {
950 constructor_kwargs.update({ 927 'auth_uri': client_info['auth_uri'],
951 'auth_uri': client_info['auth_uri'], 928 'token_uri': client_info['token_uri'],
952 'token_uri': client_info['token_uri'], 929 'message': message,
953 'message': message, 930 }
954 })
955 revoke_uri = client_info.get('revoke_uri') 931 revoke_uri = client_info.get('revoke_uri')
956 if revoke_uri is not None: 932 if revoke_uri is not None:
957 constructor_kwargs['revoke_uri'] = revoke_uri 933 constructor_kwargs['revoke_uri'] = revoke_uri
958 super(OAuth2DecoratorFromClientSecrets, self).__init__( 934 super(OAuth2DecoratorFromClientSecrets, self).__init__(
959 client_info['client_id'], client_info['client_secret'], 935 client_info['client_id'], client_info['client_secret'],
960 scope, **constructor_kwargs) 936 scope, **constructor_kwargs)
961 if message is not None: 937 if message is not None:
962 self._message = message 938 self._message = message
963 else: 939 else:
964 self._message = 'Please configure your application for OAuth 2.0.' 940 self._message = 'Please configure your application for OAuth 2.0.'
(...skipping 12 matching lines...) Expand all
977 clientsecrets file is missing or invalid. The message may contain HTML and 953 clientsecrets file is missing or invalid. The message may contain HTML and
978 will be presented on the web interface for any method that uses the 954 will be presented on the web interface for any method that uses the
979 decorator. 955 decorator.
980 cache: An optional cache service client that implements get() and set() 956 cache: An optional cache service client that implements get() and set()
981 methods. See clientsecrets.loadfile() for details. 957 methods. See clientsecrets.loadfile() for details.
982 958
983 Returns: An OAuth2Decorator 959 Returns: An OAuth2Decorator
984 960
985 """ 961 """
986 return OAuth2DecoratorFromClientSecrets(filename, scope, 962 return OAuth2DecoratorFromClientSecrets(filename, scope,
987 message=message, cache=cache) 963 message=message, cache=cache)
OLDNEW
« no previous file with comments | « third_party/oauth2client/anyjson.py ('k') | third_party/oauth2client/client.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698