
    lQ                         d Z ddlmZ ddlmZ ddlmZ ddlZddlZddlmZ	 ddl
mZ ddlmZ dd	lmZ ddlmZ ddlZdd
lmZ d Z G d de      Z	 	 ddZ G d de      Zy)a  A class for projecting and transforming JSON-serializable objects.

From the Cloud SDK doc "DD: gcloud resource projection algorithm":

  Algorithm

  The algorithm represents a resource R and projection P as trees. P is used
  to color the nodes of R (with the colors {0, 1, 2, 3}) as follows:

  1. Initialize the nodes in R to (id, 0, identity).
  2. Do a DFS on P. Let p be the projection subtree and r be the resource
     subtree at each level. Let f be a flag value at each level, and initialize
     f to the flag value of the root node of P.
     2.1. For each id i in p that is also in r, set r[i].flag |= p[i].flag | f,
          and r[i].transform = p[i].transform if  r[i].transform != identity and
          p[i].transform != identity.
     2.2. If p contains a slice then repeat step 2.1 with i = slice.
     2.3. If r[i].flag is 0 then prune the search at this node, otherwise
     2.4. descend to the next level with r = r[i], p = p[i], and f = r[i].flag.
  3. At the end of the search the nodes of R will be colored with the values
     {0, 1, 2, 3}. The projected keys are the set of the longest paths from the
     root of R ending with a flag value >= 2.

  Remarks

  If the initial value of f is PROJECT or PROJECT* (2 or 3) then all keys in R
  are projected. Non-leaf keys may be projected in this model, resulting in dict
  or list values instead of scalars.

Example usage:

  projector = resource_projector.Compile(expression)
  for resource in resources:
    obj = projector.Evaluate(resource)
    OperateOnProjectedResource(obj)
    )absolute_import)division)unicode_literalsN)messages)encoding)resource_projection_parser)resource_property)rangec                 4    t               j                  |       S )zReturns resource or a JSON-serializable copy of resource.

  Args:
    resource: The resource object.

  Returns:
    The original resource if it is a primitive type object, otherwise a
    JSON-serializable copy of resource.
  )CompileEvaluate)resources    6lib/googlecloudsdk/core/resource/resource_projector.pyMakeSerializabler   G   s     
		H	%%    c                   `    e Zd ZdZ	 	 ddZd Zd Zd Zd Zd Z	ddZ
d	 Zd
 Zd Zd Zd Zy)	Projectora
  Projects a resource using a ProjectionSpec.

  A projector is a method that takes an object and a projection as input and
  produces a new JSON-serializable object containing only the values
  corresponding to the keys in the projection. Optional projection key
  attributes may transform the values in the resulting JSON-serializable object.

  Attributes:
    _projection: The projection object.
    _been_here_done_that: A set of the current object id()'s being projected.
      Used to catch recursive objects like datetime.datetime.max.
    _by_columns: True if Projector projects to a list of columns.
    _columns: self._projection.Columns() column attributes.
    _ignore_default_transforms: Ignore default projection transforms if True.
    _retain_none_values: Retain dict entries with None values.
    _transforms_enabled_attribute: The projection.Attributes()
      transforms_enabled setting.
    _transforms_enabled: Projection attribute transforms enabled if True,
      disabled if False, or set by each Evaluate().
  c                    || _         || _        | j                   j                         | _        || _        || _        t               | _        |j                         }d|v rd| _	        nd|v rd| _	        nd| _	        d|v | _
        y)a0  Constructor.

    Args:
      projection: A ProjectionSpec (parsed resource projection expression).
      by_columns: Project to a list of columns if True.
      ignore_default_transforms: Ignore default projection transforms if True.
      retain_none_values: project dict entries with None values.
    
transformsTzno-transformsFNzjson-decode)_projection_by_columnsColumns_columns_ignore_default_transforms_retain_none_valuesset_been_here_done_that
Attributes_transforms_enabled_attribute_json_decode)self
projection
by_columnsignore_default_transformsretain_none_values
attributess         r   __init__zProjector.__init__j   s     "D!D$$,,.DM&?D#1D #D&&(Jz!+/d(	J	&+0d(+/d(%3Dr   c                 z    | j                   | j                   S |j                  d| j                  j                  fv S )zReturns True if transform is enabled.

    Args:
      transform: The resource_projection_parser._Transform object.

    Returns:
      True if the transform is enabled, False if not.
    N)_transforms_enabledactiver   )r!   	transforms     r   _TransformIsEnabledzProjector._TransformIsEnabled   s>     +%%%d&6&6&=&=>>>r   c                 <   || j                   j                  k  ry|rl|j                  r`|j                  j                  rJ| j	                  |j                  j                        r%|j                  j                  j                  |      S | j                  |||d      S )a"  Applies projection.attribute.transform in projection if any to obj.

    Args:
      obj: An object.
      projection: Projection _Tree node.
      flag: A bitmask of DEFAULT, INNER, PROJECT.

    Returns:
      The transformed obj if there was a transform, otherwise the original obj.
    NTleaf)r   PROJECT	attributer+   r,   r   _Project)r!   objr"   flags       r   _ProjectAttributezProjector._ProjectAttribute   s     d&&&z++
