o
    z                     @   sh  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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mZ ddlmZ ddlmZ ddlmZ ddlZe ZG dd deZG dd deZ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(G d'd( d(ej)Z*d)Z+d*d+ Z,d,d- Z-d.d/ Z.ej/j0j1j2ej/j0j1j2ej/j0j1j2d0Z3dzd2d3Z4G d4d5 d5eZ5G d6d7 d7eZ6G d8d9 d9eZ7G d:d; d;eZ8d<d= Z9d>d? Z:d@Z;dAdB Z<d{dDdEZ=dFdG Z>d|dHdIZ?d}dJdKZ@d~dLdMZAdNdO ZBdPdQ ZCd~dRdSZDdTdU ZEdVdW ZFdXdY ZGdZd[ ZHd\d] ZId^d_ ZJd`da ZK		C	1ddbdcZLd~dddeZMdfdg ZNdhdi ZOddkdlZPdmdn ZQdodp ZRejSrbeTneUZVe	jWjXeYe	jWjZeYe	jWj[eVe	jWj\eVe	jWj]eVe	jWj^eUe	jWj_eUe	jWj`eUe	jWjaejbe	jWjcede	jWjeejfe	jWjgeRe	jWjhdiZiddrdsZjd~dtduZkdvdw ZlG dxdy dyeZmdS )z?Utilities for generating and parsing arguments from API fields.    )absolute_import)division)unicode_literalsN)messages)encoding)extra_types)arg_parsers)base)util)
properties)resource_property)http_encodingc                   @   s   e Zd ZdZdS )ErrorzBase exception for this module.N)__name__
__module____qualname____doc__ r   r   K/tmp/google-cloud-sdk/lib/googlecloudsdk/command_lib/util/apis/arg_utils.pyr   *   s    r   c                           e Zd ZdZ fddZ  ZS )UnknownFieldErrorz>The referenced field could not be found in the message object.c                    s6   t t| d|t|ddd | D  d S )Nz<Field [{}] not found in message [{}]. Available fields: [{}], c                 s   s    | ]}|j V  qd S Nname).0fr   r   r   	<genexpr>6   s    z-UnknownFieldError.__init__.<locals>.<genexpr>)superr   __init__format_GetFullClassNamejoin
all_fields)self
field_namemessage	__class__r   r   r   2   s   
zUnknownFieldError.__init__r   r   r   r   r   __classcell__r   r   r'   r   r   /       r   c                 C   s2   t | trd| j| jS dt| jt| jS )Nz{}.{})
isinstancetyper    r   r   )objr   r   r   r!   9   s   
r!   c                       r   )InvalidFieldPathErrorzCThe referenced field path could not be found in the message object.c                    s"   t t| d|t|| d S )Nz7Invalid field path [{}] for message [{}]. Details: [{}])r   r/   r   r    r!   )r$   
field_pathr&   reasonr'   r   r   r   B   s   
zInvalidFieldPathError.__init__r)   r   r   r'   r   r/   ?   r+   r/   c                       r   )ArgumentGenerationErrorzGGeneric error when we can't auto generate an argument for an api field.c                    s   t t| d|| d S )Nz.Failed to generate argument for field [{}]: {})r   r2   r   r    )r$   r%   r1   r'   r   r   r   K   s   
z ArgumentGenerationError.__init__r)   r   r   r'   r   r2   H   r+   r2   c                 C   s6   | d}|dd D ]}t| |j} qt| |d S )a  Extract the field object from the message using a dotted field path.

  If the field does not exist, an error is logged.

  Args:
    message: The apitools message to dig into.
    field_path: str, The dotted path of attributes and sub-attributes.

  Returns:
    The Field object.
  .N)split	_GetFieldr-   )r&   r0   fieldsr   r   r   r   GetFieldFromMessageQ   s   
r8   c           	   
   C   s0  | }| d}t|D ]\}}td|}|r"| \}}t|}nd}z| |}W n ty;   t||t	|| w |rK|j
sJt||d|n|j
r_|t|d k r_t||d|t| |} | rt|rt|t| k rr| | nd} | s|t|d k rt|tjr| } qt||d||jjq| S )ac  Extract the value of the field given a dotted field path.

  If the field_path does not exist, an error is logged.

  Args:
    message: The apitools message to dig into.
    field_path: str, The dotted path of attributes and sub-attributes.

  Raises:
    InvalidFieldPathError: When the path is invalid.

  Returns:
    The value or if not set, None.
  r3   z(.+)\[(\d+)\]$Nz5Index cannot be specified for non-repeated field [{}]   z3Index needs to be specified for repeated field [{}]z'[{}] is not a valid field on field [{}])r5   	enumeraterematchgroupsintfield_by_nameKeyErrorr/   r   repeatedr    lengetattrr,   r   MessageFieldr-   r   )	r&   r0   root_messager7   ir   index_foundindexfieldr   r   r   GetFieldValueFromMessagec   sP   



