o
    O                     @   s   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G dd deZ		dddZdS )z5A class for parsing a resource projection expression.    )absolute_import)division)unicode_literalsN)resource_exceptions)resource_filter)resource_lex)resource_projection_spec)resource_transformc                   @   s   e Zd ZdZddgZdgZdddZG dd	 d	eZG d
d deZ	dd Z
dd Zdd Zdd Zdd Zdd Zdd ZdddZdS )Parsera  Resource projection expression parser.

  A projection is an expression string that contains a list of resource keys
  with optional attributes. This class parses a projection expression into
  resource key attributes and a tree data structure that is used by a projector.

  A projector is a method that takes a JSON-serializable 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.

  In the Cloud SDK projection attributes are used for output formatting.

  A default or empty projection expression still produces a projector that
  converts a resource to a JSON-serializable object.

  Attributes:
    __key_attributes_only: Parse projection key list for attributes only.
    _projection: The resource_projection_spec.ProjectionSpec to parse into.
    _root: The projection _Tree tree root node.
    _snake_headings: Dict used to disambiguate key attribute labels.
    _snake_re: Compiled re for converting key names to angry snake case.
  optionalreversewrapNc                 C   s*   d| _ tj||||d| _i | _d| _dS )a!  Constructor.

    Args:
      defaults: resource_projection_spec.ProjectionSpec defaults.
      symbols: Transform function symbol table dict indexed by function name.
      aliases: Resource key alias dictionary.
      compiler: The projection compiler method for nested projections.
    FdefaultssymbolsaliasescompilerN)_Parser__key_attributes_onlyr   ProjectionSpec_projection_snake_headings	_snake_re)selfr   r   r   r    r   T/tmp/google-cloud-sdk/lib/googlecloudsdk/core/resource/resource_projection_parser.py__init__?   s   	
zParser.__init__c                   @   s   e Zd ZdZdd ZdS )zParser._TreezDefines a Projection tree node.

    Attributes:
      tree: Projection _Tree node indexed by key path.
      attribute: Key _Attribute.
    c                 C   s   i | _ || _d S N)tree	attribute)r   r   r   r   r   r   V   s   
zParser._Tree.__init__N)__name__
__module____qualname____doc__r   r   r   r   r   _TreeN   s    r#   c                   @   s    e Zd ZdZdd Zdd ZdS )zParser._Attributea  Defines a projection key attribute.

    Attribute semantics, except transform, are caller defined.  e.g., the table
    formatter uses the label attribute for the column heading for the key.

    Attributes:
      align: The column alignment name: left, center, or right.
      flag: The projection algorithm flag, one of DEFAULT, INNER, PROJECT.
      hidden: Attribute is projected but not displayed.
      label: A string associated with each projection key.
      optional: Column data is optional if True.
      order: The column sort order, None if not ordered. Lower values have
        higher sort precedence.
      reverse: Reverse column sort if True.
      skip_reorder: Don't reorder this attribute in the next _Reorder().
      subformat: Sub-format string.
      transform: obj = func(obj,...) function applied during projection.
      width: Fixed column width.
      wrap: Column can be wrapped if True.
    c                 C   sN   t j| _|| _d| _d | _d | _d | _d | _d| _	d | _
d | _d | _d | _d S )NF)r   ALIGN_DEFAULTalignflaghiddenlabelr   orderr   skip_reorder	subformat	transformwidthr   )r   r&   r   r   r   r   p   s   
zParser._Attribute.__init__c              
   C   s   g }| j r
|d | jr|d | jr|d | jr"|d |r-dd|}nd}dj| j| jd u r:d	nt	
| j| jd u rG| jnd
| j d
 | j| jrV| jjnd | j| j|dS )Nr'   r   r   r+   z, [{0}]| zK({flag}, {order}, {label}, {align}, {active}, {wrap}, {transform}{options})	UNORDERED')r&   r)   r(   r%   activer   r,   options)r'   appendr   r   r+   formatjoinr&   r)   six	text_typer(   r%   r,   r2   r   )r   optionr3   r   r   r   __str__~   s:   





