diff -r 27971a13089f -r 2e0b0af889be thirdparty/google_appengine/google/appengine/ext/remote_api/remote_api_stub.py --- a/thirdparty/google_appengine/google/appengine/ext/remote_api/remote_api_stub.py Sat Sep 05 14:04:24 2009 +0200 +++ b/thirdparty/google_appengine/google/appengine/ext/remote_api/remote_api_stub.py Sun Sep 06 23:31:53 2009 +0200 @@ -71,6 +71,8 @@ import threading import yaml +from google.appengine.api import datastore +from google.appengine.api import apiproxy_rpc from google.appengine.api import apiproxy_stub_map from google.appengine.datastore import datastore_pb from google.appengine.ext.remote_api import remote_api_pb @@ -86,6 +88,10 @@ """Exception for configuration errors.""" +class UnknownJavaServerError(Error): + """Exception for exceptions returned from a Java remote_api handler.""" + + def GetUserAgent(): """Determines the value of the 'User-agent' header to use for HTTP requests. @@ -136,20 +142,41 @@ self._server = server self._path = path + def _PreHookHandler(self, service, call, request, response): + pass + + def _PostHookHandler(self, service, call, request, response): + pass + def MakeSyncCall(self, service, call, request, response): + self._PreHookHandler(service, call, request, response) request_pb = remote_api_pb.Request() request_pb.set_service_name(service) request_pb.set_method(call) request_pb.mutable_request().set_contents(request.Encode()) response_pb = remote_api_pb.Response() - response_pb.ParseFromString(self._server.Send(self._path, - request_pb.Encode())) + encoded_request = request_pb.Encode() + encoded_response = self._server.Send(self._path, encoded_request) + response_pb.ParseFromString(encoded_response) - if response_pb.has_exception(): - raise pickle.loads(response_pb.exception().contents()) - else: - response.ParseFromString(response_pb.response().contents()) + try: + if response_pb.has_application_error(): + error_pb = response_pb.application_error() + raise datastore._ToDatastoreError( + apiproxy_errors.ApplicationError(error_pb.code(), error_pb.detail())) + elif response_pb.has_exception(): + raise pickle.loads(response_pb.exception().contents()) + elif response_pb.has_java_exception(): + raise UnknownJavaServerError("An unknown error has occured in the " + "Java remote_api handler for this call.") + else: + response.ParseFromString(response_pb.response().contents()) + finally: + self._PostHookHandler(service, call, request, response) + + def CreateRPC(self): + return apiproxy_rpc.RPC(stub=self) class RemoteDatastoreStub(RemoteStub): @@ -192,10 +219,12 @@ self.__next_local_cursor += 1 finally: self.__local_cursor_lock.release() + query.clear_count() self.__queries[cursor_id] = query query_result.mutable_cursor().set_cursor(cursor_id) query_result.set_more_results(True) + query_result.set_keys_only(query.keys_only()) def _Dynamic_Next(self, next_request, query_result): cursor = next_request.cursor().cursor() @@ -214,6 +243,7 @@ request.set_limit(min(request.limit(), next_request.count())) else: request.set_limit(next_request.count()) + request.set_count(request.limit()) super(RemoteDatastoreStub, self).MakeSyncCall( 'remote_datastore', 'RunQuery', request, query_result) @@ -229,8 +259,8 @@ if get_request.has_transaction(): txid = get_request.transaction().handle() txdata = self.__transactions[txid] - assert (txdata.thread_id == thread.get_ident(), - "Transactions are single-threaded.") + assert (txdata.thread_id == + thread.get_ident()), "Transactions are single-threaded." keys = [(k, k.Encode()) for k in get_request.key_list()] @@ -296,8 +326,8 @@ txid = put_request.transaction().handle() txdata = self.__transactions[txid] - assert (txdata.thread_id == thread.get_ident(), - "Transactions are single-threaded.") + assert (txdata.thread_id == + thread.get_ident()), "Transactions are single-threaded." for entity in entities: txdata.entities[entity.key().Encode()] = (entity.key(), entity) put_response.add_key().CopyFrom(entity.key()) @@ -309,8 +339,8 @@ if delete_request.has_transaction(): txid = delete_request.transaction().handle() txdata = self.__transactions[txid] - assert (txdata.thread_id == thread.get_ident(), - "Transactions are single-threaded.") + assert (txdata.thread_id == + thread.get_ident()), "Transactions are single-threaded." for key in delete_request.key_list(): txdata.entities[key.Encode()] = (key, None) else: @@ -335,8 +365,8 @@ 'Transaction %d not found.' % (txid,)) txdata = self.__transactions[txid] - assert (txdata.thread_id == thread.get_ident(), - "Transactions are single-threaded.") + assert (txdata.thread_id == + thread.get_ident()), "Transactions are single-threaded." del self.__transactions[txid] tx = remote_api_pb.TransactionRequest() @@ -367,8 +397,8 @@ datastore_pb.Error.BAD_REQUEST, 'Transaction %d not found.' % (txid,)) - assert (txdata[txid].thread_id == thread.get_ident(), - "Transactions are single-threaded.") + assert (txdata[txid].thread_id == + thread.get_ident()), "Transactions are single-threaded." del self.__transactions[txid] finally: self.__local_tx_lock.release() @@ -386,14 +416,14 @@ 'The remote datastore does not support index manipulation.') -def ConfigureRemoteDatastore(app_id, - path, - auth_func, - servername=None, - rpc_server_factory=appengine_rpc.HttpRpcServer, - rtok=None, - secure=False): - """Does necessary setup to allow easy remote access to an AppEngine datastore. +def ConfigureRemoteApi(app_id, + path, + auth_func, + servername=None, + rpc_server_factory=appengine_rpc.HttpRpcServer, + rtok=None, + secure=False): + """Does necessary setup to allow easy remote access to App Engine APIs. Either servername must be provided or app_id must not be None. If app_id is None and a servername is provided, this function will send a request @@ -438,10 +468,32 @@ if not app_info or 'rtok' not in app_info or 'app_id' not in app_info: raise ConfigurationError('Error parsing app_id lookup response') if app_info['rtok'] != rtok: - raise ConfigurationError('Token validation failed during app_id lookup.') + raise ConfigurationError('Token validation failed during app_id lookup. ' + '(sent %s, got %s)' % (repr(rtok), + repr(app_info['rtok']))) app_id = app_info['app_id'] os.environ['APPLICATION_ID'] = app_id apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap() - stub = RemoteDatastoreStub(server, path) - apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', stub) + datastore_stub = RemoteDatastoreStub(server, path) + apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', datastore_stub) + stub = RemoteStub(server, path) + for service in ['capability_service', 'images', 'mail', 'memcache', + 'urlfetch']: + apiproxy_stub_map.apiproxy.RegisterStub(service, stub) + + +def MaybeInvokeAuthentication(): + """Sends an empty request through to the configured end-point. + + If authentication is necessary, this will cause the rpc_server to invoke + interactive authentication. + """ + datastore_stub = apiproxy_stub_map.apiproxy.GetStub('datastore_v3') + if isinstance(datastore_stub, RemoteStub): + datastore_stub._server.Send(datastore_stub._path, payload=None) + else: + raise ConfigurationError('remote_api is not configured.') + + +ConfigureRemoteDatastore = ConfigureRemoteApi