rJ   c                 C   s   |d ur
t | |S d S r   )r   PyValueToMessage)
field_typevaluer   r   r   EncodeToMessage   s   rN   c           
      C   s   | d}|dd D ])}t| |}t| |j}|s,t| | }|r&|g}t| || |r2|d n|} qt| |d j}t|trGt||}t|t	rft
|D ]\}}	t|tret|	|set||	||< qPt| |d | dS )zSets the given field in the message object.

  Args:
    message: A constructed apitools message object to inject the value into.
    field_path: str, The dotted path of attributes and sub-attributes.
    value: The value to set.
  r3   Nr4   r   )r5   rC   r6   rA   r-   setattrr,   dictrN   listr:   )
r&   r0   rM   r7   r   sub_messageis_repeatedrL   rF   itemr   r   r   SetFieldInMessage   s&   




rU   c                 C   sP   | sdS | }| d}|dd D ]}t||d}|s dS q||d  dS )zResets the given field in the message object.

  Args:
    message: A constructed apitools message object to inject the value into.
    field_path: str, The dotted path of attributes and sub-attributes.
  Nr3   r4   )r5   rC   reset)r&   r0   rR   r7   r   r   r   r   ResetFieldInMessage   s   
rW   c                 C   s   |  dd S )zGets the child field name from the api field.

  If api field path is multiple levels deep, return the last field name.
  i.e. 'x.y.z' would return 'z'

  Args:
    api_field: str, full api field path

  Returns:
    str, child api field
  r3   r4   )
rpartition)	api_fieldr   r   r   GetChildFieldName   s   rZ   c                 C   s&   z|  |W S  ty   t|| w r   )r?   r@   r   )r&   r%   r   r   r   r6      s
   
