
    Md                         S r SSKJr  SSKrSSKrSSKrSSKJr  SSKJ	r	  SS jr
SS jr " S S	\5      r " S
 S\5      r " S S\5      rS r\" 5       rg)a+  Container of APIProxy stubs for more convenient unittesting.

Classes/variables/functions defined here:
  APIProxyStubMap: container of APIProxy stubs.
  apiproxy: global instance of an APIProxyStubMap.
  MakeSyncCall: APIProxy entry point.
  UserRPC: User-visible class wrapping asynchronous RPCs.
    )absolute_importN)apiproxy_rpc)apiproxy_errorsc                     Uc  [         nUR                  U 5      nU(       d
   SU -  5       e[        US5      (       d
   SU -  5       eUR                  5       $ )a  Creates a RPC instance for the given service.

The instance is suitable for talking to remote services.
Each RPC instance can be used only once, and should not be reused.

Args:
  service: string representing which service to call.
  stubmap: optional APIProxyStubMap instance, for dependency injection.

Returns:
  the rpc object.

Raises:
  AssertionError or RuntimeError if the stub for service doesn't supply a
  CreateRPC method.
#No api proxy found for service "%s"	CreateRPCz1The service "%s" doesn't have a CreateRPC method.)apiproxyGetStubhasattrr   )servicestubmapstubs      5lib/googlecloudsdk/appengine/api/apiproxy_stub_map.pyr   r   )   sf    " _G		!$	>4w>>	{	#	# I (=@G'H I	#		    c                 8    Uc  [         nUR                  XX#5      $ )a_  The APIProxy entry point for a synchronous API call.

Args:
  service: string representing which service to call
  call: string representing which function to call
  request: protocol buffer for the request
  response: protocol buffer for the response
  stubmap: optional APIProxyStubMap instance, for dependency injection.

Returns:
  Response protocol buffer or None. Some implementations may return
  a response protocol buffer instead of modifying 'response'.
  Caller must use returned value in such cases. If 'response' is modified
  then returns None.

Raises:
  apiproxy_errors.Error or a subclass.
)r	   MakeSyncCall)r   callrequestresponser   s        r   r   r   C   s!    & _G			gW	??r   c                   R    \ rS rSrSrS rS rSS jrSS jrSS jr	S	 r
SS
 jrSrg)ListOfHooks[   a  An ordered collection of hooks for a particular API call.

A hook is a function that has exactly the same signature as
a service stub. It will be called before or after an api hook is
executed, depending on whether this list is for precall of postcall hooks.
Hooks can be used for debugging purposes (check certain
pre- or postconditions on api calls) or to apply patches to protocol
buffers before/after a call gets submitted.
c                 0    / U l         [        5       U l        g)zConstructor.N_ListOfHooks__contentset_ListOfHooks__unique_keysselfs    r   __init__ListOfHooks.__init__f   s     DN Dr   c                 6    U R                   R                  5       $ )z1Returns the amount of elements in the collection.)r   __len__r   s    r   r#   ListOfHooks.__len__o   s    >>!!##r   Nc                 J   U[         R                  " U5      4nXPR                  ;   a  g[        [         R                  " U5      S   5      n[         R
                  " U5      (       a  US-  nU R                  R                  XX4U45        U R                  R                  U5        g)a  Appends a hook at a certain position in the list.

Args:
  index: the index of where to insert the function
  key: a unique key (within the module) for this particular function.
    If something from the same module with the same key is already
    registered, nothing will be added.
  function: the hook to be added.
  service: optional argument that restricts the hook to a particular api

Returns:
  True if the collection was modified.