0D0D0N0N$$Z%9%9%C%CD!!++44S99==j$T=::r   c                    i }t               }t        |t        j                        r*t        j                  |      |d<   |j                  d       nD	 |j                  t        |j                        D cg c]  }|j                         s| c}       t        |      D ]  }|j                  d      r||v r	 t        ||      }t        |d      r4|}	||j                  v rY|j                  |   }
|	|
j                  j                  z  }	|	| j                   j"                  k  r| j%                  ||
|	      ||<   | j'                  || j                   j)                         |	      ||<    |S c c}w # t        $ r Y w xY w#  Y xY w)a-  Converts class object to a dict.

    Private and callable attributes are omitted in the dict.

    Args:
      obj: The class object to convert.
      projection: Projection _Tree node.
      flag: A bitmask of DEFAULT, INNER, PROJECT.

    Returns:
      The dict representing the class object.
    datetime)maxmin
resolutiontzinfo___call__)r   
isinstancer7   six	text_typeupdatedir	__class__isupperAttributeError
startswithgetattrhasattrtreer1   r4   r   INNERr2   r5   GetEmpty)r!   r3   r"   r4   rexcludeaattrvaluefchild_projections              r   _ProjectClasszProjector._ProjectClass   su    	AeG#x(() mmC(a
m nn;<3s}}#5E#5a#5EF C			T" 

	#
a		 %??40	'',,,t%%%
 --'7;$((0@0@0I0I0KQO$3 4 H; F s6   "E4 4E/
E/E4 ;F/E4 4	F ?F Fc                    |s|S i }	 t        j                  |       t        j                  |      D ]  \  }}|}||j                  v rV|j                  |   }||j                  j
                  z  }|| j                  j                  k  rX| j                  |||      }n+| j                  || j                  j                         |      }|3| j                  s'|| j                  j                  k\  s| j                  s	 ||t        j                  |      <    |xs dS # t        $ r Y yw xY w# t         $ r	 |||<   Y w xY w)zProjects a dictionary object.

    Args:
      obj: A dict.
      projection: Projection _Tree node.
      flag: A bitmask of DEFAULT, INNER, PROJECT.

    Returns:
      The projected obj.
    N)r?   	iteritems
ValueErrorrI   r1   r4   r   rJ   r2   r5   rK   r   r0   r   r   DecodeUnicodeError)	r!   r3   r"   r4   reskeyvalrQ   rR   s	            r   _ProjectDictzProjector._ProjectDict   s9    j
C	mmC MM#&S
a	
	%??3/	'',,,t%%%
 mmC!115$$S$*:*:*C*C*EqI
/T55
t''
'DMM	&)#hooc"
## '( ;$-  (  	#c(	s#   D ?D.	D+*D+.E ?E c                    ysg S 	 t              }	 d   }t	        g       }d}|j
                  s|| j                  j                  k  ry|j
                  D ]  }|M|| j                  j                  k\  s$|j
                  |   j                  j                  sB|j
                  |   }Rt        |t        j                        sm|t        t               t                    v s|j                  |        || j                  j                  k\  r|s| j                  j                         }|s|syd}|rdgt              z  }	ndgt!        fd|D              dz   z  }	|rt        t                    n|D ]  }|   }
|
|}||j
                  v r+|j
                  |   }|r||j                  j                  z  }n|}|rH||j                  j                  z  }|| j                  j"                  k\  r| j%                  |