r6   c                   @   s    e Zd ZdZdZdZdZdZdS )	FieldTypemapr&   rI   json
json_valueN)r   r   r   MAPMESSAGEFIELDJSON
JSON_VALUEr   r   r   r   r[      s    r[   additionalPropertiesc                 C   s2   | j tkr| S zt| jtW S  ty   Y d S w r   )r   ADDITIONAL_PROPSr8   r-   r   rI   r   r   r   _GetAdditionalPropsField   s   
rg   c                 C   s   | j tjkS r   )r-   r   	JsonValuerf   r   r   r   _IsJSONValueType  s   ri   c                 C   st   t | tjs	tjS t| }|ot |tjo|j}|r t|jdnd}|r+t	|r+tj
S |r0tjS t	| r7tjS tjS )zDetermines whether the apitools field is a map, message, or field.

  Args:
    field: messages.Field, apitools field instance

  Returns:
    FieldType based on the apitools field type and the type of fields
      it contains.
  rM   N)r,   r   rD   r[   ra   rg   rA   r8   r-   ri   rb   r_   rc   r`   )rI   additional_props_fieldis_mapvalue_fieldr   r   r   GetFieldType  s&   

rm   )project	projectId
projectsIdFc                 C   sZ   | dr|dd }|dd}t| |d}|s|r| }|s+|r+t|dd  }|S )z+Gets the given argument from the namespace.--   N-_c                   S   s   d S r   r   r   r   r   r   <lambda>6      z"GetFromNamespace.<locals>.<lambda>)
startswithreplacerC   DEFAULT_PARAMSget)	namespacearg_namefallbackuse_defaultsnormalized_arg_namerM   r   r   r   GetFromNamespace-  s   
r   c                   @       e Zd ZdZdd Zdd ZdS )FileTypez<An interface for custom type generators derived from a file.c                 C      dS zAGenerates an argparse type function to use to parse the argument.Nr   r$   rI   r   r   r   GenerateType=  rv   zFileType.GenerateTypec                 C   r   z-The argparse action to use for this argument.storer   r$   r   r   r   Action@     zFileType.ActionNr   r   r   r   r   r   r   r   r   r   r   :      r   c                   @   r   )ArgJSONTypez?An interface for custom type generators for JSON (struct type).c                 C   r   r   r   r   r   r   r   r   H  rv   zArgJSONType.GenerateTypec                 C   r   r   r   r$   unused_repeatedr   r   r   r   K  r   zArgJSONType.ActionNr   r   r   r   r   r   E  r   r   c                   @   r   )ArgObjectTypezAn interface for custom type generators that bind directly to a message.

  Like ArgDict, ArgObject type can only be generated one we know the type
  of the message.
  c                 C   r   z{Generates an argparse type function to use to parse the argument.

    Args:
      field: The apitools field instance.
    Nr   r   r   r   r   r   W  rv   zArgObjectType.GenerateTypec                 C   r   )aO  The argparse action to use for this argument.

    'store' is the default action, but sometimes something like 'append' might
    be required to allow the argument to be repeated and all values collected.

    Args:
      unused_repeated: whether or not the message is repeated

    Returns:
      str, The argparse action to use.
    r   r   r   r   r   r   r   ^  s   zArgObjectType.ActionNr   r   r   r   r   r   P  s    r   c                   @   r   )RepeatedMessageBindableTypea  An interface for custom type generators that bind directly to a message.

  An argparse type function converts the parsed string into an object. Some
  types (like ArgDicts) can only be generated once we know what message it will
  be bound to (because the spec of the ArgDict depends on the fields and types
  in the message. This interface allows encapsulating the logic to generate a
  type function at the point when the message it is being bound to is known.
  c                 C   r   r   r   r   r   r   r   r   w  rv   z(RepeatedMessageBindableType.GenerateTypec                 C   r   )a  The argparse action to use for this argument.

    'store' is the default action, but sometimes something like 'append' might
    be required to allow the argument to be repeated and all values collected.

    Returns:
      str, The argparse action to use.
    r   r   r   r   r   r   r   ~  s   	z"RepeatedMessageBindableType.ActionNr   r   r   r   r   r   m  s    	r   c                 C   sx   | r| j nd }d }|jd ur(dd |jD }t| r |}|S t| }|S |tjjkr:dd t| j	
 D }|S )Nc                 S   s   i | ]}|j |jqS r   )	arg_value	help_textr   cr   r   r   
<dictcomp>      z#GenerateChoices.<locals>.<dictcomp>c                 S      g | ]}t |qS r   EnumNameToChoicer   r   r   r   r   
<listcomp>      z#GenerateChoices.<locals>.<listcomp>)variantchoicesanyvaluessortedkeysr   VariantENUMr-   names)rI   
attributesr   r   
choice_mapr   r   r   GenerateChoices  s   

r   c                 C   s&   | j d urdd | j D }|r|S d S )Nc                 S   s   g | ]}|j r|jqS r   )hiddenr   r   r   r   r   r         z)GenerateHiddenChoices.<locals>.<listcomp>r   )r   hidden_choicesr   r   r   GenerateHiddenChoices  s
   
r   
store_truec                 C   s   | t kp| tjkS r   )
STORE_TRUEr   StoreTrueFalseAction)actionr   r   r   _IsStoreBoolAction  s   r   Tc           
      C   s  |j rt|j tr|j | }n| r| jnd}|j pt|d}|j}|tkr-|r-|s-t	}d}| o8| j
o8|j
du}t|tsCt|tr`|rRt| jdt |j||| }|| }||fS |r|rt|t}t|tj}	|ss|	r|rt| jdt |j||r| }|| }||fS |	s||krtj|t| |t|d}||fS t|trt| jdt |j||krt| jd|||fS )a-  Generates the type and action for a flag.

  Translates the yaml type (or deault apitools type) to python type. If the
  type is for a repeated field, then a function that turns the input into an
  apitools message is returned.

  Args:
    field: apitools field object flag is associated with
    attributes: yaml_arg_schema.Argument, data about flag being generated
    fix_bools: bool, whether to update flags to store_true action

  Raises:
    ArgumentGenerationError: user cannot specify action for repeated field
    ArgumentGenerationError: cannot use a dictionary on a non-repeating field
    ArgumentGenerationError: append action can only be used for repeated fields

  Returns:
    (str) -> Any, a type or function that returns input into correct type
    action, flag action used with a given type
  NappendFzJType {0} cannot be used with a custom action. Remove action {1} from spec.)element_typer   r   z-Type {0} can only be used on repeated fields.z6{0} custom action can only be used on repeated fields.)r-   r,   r   r   r   TYPESrz   r   boolr   rA   r   r   r2   r   r    r   r   r   r   ArgListr   r   )
rI   r   	fix_bools	flag_typer   r   append_actionrA   is_repeatable_messageis_arg_listr   r   r   GenerateFlagType  sf   

 