zParser._Attribute.__str__N)r   r    r!   r"   r   r:   r   r   r   r   
_AttributeZ   s    r;   c                 C   sz   | j du rtd| _ d}t|D ])}t|tjr:| j d| }|r+|d | }n|}|| j	vr:d| j	|<  |S q|S )a  Returns an ANGRY_SNAKE_CASE string representation of a parsed key.

    For key input [A, B, C] the headings [C, C_B, C_B_A] are generated. The
    first heading not in self._snake_headings is added to self._snake_headings
    and returned.

    Args:
        key: A parsed resource key and/or list of strings.

    Returns:
      The ANGRY_SNAKE_CASE string representation of key, adding components
        from right to left to disambiguate from previous ANGRY_SNAKE_CASE
        strings.
    Nz)((?<=[a-z0-9])[A-Z]+|(?!^)[A-Z](?=[a-z]))r/   z_\1_   )
r   recompilereversed
isinstancer7   string_typessubupperr   )r   keyr(   index	key_snaker   r   r   _AngrySnakeCase   s   


 zParser._AngrySnakeCasec                    s  | j } dd D ]+}|j}||v r$|| j}|j| jjkr#| jj|_n| | | jj||< || }q	|j} r> d nd}||v }|rk|| j}| j	sat
 fdd| j D rat|}| j	rg|jsjd|_n0t|tjrd|v rt|d ||< || j}n|}| j	r|jrd|_ s|jr| |||< |jdur|j|_| j	r|  jd7  _d|_|jdur|j|_n|jdu r|  |_|jtjkr|j|_|jdur|j|_n|jdu rd|_|jdur|j|_n|jdu rd|_|jr|j|_|jr|j|_|jdur|j|_n	|jdu rd|_|jdur"|j|_n	|jdu r+d|_| j |j | | j	r<|jrJ| jj|_| j! | dS |sT| jj"|_dS dS )	zPropagates default attribute values and adds key to the projection.

    Args:
      key: The parsed key to add.
      attribute_add: Parsed _Attribute to add.
    Nr/   c                    s   g | ]	}|j  kr|qS r   rE   ).0colrJ   r   r   
<listcomp>   s    z"Parser._AddKey.<locals>.<listcomp>FTr=   )#_rootr   r   r&   r   PROJECTINNERr#   r;   r   anyColumnscopyr)   r'   rA   r7   integer_typesdeepcopyr,   _Parser__key_order_offsetr*   r(   rH   r%   r   r$   r   r   r+   r-   r   AddAliasAddKeyDEFAULT)r   rE   attribute_add
projectionnamer   r   name_in_treer   rJ   r   _AddKey   s   


















zParser._AddKeyc                    s.    fdd j r jj d_ dS dS )zRecursively adds self.__key_order_offset to non-zero attribute order.

    This slides established attribute.order out of the way so new
    attribute.order in projection composition take precedence.
    c                    sH   |   D ]}|jjr|jjrd|j_n	|j jj7  _ |j qdS )a;  Adds self.__key_order_offset to unmarked attribute.order.

      A DFS search that visits each attribute once. The search clears
      skip_reorder attributes marked skip_reorder, otherwise it adds
      self.__key_order_offset to attribute.order.

      Args:
        tree: The attribute subtree to reorder.
      FN)valuesr   r)   r*   rV   r   )r   node_AddOffsetToOrderr   r   r   rb     s   

z*Parser._Reorder.<locals>._AddOffsetToOrderr   N)rV   rN   r   r   r   ra   r   _Reorder  s
   
zParser._Reorderc                 C   s  	 | j jddd}| j  }| j jdddr"d}| j jdddd}nd}|d	r2|d
d }d}nd}|| jv rH|sGtd| j 	|n|r[|| j
vr[td| j 	||dkrv|smtd| j 	|| j||| na|dkr|tjvrtd| j 	|||_nH|dkr|pd|_n>|dkr|pd|_n4|dkr||_n,|dkr||_n$|dkr||_n|dkr||_n|dkr||_ntd| j 	|| j dsdS q)aS  Parses one or more key attributes and adds them to attribute.

    The initial ':' has been consumed by the caller.

    Args:
      key: The parsed key name of the attributes.
      attribute: Add the parsed transform to this resource_projector._Attribute.

    Raises:
      ExpressionSyntaxError: The expression has a syntax error.
    Tz=:,)Fspace=eoi_okz:,)rf   convertno-   Nzvalue not expected [{0}].zvalue expected [{0}].aliaszCannot unset alias [{0}].r%   zUnknown alignment [{0}].r5   r/   r(   r   r   sortr-   r   zUnknown key attribute [{0}].:)_lexTokenGetPositionIsCharacter
startswith_BOOLEAN_ATTRIBUTESr   ExpressionSyntaxErrorr5   Annotate_OPTIONAL_BOOLEAN_ATTRIBUTESr   rW   r   
ALIGNMENTSr%   r+   r(   r   r   r)   r-   r   )r   rE   r   r\   hereboolean_valuevaluer   r   r   _ParseKeyAttributes2  sj   