||      }
nd}
|
|dk  r|t              z  }||k  r|}|
|	|<    |dk  ry|r|	d|dz    S |	S # t        $ r t              Y Aw xY w# t        $ r! 	 t              n# t        $ r Y Y yw xY wY nw xY w)zProjects a list, tuple or set object.

    Args:
      obj: A list, tuple or set.
      projection: Projection _Tree node.
      flag: A bitmask of DEFAULT, INNER, PROJECT.

    Returns:
      The projected obj.
    Nr   c              3   H   K   | ]  }|d k  r|t              z   n|  yw)r   N)len).0xr3   s     r   	<genexpr>z)Projector._ProjectList.<locals>.<genexpr>F  s%     H1!a%!c#h,Q6s   "   )r`   	TypeErrorsortedlistr   rI   r   r0   r1   r4   r>   r?   integer_typesr
   addrK   r8   rJ   r2   )r!   r3   r"   r4   r<   indicesslicedindexmaxindexrY   r[   rQ   rR   s    `           r   _ProjectListzProjector._ProjectList  s    {i
c(aF "gGF??	  ((	( ??%=d&&...ooe$..33__U+F 1 12uc#hYC11
++e
 # t'''((*f 6 HFc#hc FcHHH1LMc$*s3x7Jc 
 a	*//	!%??51
v$$
$! " 
	'',,,  &&& c#3Q7## 
	S	E	c%jK 8P !| #)3qA1c1q  Sk  3i  	sR   I  I II  II   	J
*I65J
6	J?J
JJ
	J
c                 j   t        |      }|| j                  v ry|nBt        |t        j                        st        |t        j
                        rt        |t        j
                        rt        j                  |      }| j                  r|j                  d      r|j                  d      s$|j                  d      r|j                  d      r	 | j                  t        j                  |      |||      S t        |t        t         t"        f      st        |t        j$                        rn,t        |t&              r t        j                  t)        |            }nt        |t*        j,                        r|j.                  }n| j                  j1                  |       ddlm} ddl}t        |t*        j8                        rt;        j<                  |      }nt        ||j8                        rdd	lm} |j=                  |      }n]t        ||j8                        r|j@                  jC                  |      }n+tE        |d
      rtE        |d      r| jG                  |||      }|rm|jH                  ra|jH                  jJ                  rK| jM                  |jH                  jJ                        r&|jH                  jJ                  jO                  |      }nh|| jP                  jR                  k\  s|rM|jT                  rAtE        |d
      r5tE        |d      r	 | jW                  |||      }n	 | j]                  |||      }| j                  j_                  |       |S |r|S | ja                  |||      S # t        $ r Y "w xY w# tX        tZ        f$ r d}Y Vw xY w# tX        tZ        f$ r d}Y mw xY w)a  Evaluate() helper function.

    This function takes a resource obj and a preprocessed projection. obj
    is a dense subtree of the resource schema (some keys values may be missing)
    and projection is a sparse, possibly improper, subtree of the resource
    schema. Improper in that it may contain paths that do not exist in the
    resource schema or object. _Project() traverses both trees simultaneously,
    guided by the projection tree. When a projection tree path reaches an
    non-existent obj tree path the projection tree traversal is pruned. When a
    projection tree path terminates with an existing obj tree path, that obj
    tree value is projected and the obj tree traversal is pruned.

    Since resources can be sparse a projection can reference values not present
    in a particular resource. Because of this the code is lenient on out of
    bound conditions that would normally be errors.

    Args:
      obj: An object.
      projection: Projection _Tree node.
      flag: A bitmask of DEFAULT, INNER, PROJECT.
      leaf: Do not call _ProjectAttribute() if True.

    Returns:
      An object containing only the key:values selected by projection, or obj if
      the projection is None or empty.
    Nz{"}[]r.   r   )message)json_format__iter___fieldsitems)1idr   r>   r?   r@   binary_typer   rW   r    rF   endswithr2   jsonloadsrV   boolfloatcomplexrh   	bytearraybytesprotorpc_messageEnumnameri   cloudsdk.google.protobufrs   protoMessageprotorpc_encodingMessageToDictrt   rC   to_dictrH   rS   r1   r+   r,   r   r   r0   rI   r\   IOErrorre   rn   discardr5   )	r!   r3   r"   r4   r/   objidprotobuf_messager   protobuf_encodings	            r   r2   zProjector._Projectu  s   6 sGE)))	
	C	':c3??+K 
C	)ooc"



..
3<<#4
..
#,,s"3	tzz#
DtL
L S40
1
S#++
,
	C	#OOE#J'c	C)..	/HHc