r   c                 C   sL   | r| }nt |tjrd}nt |tjr|}nd}|r$t|ddS dS )zGets the metavar for specific flag.

  Args:
    specified_metavar: str, metavar that is specified by user.
    flag_type: (str)->None, type function of the flag.
    flag_name: str, name of the flag

  Returns:
    str | None, the flag's metavar
  Nrs   rt   )r,   r   ArgDictr   r   ConvertToAngrySnakeCaserx   )specified_metavarr   	flag_namemetavarr   r   r   
GetMetavar  s   r   c                 C   s  t | ||\}}t|tjrd}d}n	t| |}t|}| r+|s+|s+|js+t| jd|j	}t
j|jr5|nd| |js=|nd|pAd|j|j|jd}	|jtkrU|j|	jd< t|sxt|j||}
|
rg|
|	jd< ||	jd< ||	jd	< |rx||	jd
< |js|j|	jd< |	S )a&  Generates a flag for a single field in a message.

  Args:
    field: The apitools field object.
    attributes: yaml_arg_schema.Argument, The attributes to use to
      generate the arg.
    fix_bools: True to generate boolean flags as switches that take a value or
      False to just generate them as regular string flags.
    category: The help category to put the flag in.

  Raises:
    ArgumentGenerationError: When an argument could not be generated from the
      API field.

  Returns:
    calliope.base.Argument, The generated argument.
  NzqThe field is of an unknown type. You can specify a type function or a processor to manually handle this argument.rq   r   )categoryr   	completerhelpr   defaultr   r-   r   r   required)r   r,   r   r   r   r   	processorr2   r   r|   r	   Argumentis_positionalr   r   r   r   UNSPECIFIEDkwargsr   r   r   r   )rI   r   r   r   r   r   r   r   r   argr   r   r   r   GenerateFlag  s@   





r   c                    s   | j o|du}|r||}nMd r=  | jtjjkr#| j }ng }t| 	  |r8 fdd|D }nt
 |}| jtjjkr[| j|rTfdd|D }nt|d}| j rh|sht|tsh|g}|S )a@  Coverts the parsed value into something to insert into a request message.

  If a processor is registered, that is called on the value.
  If a choices mapping was provided, each value is mapped back into its original
  value.
  If the field is an enum, the value will be looked up by name and the Enum type
  constructed.

  Args:
    field: The apitools field object.
    value: The parsed value. This must be a scalar for scalar fields and a list
      for repeated fields.
    repeated: bool, Set to False if this arg was forced to be singular even
      though the API field it corresponds to is repeated.
    processor: A function to process the value before putting it into the
      message.
    choices: {str: str} A mapping of argument value, to enum API enum value.

  Returns:
    The value to insert into the message.
  FNc                    s   g | ]}t  |qS r   )
_MapChoicer   vr   r   r   r   s  r   z ConvertValue.<locals>.<listcomp>c                    s   g | ]	}t | d qS )valid_choices)ChoiceToEnumr   )tr   r   r   r   y  s    r   )rA   r   r   r   r   r   r-   r   CheckValidEnumNamesr   r   r   r,   rQ   )rI   rM   rA   r   r   arg_repeated	api_namesr   )r   r   r   r   ConvertValueO  s*   

r   c                 C   s$   |d ur|d |  }n| }t |S )Nrs   )format_utilFlagNameFormat)r|   flag_prefixr   r   r   r   GetFlagName  s   
r   c                 C   sF   g }t | D ]\}}|t|ks|| |kr |S |||  q|S )z0Gets the long common sub list between two lists.)r:   rB   r   )longest_arrarrnew_arrrF   longest_substr_segr   r   r   _GetCommonPrefix  s   r   c                 C   sB   | sdS | d  d}| D ]}| d}t||}qd|p dS )a<  Gets shared parent of api_fields.

  For a list of fields, find the common parent between them or None.
  For example, ['a.b.c', 'a.b.d'] would return 'a.b'

  Args:
    api_fields: [list], list of api fields that we need to find parent

  Returns:
    str | None, shared common parent or None if one is not found
  Nr   r3   )r5   r   r"   )
api_fieldslongest_parentrI   substrr   r   r   GetSharedParent  s   
r   c                 C   s   |rt |d nd}g }| D ]7}|r||std||||d d}|o-|d }|r:|r:d||f}n|p=|}|rE|| q|S )a  Gets first child for api_fields.

  For a list of fields, supply the full api_field up through the first child.
  For example:
      ['a.b.c', 'a.b.d.e.f'] with shared parent 'a.b'
      returns children ['a.b.c', 'a.b.d']

  Args:
    api_fields: [str], list of api fields to get children from
    shared_parent: str | None, the shared parent between all api fields

  Returns:
    [str], list of the children api_fields
  r9   r   z*Invalid parent: {} does not start with {}.Nr3   )rB   rw   