Fr      T)	inspect	getmoduler   len
getargspecismethodr   insertadd)r   indexkeyfunctionr   
unique_keynum_argss          r   __InsertListOfHooks.__Inserts   s     w((23J'''7%%h/23H""!mhNN%x(!CD:&r   c                 :    U R                  [        U 5      XU5      $ )az  Appends a hook at the end of the list.

Args:
  key: a unique key (within the module) for this particular function.
    If something from the same module with the same key is already
    registered, nothing will be added.
  function: the hook to be added.
  service: optional argument that restricts the hook to a particular api

Returns:
  True if the collection was modified.
)_ListOfHooks__Insertr)   r   r/   r0   r   s       r   AppendListOfHooks.Append   s     ==TC7;;r   c                 (    U R                  SXU5      $ )a  Inserts a hook at the beginning of the list.

Args:
  key: a unique key (within the module) for this particular function.
    If something from the same module with the same key is already
    registered, nothing will be added.
  function: the hook to be added.
  service: optional argument that restricts the hook to a particular api

Returns:
  True if the collection was modified.
r   )r6   r7   s       r   PushListOfHooks.Push   s     ==C733r   c                 0    / U l         [        5       U l        g)z8Removes all hooks from the list (useful for unit tests).Nr   r   s    r   ClearListOfHooks.Clear   s    DNDr   c           	          U R                    HB  u  pxpU	b  X:X  d  M  U
S:X  a  U" XX4XV5        M"  Ub  M'  U
S:X  a  U" XX4U5        M9  U" XX45        MD     g)aO  Invokes all hooks in this collection.

NOTE: For backwards compatibility, if error is not None, hooks
with 4 or 5 arguments are *not* called.  This situation
(error=None) only occurs when the RPC request raised an exception;
in the past no hooks would be called at all in that case.

Args:
  service: string representing which service to call
  call: string representing which function to call
  request: protocol buffer for the request
  response: protocol buffer for the response
  rpc: optional RPC used to make this call
  error: optional Exception instance to be passed as 6th argument
N      )r   )r   r   r   r   r   rpcerrorr/   r0   srvr2   s              r   CallListOfHooks.Call   s[      )-$s	q=
7'S
@ ]
7'S
9
7'
4 )7r   )	__content__unique_keysNNN)__name__
__module____qualname____firstlineno____doc__r    r#   r6   r8   r;   r>   rF   __static_attributes__ r   r   r   r   [   s*    $0<4
5r   r   c                   R    \ rS rSrSrSS jrS rS rS rS r	S	 r
S
 rS rS rSrg)APIProxyStubMap   a  Container of APIProxy stubs for more convenient unittesting.

Stubs may be either trivial implementations of APIProxy services (e.g.
DatastoreFileStub, UserServiceStub) or "real" implementations.

For unittests, we may want to mix and match real and trivial implementations
of services in order to better focus testing on individual service
implementations. To achieve this, we allow the client to attach stubs to
service names, as well as define a default stub to be used if no specific
matching stub is identified.
Nc                 Z    0 U l         Xl        [        5       U l        [        5       U l        g)z|Constructor.

Args:
  default_stub: optional stub

'default_stub' will be used whenever no specific matching stub is found.
N)_APIProxyStubMap__stub_map_APIProxyStubMap__default_stubr   _APIProxyStubMap__precall_hooks _APIProxyStubMap__postcall_hooks)r   default_stubs     r   r    APIProxyStubMap.__init__   s%     DO&&=D'MDr   c                     U R                   $ z(Gets a collection for all precall hooks.)rY   r   s    r   GetPreCallHooksAPIProxyStubMap.GetPreCallHooks   s    r   c                     U R                   $ r^   )rZ   r   s    r   GetPostCallHooks APIProxyStubMap.GetPostCallHooks   s       r   c                 R    X R                   U'   US:X  a  U R                  SU5        gg)zReplace the existing stub for the specified service with a new one.

NOTE: This is a risky operation; external callers should use this with
caution.

Args:
  service: string
  stub: stub
	datastoredatastore_v3N)rW   RegisterStubr   r   r   s      r   ReplaceStubAPIProxyStubMap.ReplaceStub   s/      $OOG +
- r   c                 d    XR                   ;  d   [        U5      5       eU R                  X5        g)z\Register the provided stub for the specified service.

Args:
  service: string
  stub: stub
N)rW   reprri   rh   s      r   rg   APIProxyStubMap.RegisterStub  s+     //)84=8)W#r   c                 L    U R                   R                  XR                  5      $ )zRetrieve the stub registered for the specified service.

Args:
  service: string

Returns:
  stub

Returns the stub registered for 'service', and returns the default stub
if no such stub is found.
)rW   getrX   )r   r   s     r   r
   APIProxyStubMap.GetStub  s     ??w(;(;<<r   c                 ,    [        U R                  5      $ )z^Get a copy of the stub map. For testing only.

Returns:
  Get a shallow copy of the stub map.
)dictrW   r   s    r   _CopyStubMapAPIProxyStubMap._CopyStubMap  s       r   c           	         U R                  U5      nU(       d
   SU-  5       e[        US5      (       a~  UR                  5       nU R                  R	                  XX4U5         UR                  XX45        UR                  5         UR                  5         U R                  R	                  XX4U5        gU R                  R	                  XX45         UR                  XX45      nU R                  R	                  XUU=(       d    U5        U$ ! [         a#  nU R                  R	                  XX4Xg5        e SnAff = f! [         a$  nU R                  R	                  XX4SU5        e SnAff = f)a  The APIProxy entry point.

Args:
  service: string representing which service to call
  call: string representing which function to call
  request: protocol buffer for the request
  response: protocol buffer for the response

Returns:
  Response protocol buffer or None. Some implementations may return
  a response protocol buffer instead of modifying 'response'.
  Caller must use returned value in such cases. If 'response' is modified
  then returns None.

Raises:
  apiproxy_errors.Error or a subclass.
r   r   N)r
   r   r   rY   rF   MakeCallWaitCheckSuccessrZ   	Exceptionr   )	r   r   r   r   r   r   rC   errreturned_responses	            r   r   APIProxyStubMap.MakeSyncCall$  sK   ( << D@6@@4t[!!NNc
w#FJWG6

 	""7'SI
wA! --gWO
 	""7'#4#@	B    ""7'SN  ""7'T3Os0   "2D	 D9 	
D6D11D69
E'E""E'c                 \    U R                   (       a  U R                   R                  5         g g rJ   )rX   CancelApiCallsr   s    r   r~   APIProxyStubMap.CancelApiCallsR  s"    
((* r   )__default_stub__postcall_hooks__precall_hooks
__stub_maprJ   )rL   rM   rN   rO   rP   r    r_   rb   ri   rg   r
   rs   r   r~   rQ   rR   r   r   rT   rT      s5    
* !.&$=!,!\+r   rT   c                   H   \ rS rSrSrSrSrSrSrSr	 " S S\
R                  5      r\" 5       rSS jrS r\S	 5       r\S
 5       r\S 5       r\S 5       r\S 5       r\S 5       r\S 5       r\S 5       r SS jrS rS rS rS r\S 5       r\S 5       r \S 5       r!Sr"g)UserRPCiW  a  Wrapper class for asynchronous RPC.

Simplest low-level usage pattern:

  rpc = UserRPC('service', [deadline], [callback])
  rpc.make_call('method', request, response)
  .
  .
  .
  rpc.wait()
  rpc.check_success()

However, a service module normally provides a wrapper so that the
typical usage pattern becomes more like this:

  from google.appengine.api import service
  rpc = service.create_rpc([deadline], [callback])
  service.make_method_call(rpc, [service-specific-args])
  .
  .
  .
  rpc.wait()
  result = rpc.get_result()

The service.make_method_call() function sets a service- and method-
specific hook function that is called by rpc.get_result() with the
rpc object as its first argument, and service-specific value as its
second argument.  The hook function should call rpc.check_success()
and then extract the user-level result from the rpc.result
protobuffer.  Additional arguments may be passed from
make_method_call() to the get_result hook via the second argument.

Also note wait_any() and wait_all(), which wait for multiple RPCs.
NFc                       \ rS rSrSrSrSrg)UserRPC.MyLocali  z0Class to hold per-thread class level attributes.FrR   N)rL   rM   rN   rO   rP   may_interrupt_waitrQ   rR   r   r   MyLocalr     s    :r   r   c                     Uc  [         nX@l        Xl        [        X5      U l        X R                  l        U R                  U R                  l        X0l        SU R                  R                  l
        g)zConstructor.

Args:
  service: The service name.
  deadline: Optional deadline.  Default depends on the implementation.
  callback: Optional argument-less callback function.
  stubmap: optional APIProxyStubMap instance, for dependency injection.
NF)r	   _UserRPC__stubmap_UserRPC__servicer   _UserRPC__rpcdeadline_UserRPC__internal_callbackcallback	__class___UserRPC__localr   )r   r   r   r   r   s        r   r    UserRPC.__init__  sY     gNN7,DJ"JJ22DJJM 16DNN-r   c                     SU l         SU R                  l        U R                  R                  R
                  (       a=  U R                  R                  (       d!  [        R                  " SU R                  5      egg)zThis is the callback set on the low-level RPC object.

It sets a flag on the current object indicating that the high-level
callback should now be called.  If interrupts are enabled, it also
interrupts the current wait_any() call by raising an exception.
TN)	!_UserRPC__must_call_user_callbackr   r   r   r   r   	exceptionr   InterruptedErrorr   s    r   __internal_callbackUserRPC.__internal_callback  sY     &*D"DJJ~~009M9M ,,T4::>> :N0r   c                     U R                   $ )zReturn the service name.)r   r   s    r   r   UserRPC.service  s     >>r   c                     U R                   $ )zReturn the method name.)_UserRPC__methodr   s    r   methodUserRPC.method  s     ==r   c                 .    U R                   R                  $ )z8Return the deadline, if set explicitly (otherwise None).)r   r   r   s    r   r   UserRPC.deadline       ::r   c                 .    U R                   R                  $ )z*Return the request protocol buffer object.)r   r   r   s    r   r   UserRPC.request  s     ::r   c                 .    U R                   R                  $ )z+Return the response protocol buffer object.)r   r   r   s    r   r   UserRPC.response  r   r   c                 .    U R                   R                  $ )zeReturn the RPC state.

Possible values are attributes of apiproxy_rpc.RPC: IDLE, RUNNING,
FINISHING.
)r   stater   s    r   r   UserRPC.state  s     ::r   c                     U R                   $ )z$Return the get-result hook function.)_UserRPC__get_result_hookr   s    r   get_result_hookUserRPC.get_result_hook  s     !!!r   c                     U R                   $ )z+Return the user data for the hook function.)_UserRPC__user_datar   s    r   	user_dataUserRPC.user_data  s     r   c                    U R                   R                  [        R                  R                  :X  d   [        U R                  5      5       eXl        X@l        XPl        U R                  R                  5       R                  U R                  XX0R                   5        U R                   R                  U R                  XU5        g)a?  Initiate a call.

Args:
  method: The method name.
  request: The request protocol buffer.
  response: The response protocol buffer.
  get_result_hook: Optional get-result hook function.  If not None,
    this must be a function with exactly one argument, the RPC
    object (self).  Its return value is returned from get_result().
  user_data: Optional additional arbitrary data for the get-result
    hook function.  This can be accessed as rpc.user_data.  The
    type of this value is up to the service module.

This function may only be called once per RPC object.  It sends
the request to the remote server, but does not wait for a
response.  This allows concurrent execution of the remote call and
further local processing (e.g., making additional remote calls).

Before the call is initiated, the precall hooks are called.
N)r   r   r   RPCIDLErl   r   r   r   r   r_   rF   r   rv   )r   r   r   r   r   r   s         r   	make_callUserRPC.make_call  s    . ::|//444Fd4::6FF4M, NN""$))::? 	JJBr   c                    U R                   R                  [        R                  R                  :w  d   [        U R                  5      5       eU R                   R                  [        R                  R                  :X  a  U R                   R                  5         U R                   R                  [        R                  R                  :X  d   [        U R                  5      5       eU R                  5         g)a  Wait for the call to complete, and call callback if needed.

This and wait_any()/wait_all() are the only time callback
functions may be called.  (However, note that check_success() and
get_result() call wait().)  Waiting for one RPC will not cause
callbacks for other RPCs to be called.  Callback functions may
call check_success() and get_result().

Callbacks are called without arguments; if a callback needs access
to the RPC object a Python nested function (a.k.a. closure) or a
bound may be used.  To facilitate this, the callback may be
assigned after the RPC object is created (but before make_call()
is called).

Note: don't confuse callbacks with get-result hooks or precall
and postcall hooks.
N)
r   r   r   r   r   rl   RUNNINGrw   	FINISHING_UserRPC__call_user_callbackr   s    r   waitUserRPC.wait  s    & ::|//444Fd4::6FF4zz<++333
jjoo::|//999K4

;KK9r   c                 r    U R                   (       a&  SU l         U R                  b  U R                  5         ggg)z+Call the high-level callback, if requested.FN)r   r   r   s    r   __call_user_callbackUserRPC.__call_user_callback&  s0    %%',d$		" 
# &r   c           	      `   U R                  5          U R                  R                  5         U R                  (       dg  SU l        U R                  R                  5       R                  U R                  U R                  U R                  U R                  U R                  5        gg! [         a~  nU R                  (       dg  SU l        U R                  R                  5       R                  U R                  U R                  U R                  U R                  U R                  U5        e SnAff = f)aC  Check for success of the RPC, possibly raising an exception.

This function should be called at least once per RPC.  If wait()
hasn't been called yet, it is called first.  If the RPC caused
an exceptional condition, an exception will be raised here.
The first time check_success() is called, the postcall hooks
are called.
TN)r   r   rx   _UserRPC__postcall_hooks_calledr   rb   rF   r   r   r   r   ry   )r   rz   s     r   check_successUserRPC.check_success-  s     	IIK;
jj ))'+$'')..t~~t}}/3||T]]/3zz	; *  ))'+$'')..t~~t}}/3||T]]/3zz3	@ s   B% %
D-/A9D((D-c                 `    U R                   c  U R                  5         gU R                  U 5      $ )a=  Get the result of the RPC, or possibly raise an exception.

This implies a call to check_success().  If a get-result hook was
passed to make_call(), that hook is responsible for calling
check_success(), and the return value of the hook is returned.
Otherwise, check_success() is called directly and None is
returned.
N)r   r   r   s    r   
get_resultUserRPC.get_resultK  s0     %
##D))r   c                 P   SnU H  n[        X 5      (       d   [        U5      5       eUR                  R                  nU[        R
                  R                  :X  a  UR                  5         US4s  $ U[        R
                  R                  :w  a  M   [        U5      5       e   SU4$ )av  Check the list of RPCs for one that is finished, or one that is running.

Args:
  rpcs: Iterable collection of UserRPC instances.

Returns:
  A pair (finished, running), as follows:
  (UserRPC, None) indicating the first RPC found that is finished;
  (None, UserRPC) indicating the first RPC found that is running;
  (None, None) indicating no RPCs are finished or running.
N)	
isinstancerl   r   r   r   r   r   r   r   )clsrpcsrC   r   s       r   __check_oneUserRPC.__check_one^  s     C!!,49,!iiooe	,"",,	,  "Dyl&&+++6T#Y6+  9r   c                    [        U5      ULd   S5       eU R                  U5      u  p#Ub  U$ Uc  g SU R                  l         UR                  R                  5         SU R                  l        U R                  U5      u  p#U$ ! [        R                   a,  nSUR                  l	        SUR                  l
         SnANaSnAff = f! SU R                  l        f = f)a  Wait until an RPC is finished.

Args:
  rpcs: Iterable collection of UserRPC instances.

Returns:
  A UserRPC instance, indicating the first RPC among the given
  RPCs that finished; or None, indicating that either an RPC not
  among the given RPCs finished in the mean time, or the iterable
  is empty.

NOTES:

(1) Repeatedly calling wait_any() with the same arguments will not
    make progress; it will keep returning the same RPC (the one
    that finished first).  The callback, however, will only be
    called the first time the RPC finishes (which may be here or
    in the wait() method).

(2) It may return before any of the given RPCs finishes, if
    another pending RPC exists that is not included in the rpcs
    argument.  In this case the other RPC's callback will *not*
    be called.  The motivation for this feature is that wait_any()
    may be used as a low-level building block for a variety of
    high-level constructs, some of which prefer to block for the
    minimal amount of time without busy-waiting.
z*rpcs must be a collection, not an iteratorNTF)iter_UserRPC__check_oner   r   r   rw   r   r   rC   
_exception
_traceback)r   r   finishedrunningrz   s        r   wait_anyUserRPC.wait_anyu  s    : :T!O#OO!-Ho-'+ckk$	" (-ckk$-HO -- " "!" (-ckk$s/   C B C"C ;C  CC Cc                     [        U5      nU(       a/  U R                  U5      nUb  UR                  U5        U(       a  M.  gg)zWait until all given RPCs are finished.

This is a thin wrapper around wait_any() that loops until all
given RPCs have finished.

Args:
  rpcs: Iterable collection of UserRPC instances.

Returns:
  None.
N)r   r   remove)r   r   r   s      r   wait_allUserRPC.wait_all  s7     t9D
d#h		H $r   )	__get_result_hook__method__must_call_user_callback__postcall_hooks_called__rpc	__service	__stubmap__user_datar   )NNNrK   )#rL   rM   rN   rO   rP   r   r   r   r   r   	threadinglocalr   r   r    r   propertyr   r   r   r   r   r   r   r   r   r   r   r   r   classmethodr   r   r   rQ   rR   r   r   r   r   W  sG   !F (+!#	 
 I'6@?(             " "  
 15!CF 6;<*&  , 1 1f  r   r   c                       [        S[        5       [        5       S/5      n [        U R                  5      $ ! [
        [        4 a    [        5       s $ f = f)Nz googlecloudsdk.appengine.runtimer	   )
__import__globalslocalsrT   r	   AttributeErrorImportError)runtimes    r   GetDefaultAPIProxyr     sQ    
 ;WY$'G7++,,
+	& s   36 AArJ   )rP   
__future__r   r'   sysr   googlecloudsdk.appengine.apir    googlecloudsdk.appengine.runtimer   r   r   objectr   rT   r   r   r	   rR   r   r   <module>r      se     '  
  5 <4@0n5& n5bH+f H+Vcf cN  r   