zParser._ParseKeyAttributesc                    sP  | j  \}}| j jdddr| j | | jj}nd}| js"|s)| jr/|r/|s/t|}n| 	| jj
}|js=||_n
|rG|jj|j | j   | j drX| || |jr|jjr| jjtd  fdd}tjtj|id	}tj|jj|d
 sdS |jdu r|s|jr| |jjg|jjd j |_| || dS )a  Parses a key and optional attributes from the expression.

    The parsed key is appended to the ordered list of keys via _AddKey().
    Transform functions and key attributes are also handled here.

    Raises:
      ExpressionSyntaxError: The expression has a syntax error.
    (Trh   Nrp   conditionalsc                    s   t  |d S r   )getattr)
unused_objrestrictionunused_patternr   r   r   EvalGlobalRestriction  s   z/Parser._ParseKey.<locals>.EvalGlobalRestriction)r   )r   r   ) rq   KeyWithAttributert   	Transformpopr   r2   r   rS   r;   rO   r,   _transformsextend	SkipSpacer~   conditionalr   getr	   GetTypeDataNamer   r   GLOBAL_RESTRICTION_NAMEr   CompileEvaluater(   rH   r\   argsr^   )r   rE   r   add_transformr   r   r   r   r   	_ParseKeyr  s\   	
zParser._ParseKeyc                 C   sX   | j drdS 	 |   | j   | j drdS | j ds+td| j  q	)zParses a comma separated list of keys.

    The initial '(' has already been consumed by the caller.

    Raises:
      ExpressionSyntaxError: The expression has a syntax error.
    )NT,z*Expected ) in projection expression [{0}].)rq   rt   r   r   r   rw   r5   rx   rc   r   r   r   
_ParseKeys  s   
zParser._ParseKeysc                 C   s   	 | j jddd}|rL| j dr| j jdddd}nd}t|tjr-|d	d
dd}| j|| |	drD| j
|dd  n| j
d|  | j drTdS | j dsetd| j  q)zParses a comma separated [no-]name[=value] projection attribute list.

    The initial '[' has already been consumed by the caller.

    Raises:
      ExpressionSyntaxError: The expression has a syntax error.
    Tz=,])Fre   rg   z,])rj   r=   z\n
z\t	rl   rm   N]r   z#Expected ] in attribute list [{0}].)rq   rr   rt   rA   r7   rB   replacer   AddAttributeru   DelAttributer   rw   r5   rx   )r   r\   r}   r   r   r   _ParseAttributes  s&   
zParser._ParseAttributesc                 C   sR  | j  | _| js| | | j j| _| j | j | j | | | j j |rt	
|| j | _d}d| _| j r| jdr\| jsMd}| j   |   | jr[d| _|   n;| jdrg|   n0| jdrtd| _d| _n#| j }| jd}| std| j|| j | d}| j s=d	| _|r| j   | j S )
a  Parse a projection expression.

    An empty projection is OK.

    Args:
      expression: The resource projection expression string.

    Raises:
      ExpressionSyntaxError: The expression has a syntax error.

    Returns:
      A ProjectionSpec for the expression.
    Fr   [rp   Tr   z:([zName expected [{0}].N)r   GetRootrN   r#   r;   rY   SetRootSetEmptyrO   r   Lexerrq   r   r   rt   Defaultsr   rd   r   rV   rs   rr   isalphar   rw   r5   rx   SetName)r   
expressionr   r{   r\   r   r   r   Parse  sN   





zParser.Parse)NNNNr   )r   r    r!   r"   rv   ry   r   objectr#   r;   rH   r^   rd   r~   r   r   r   r   r   r   r   r   r
   "   s    
?^@5r
   r/   c                 C   s   t ||||d| S )a  Parses a resource projector expression.

  Args:
    expression: The resource projection expression string.
    defaults: resource_projection_spec.ProjectionSpec defaults.
    symbols: Transform function symbol table dict indexed by function name.
    aliases: Resource key alias dictionary.
    compiler: The projection compiler method for nested projections.

  Returns:
    A ProjectionSpec for the expression.
  r   )r
   r   )r   r   r   r   r   r   r   r   r     s
   r   )r/   NNNN)r"   
__future__r   r   r   rS   r>   googlecloudsdk.core.resourcer   r   r   r   r	   r7   r   r
   r   r   r   r   r   <module>   s&      m