ValueErrorr    r5   r"   r   )r   shared_parentstart_indexchild_fieldsrY   childrenfirst_childrI   r   r   r   _GetFirstChildFields  s    
r   c                 C   s   | D ]
}| |r dS qdS )a  Get api fields of arguments when at least one is specified.

  Args:
    specified_fields: List[str], list of api fields that have been specified.
    message_field: str, message field we are determining if specified

  Returns:
    bool, whether the message field is specified.
  TF)rw   )specified_fieldsmessage_fieldspecified_fieldr   r   r   _IsMessageFieldSpecified  s
   

r   c                 C   s(   g }| D ]}| |r||j q|S )aM  Get api fields of arguments when at least arg is specified in namespace.

  Args:
    arguments: List[yaml_arg_schema.YAMLArgument], list of arguments we want
      to see if they are specified.
    namespace: The parsed command line argument namespace.

  Returns:
    List[str] of api_fields that are specified in the namespace.
  )IsApiFieldSpecifiedextendr   )	argumentsr{   r   r   r   r   r   _GetSpecifiedApiFieldsInGroup  s   
r   c                 C   sR   |j r||s
dS t|j|jd}t|j|}|D ]}t||s&t| | qdS )aJ  Clears message fields associated with this mutex ArgGroup.

  Clearing fields is necessary when using read_modify_update. This prevents
  more than one field in a mutex group from being sent in a request message.
  Apitools does not contain information on which fields are mutually exclusive.
  Therefore, we use the api_fields in the argument group to determine which
  fields should be mutually exclusive.

  Args:
    message: The api message that needs to have fields cleared
    namespace: The parsed command line argument namespace.
    arg_group: yaml_arg_schema.ArgGroup, arg
  N)r   )	mutexr   r   r   parent_api_fieldr   r   r   rW   )r&   r{   	arg_groupfirst_child_fieldsr   rY   r   r   r   ClearUnspecifiedMutexFields  s   

r   c                 C   s    t |tjr
| }| ||S r   )r,   sixstring_typeslowerrz   )r   rM   r   r   r   r     s   r   c                 C   s0   t | tr|r	| S | r| d S d S |r| gS | S )Nr   )r,   rQ   )r   pluralr   r   r   
_ListValue  s
   
r  c                 C   s:   g }g }| D ]}| |j|d | |  q||fS )N)parent_collection)r   ParentName)refsr  parentsr   refr   r   r   _ParseParents(  s   
r
  c                 C   s    |r|   n|  }t| ||S r   )RelativeNamer  rC   )r	  pdefault_relative_namedefault_valr   r   r   	_GetParam2  s   r  c                    s   |pi }|  }d}t| tsd}| g} |r6|r6|r6|jj|jjkr6t| |jj\} }t||t	|| d}|r=|r=|j
ng }	|	D ] | g }
|
sU fdd| D }
t| t	|
| qA| D ]\}}t||t	|| qcdS )am  Set fields in message corresponding to a resource.

  Args:
    refs: googlecloudsdk.core.resources.Resource or list, the resource
      reference.
    method: the API method.
    message: apitools Message object.
    message_resource_map: {str: str}, A mapping of API method parameter name to
      resource ref attribute, if any
    request_id_field: str, the name that the ID of the resource arg takes if the
      API method params and the resource params don't match.
    use_relative_name: Used ref.RelativeName() if True, otherwise ref.Name().
    is_primary_resource: Determines if we should use method.params.
  TFc                    s   g | ]}t | qS r   )r  )r   r	  r  use_relative_namer   r   r   a  r   z,ParseResourceIntoMessage.<locals>.<listcomp>N)copyr,   rQ   resource_argument_collectiondetailed_paramsrequest_collectionr
  	full_namerU   r  paramspopitems)r  methodr&   message_resource_maprequest_id_fieldr  is_primary_resourcer  r   r  r   message_field_name	ref_paramr   r  r   ParseResourceIntoMessage7  s0   
r   c                 C   s<   |pi }t |D ]\}}t| |}t| |t|| q	dS )zSet fields in message corresponding to a dict of static field values.

  Args:
    message: the Apitools message.
    static_fields: dict of fields to values.
  N)r   	iteritemsr8   rU   r   )r&   static_fieldsr0   rM   rI   r   r   r   ParseStaticFieldsIntoMessagei  s   