##E*F	C)11	2--c2c+334M--c2c5==)mm##C(sJ'73	+B  j$7
--



(
(

"
":#7#7#A#A
B"",,55c:T%%---
Z(3 ##CT:C##CT:C ''.j 3ID223
DIIg  	
	P 9% C
 9% Cs6   'M8 N 1N 8	NNNNN21N2c                     || _         y)z{Sets the projection to list-of-columns mode.

    Args:
      enable: Enables projection to a list-of-columns if True.
    N)r   r!   enables     r   SetByColumnszProjector.SetByColumns  s     Dr   c                     || _         y)zuSets the ignore default transforms mode.

    Args:
      enable: Disable default projection transforms if True.
    N)r   r   s     r   SetIgnoreDefaultTransformsz$Projector.SetIgnoreDefaultTransforms  s     '-D#r   c                     || _         y)zSets the projection to retain-none-values mode.

    Args:
      enable: Enables projection to a retain-none-values if True.
    N)r   r   s     r   SetRetainNoneValueszProjector.SetRetainNoneValues  s      &Dr   c                    | j                   | _        | j                  r| j                  s| j                  rd| _        | j
                  j                  }n| j
                  j                  }t        |d      r|j                         }| j                  || j
                  j                         |      S | j                  || j
                  j                         | j
                  j                        }| j                   | j                   | _        g }| j                  D ]  }|j                  r t        j                   ||j                        n|}|j"                  j$                  rK| j'                  |j"                  j$                        r&|j"                  j$                  j)                  ||      }|j+                  |        |S )a  Serializes/projects/transforms obj.

    A default or empty projection expression simply converts a resource object
    to a JSON-serializable copy of the object.

    Args:
      obj: An object.

    Returns:
      A JSON-serializeable object containing only the key values selected by
        the projection. The return value is a deep copy of the object: changes
        to the input object do not affect the JSON-serializable copy.
    Fr   )r   r)   r   r   r   r   DEFAULTr0   rH   r   r2   TreerK   r   rZ   r	   Getr1   r+   r,   r   append)r!   r3   r4   obj_serializedcolumnscolumnr[   s          r   r   zProjector.Evaluate  sv     $AAD4==	#( ''''	(	)""$]]3 0 0 5 5 7>>]]T&&($*:*:*B*BN ))1%)%D%D!DdG-- ZZ 




; 

 
			#	#(@(@



$
$) ((11#s;nnS   Nr   c                     | j                   S )zzReturns the ProjectionSpec object for the projector.

    Returns:
      The ProjectionSpec object for the projector.
    )r   )r!   s    r   
ProjectionzProjector.Projection  s     r   N)FFF)F)__name__
__module____qualname____doc__r'   r,   r5   rS   r\   rn   r2   r   r   r   r   r    r   r   r   r   T   sS    * -2CH42?;*7r&Pm2^_JB-&*Xr   r   c                 X    t        j                  | ||t              }t        |||      S )a  Compiles a resource projection expression.

  Args:
    expression: The resource projection string.
    defaults: resource_projection_spec.ProjectionSpec defaults.
    symbols: Transform function symbol table dict indexed by function name.
    by_columns: Project to a list of columns if True.
    retain_none_values: Retain dict entries with None values.

  Returns:
    A Projector containing the compiled expression ready for Evaluate().
  )defaultssymbolscompiler)r#   r%   )r   Parser   r   )
expressionr   r   r#   r%   r"   s         r   r   r   #  s2     *//8WwH*	:*&8
: :r   c                   (     e Zd ZdZ fdZd Z xZS )IdentityProjectorz>A no-op resource projector that preserves the original object.c                 P    t         t        |   t        j                                y N)superr   r'   r   r   )r!   rC   s    r   r'   zIdentityProjector.__init__:  s    	
T+,F,L,L,NOr   c                     |S r   r   )r!   r3   s     r   r   zIdentityProjector.Evaluate=  s    Jr   )r   r   r   r   r'   r   __classcell__)rC   s   @r   r   r   7  s    FPr   r   ) NNFF)r   
__future__r   r   r   r7   r{   apitools.base.protorpcliter   r   apitools.base.pyr   r   googlecloudsdk.core.resourcer   r	   googlecloudsdk.core.utilr?   	six.movesr
   r   objectr   r   r   r   r   r   <module>r      s`    #J '  '   C : C : - 
 
&L L^ DI$:(	 r   