r#  c              	   C   s   t |t | kr
|S |j}| |j}|jt |krA| }| D ]}z|jt |kr6|d|j 7 }W  nW q" ty@   Y q"w t| || | S )a;  Sets fields in message based on an existing message.

  This function is used for get-modify-update pattern. The request type of
  update requests would be either the same as the response type of get requests
  or one field inside the request would be the same as the get response.

  For example:
  1) update.request_type_name = ServiceAccount
     get.response_type_name = ServiceAccount
  2) update.request_type_name = updateInstanceRequest
     updateInstanceRequest.instance = Instance
     get.response_type_name = Instance

  If the existing message has the same type as the message to be sent for the
  request, then return the existing message instead. If they are different, find
  the field in the message which has the same type as existing_message, then
  assign exsiting message to that field.

  Args:
    message: the apitools message to construct a new request.
    existing_message: the exsting apitools message returned from server.
    method: APIMethod, the method to generate request for.

  Returns:
    A modified apitools message to be send to the method.
  r3   )r-   request_fieldr?   message_typer#   r   AttributeErrorrU   )r&   existing_messager  r0   rI   nested_messagenested_fieldr   r   r   ParseExistingMessageIntoMessagew  s"   r*  c                    s:    r fdd|D }ng }|rt dd|dS )zDEnsures the api_name given in the spec matches a value from the API.c                    s*   g | ]}| v st t| v s|qS r   )ChoiceToEnumNamer   	text_typer   r   r   r   r     s    
z'CheckValidEnumNames.<locals>.<listcomp>z {} is/are not valid enum values.r   N)r   ArgumentTypeErrorr    r"   )r   choices_valuesbad_choicesr   r-  r   r     s   r   choicec                 C   st   | du rdS t | }|pdd | D }z||W S  ty9   tdj|t|ddd t	|D dw )	z6Converts the typed choice into an apitools Enum value.Nc                 S   r   r   r   r   nr   r   r   r     r   z ChoiceToEnum.<locals>.<listcomp>z;Invalid {item}: {selection}. Valid choices are: [{values}].r   c                 s   s    | ]}|V  qd S r   r   r   r   r   r   r     s    zChoiceToEnum.<locals>.<genexpr>)rT   	selectionr   )
r+  r   lookup_by_namer@   r   r.  r    r   r"   r   )r1  	enum_type	item_typer   r   r   r   r   r     s"   r   c                 C      |  dd S )zDConverts a typeable choice to the string representation of the Enum.rs   rt   )rx   upper)r1  r   r   r   r+       r+  c                 C   r8  )z:Converts the name of an Enum value into a typeable choice.rt   rs   )rx   r  r   r   r   r   r     r:  r   Fieldsc                 C   s   i }d}t d|| jpdt j}|s|S | j| d  D ]/}t d|}|r:|d}|d	 ||< q!|rP|	 }|rP|
|d}|d | ||< q!|S )a6  Gets the help text for the fields in the request message.

  Args:
    message: The apitools message.
    section: str, The section to extract help data from. Fields is the default,
      may also be Values to extract enum data, for example.

  Returns:
    {str: str}, A mapping of field name to help text.
  Nz
^\s+{}:.*$ z^\s+(\w+): (.*)$r9   rr    )r;   searchr    r   	MULTILINEend
splitlinesr<   groupstriprz   )r&   sectionfield_helpscurrent_fieldr<   line	to_appendcurrent_textr   r   r   FieldHelpDocs  s&   
rJ  c                    s   |du rg }| |v ri S | |  t| }i }|  D ]O}d||ji}|j|d< |jtjj	krE|j
j|d< t|j
|d}|rD||d< n |j|d< |jtjjkret|j
d  fdd	|j
 D |d
< |||j< q|  |S )a   Gets the recursive representation of a message as a dictionary.

  Args:
    message: The apitools message.
    definitions: A list of message definitions already encountered.

  Returns:
    {str: object}, A recursive mapping of field name to its data.
  NdescriptionrA   r-   )definitionsr7   Valuesc                    s   i | ]}|  |qS r   )rz   r2  	enum_helpr   r   r   1  s    z+GetRecursiveMessageSpec.<locals>.<dictcomp>r   )r   rJ  r#   rz   r   rA   r   r   r   r`   r-   r   GetRecursiveMessageSpecr   r   r  )r&   rL  rE  datarI   
field_datar7   r   rN  r   rP    s2   





rP  c                 C   s   | o|  dp| dS )z@Determines if the given field is output only based on help text.z[Output Only]z@OutputOnly)rw   endswith)r   r   r   r   IsOutputField9  s   
rT  c                   @   s   e Zd ZdZdZ										dddZdd Zd	d
 Zdd Zdd Z	dd Z
edd Zedd Zedd Zedd Zedd Zedd Zedd ZdS ) ChoiceEnumMappera<  Utility class for mapping apitools Enum messages to argparse choice args.

  Dynamically builds a base.Argument from an enum message.
  Derives choice values from supplied enum or an optional custom_mapping dict
  (see below).

  Class Attributes:
   choices: Either a list of strings [str] specifying the commandline choice
       values or an ordered dict of choice value to choice help string mappings
       {str -> str}
   enum: underlying enum whos values map to supplied choices.
   choice_arg: base.Argument object
   choice_mappings: Mapping of argparse choice value strings to enum values.
   custom_mappings: Optional dict mapping enum values to a custom
     argparse choice value. To maintain compatiblity with base.ChoiceAgrument(),
     dict can be either:
     {str-> str} - Enum String value to choice argument value i.e.
     {'MY_MUCH_LONGER_ENUM_VALUE':'short-arg'}
     OR
     {str -> (str, str)} -  Enum string value to  tuple of
     (choice argument value, choice help string) i.e.
     {'MY_MUCH_LONGER_ENUM_VALUE':('short-arg','My short arg help text.')}
  zcustom_mappings must be a dict of enum string values to argparse argument choices. Choices must be either a string or a string tuple of (choice, choice_help_text): [{}]NFc                 C   s   t |tjstd||| _|| _|| _|| _|dur(t	|s(t
d||| _| j| _|   tj|| j||||||	|
|d
| _dS )a  Initialize ChoiceEnumMapper.

    Args:
      arg_name: str, The name of the argparse argument to create
      message_enum: apitools.Enum, the enum to map
      custom_mappings: See Above.
      help_str: string, pass through for base.Argument,
        see base.ChoiceArgument().
      required: boolean,string, pass through for base.Argument,
          see base.ChoiceArgument().
      action: string or argparse.Action, string, pass through for base.Argument,
          see base.ChoiceArgument().
      metavar: string,  string, pass through for base.Argument,
          see base.ChoiceArgument()..
      dest: string, string, pass through for base.Argument,
          see base.ChoiceArgument().
      default: string, string, pass through for base.Argument,
          see base.ChoiceArgument().
      hidden: boolean, pass through for base.Argument,
          see base.ChoiceArgument().
      hidden_choices: list, pass through for base.Argument,
          see base.ChoiceArgument().
      include_filter: callable, function of type string->bool used to filter
          enum values from message_enum that should be included in choices.
          If include_filter returns True for a particular enum value, it will be
          included otherwise it will be excluded. This is ignored if
          custom_mappings is specified.

    Raises:
      ValueError: If no enum is given, mappings are incomplete
      TypeError: If invalid values are passed for base.Argument or
       custom_mapping
    zInvalid Message Enum: [{}]Nz-include_filter must be callable received [{}])help_strr   r   r   destr   r   r   )r,   r   
_EnumClassr   r    	_arg_name_enum_custom_mappings_hidden_choicescallable	TypeError_filter_filtered_enum_ValidateAndParseMappingsr	   ChoiceArgumentr   _choice_arg)r$   r|   message_enumcustom_mappingsrV  r   r   r   rW  r   r   r   include_filterr   r   r   r   ]  s2   /zChoiceEnumMapper.__init__c              	      s6   j rNt j tst j j tdd  jD }t j  | }|r8t	dd
 j  d
|z   W n< tt	fyM      Y n.w t jr^ fdd jD  _dd  jD  _dd t jD  _t j  _ jrt j jst	d	d
 jd
 jd
S d
S )aV  Validates and parses choice to enum mappings.

    Validates and parses choice to enum mappings including any custom mappings.

    Raises:
      ValueError: custom_mappings does not contain correct number of mapped
        values.
      TypeError: custom_mappings is incorrect type or contains incorrect types
        for mapped values.
    c                 S   s   g | ]}|j qS r   r   r   xr   r   r   r     s    z>ChoiceEnumMapper._ValidateAndParseMappings.<locals>.<listcomp>zScustom_mappings [{}] may only contain mappings for enum values. invalid values:[{}]r   c                    s   g | ]
}  |jr|qS r   )r_  r   )r   er   r   r   r     s
    c                 S   s   i | ]}t |j|qS r   )r   r   rg  r   r   r   r     s    
z>ChoiceEnumMapper._ValidateAndParseMappings.<locals>.<dictcomp>c                 S   s   i | ]\}}|j |qS r   r   )r   rh  yr   r   r   r     s    z2hidden_choices [{}] must be subset of choices [{}]N)r[  r,   rP   r^  _CUSTOM_MAPPING_ERRORr    setrZ  r   r   r"   _ParseCustomMappingsFromTuples_ParseCustomMappingsFromStringsr]  r_  r`  _choice_to_enumr   r!  _enum_to_choicer   _choicesr\  
issuperset)r$   enum_stringsdiffr   r   r   ra    sN   


z*ChoiceEnumMapper._ValidateAndParseMappingsc                 C   s\   i | _ i | _t | _tt| jD ]\}\}}| 	|| j |< || j|< || j|< qdS )a   Parses choice to enum mappings from custom_mapping with tuples.

     Parses choice mappings from dict mapping Enum strings to a tuple of
     choice values and choice help {str -> (str, str)} mapping.

    Raises:
      TypeError - Custom choices are not not valid (str,str) tuples.
    N)
ro  rp  collectionsOrderedDictrq  r   r   r!  r[  rZ  )r$   enum_stringr1  rV  r   r   r   rm    s   	


z/ChoiceEnumMapper._ParseCustomMappingsFromTuplesc                 C   sl   i | _ g | _tt| jD ]!\}}t|tjs!t| j	
| j| || j |< | j| q| j| _dS )zParses choice to enum mappings from custom_mapping with strings.

     Parses choice mappings from dict mapping Enum strings to choice
     values {str -> str} mapping.

    Raises:
      TypeError - Custom choices are not strings
    N)ro  rq  r   r   r!  r[  r,   r   r^  rk  r    rZ  r   rp  )r$   rw  choice_stringr   r   r   rn    s   	
z0ChoiceEnumMapper._ParseCustomMappingsFromStringsc                 C   s   | j t|S )z2Converts an enum value to a choice argument value.)rp  rz   r   r,  )r$   
enum_valuer   r   r   GetChoiceForEnum  s   z!ChoiceEnumMapper.GetChoiceForEnumc                 C   s   | j |S )z1Converts a mapped string choice value to an enum.)ro  rz   )r$   choice_valuer   r   r   GetEnumForChoice  s   z!ChoiceEnumMapper.GetEnumForChoicec                 C      | j S r   )rq  r   r   r   r   r        zChoiceEnumMapper.choicesc                 C   r}  r   )rZ  r   r   r   r   enum	  r~  zChoiceEnumMapper.enumc                 C   r}  r   )r`  r   r   r   r   filtered_enum  r~  zChoiceEnumMapper.filtered_enumc                 C   r}  r   )rc  r   r   r   r   
choice_arg  r~  zChoiceEnumMapper.choice_argc                 C   r}  r   )ro  r   r   r   r   choice_mappings  r~  z ChoiceEnumMapper.choice_mappingsc                 C   r}  r   )r[  r   r   r   r   re    r~  z ChoiceEnumMapper.custom_mappingsc                 C   r}  r   )r_  r   r   r   r   rf    r~  zChoiceEnumMapper.include_filter)
NNFNNNNFNN)r   r   r   r   rk  r   ra  rm  rn  rz  r|  propertyr   r  r  r  r  re  rf  r   r   r   r   rU  @  sB    
H1





rU  )NF)T)TN)NNNr   )NNTF)r1  N)r;  )nr   
__future__r   r   r   ru  r  r;   apitools.base.protorpcliter   apitools.base.pyr   r   googlecloudsdk.callioper   r	    googlecloudsdk.calliope.conceptsr
   r   googlecloudsdk.corer   googlecloudsdk.core.resourcer   googlecloudsdk.core.utilr   r   objectr   	Exceptionr   r   r!   r/   r2   r8   rJ   rN   rU   rW   rZ   r6   Enumr[   re   rg   ri   rm   VALUEScorern   Getry   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r
  r  r   r#  r*  r   r   r+  r   PY2longr>   
_LONG_TYPEr   DOUBLEfloatFLOATINT64UINT64SINT64INT32UINT32SINT32STRINGr,  BOOLr   BYTESEncoder   r`   r   rJ  rP  rT  rU  r   r   r   r   <module>   s   
		<	
"



N

=
5	
&"	


24




$'