B
    `5                 @   s  d Z ddlZddlZddlZddlZddlZddlmZmZm	Z	m
Z
mZmZmZ ddlmZmZ ddlmZ ddlmZ ddlmZmZ ejZedeZerd	nd
ZdZeddddddZejejej ej!ej"fZ#ejejej fZ$e%e&Z'dd Z(dd Z)dd Z*G dd dZ+dS )a  Configuration management setup

Some terminology:
- name
  As written in config files.
- value
  Value associated with a name
- key
  Name combined with it's section (section.name)
- variant
  A single word describing where the configuration key-value pair came from
    N)AnyDictIterableListNewTypeOptionalTuple)ConfigurationError!ConfigurationFileCouldNotBeLoaded)appdirs)WINDOWS)
ensure_direnumKindzpip.inizpip.conf)versionhelpuserglobalsiteenvzenv-var)USERGLOBALSITEENVENV_VARc             C   s*   |   dd} | dr&| dd } | S )zFMake a name consistent regardless of source (environment or file)
    _-z--   N)lowerreplace
startswith)name r"   </tmp/pip-install-4tin_oll/pip/pip/_internal/configuration.py_normalize_name2   s    
r$   c             C   s&   d| krd | }t|| ddS )N.zbKey does not contain dot separated section and key. Perhaps you wanted to use 'global.{}' instead?   )formatr	   split)r!   error_messager"   r"   r#   _disassemble_key<   s
    r*   c              C   st   dd t dD } tjtjt}tjtjdt	r<dndt}tjt 
dt}tj| tj|gtj||giS )Nc             S   s   g | ]}t j|tqS r"   )ospathjoinCONFIG_BASENAME).0r,   r"   r"   r#   
<listcomp>J   s   z+get_configuration_files.<locals>.<listcomp>pip~z.pip)r   site_config_dirsr+   r,   r-   sysprefixr.   
expanduserr   user_config_dirkindsr   r   r   )Zglobal_config_filesZsite_config_filelegacy_config_filenew_config_filer"   r"   r#   get_configuration_filesG   s    

r;   c                   s   e Zd ZdZd- fdd	Zdd Zdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd Zedd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Z  ZS ).Configurationa  Handles management of configuration.

    Provides an interface to accessing and managing configuration files.

    This class converts provides an API that takes "section.key-name" style
    keys and stores the value associated with it as "key-name" under the
    section "section".

    This allows for a clean interface wherein the both the section and the
    key-name are preserved in an easy to manage form in the configuration files
    and the data stored is also nice.
    Nc                sj   t    |d k	r4|tkr4tddttt|| _|| _	dd t
D | _dd t
D | _g | _d S )Nz5Got invalid value for load_only - should be one of {}z, c             S   s   i | ]
}g |qS r"   r"   )r/   variantr"   r"   r#   
<dictcomp>z   s   z*Configuration.__init__.<locals>.<dictcomp>c             S   s   i | ]
}i |qS r"   r"   )r/   r=   r"   r"   r#   r>   }   s   )super__init__VALID_LOAD_ONLYr	   r'   r-   mapreprisolated	load_onlyOVERRIDE_ORDER_parsers_config_modified_parsers)selfrD   rE   )	__class__r"   r#   r@   l   s    


zConfiguration.__init__c             C   s   |    | js|   dS )zELoads configuration from configuration files and environment
        N)_load_config_filesrD   _load_environment_vars)rJ   r"   r"   r#   load   s    zConfiguration.loadc             C   s8   | j dk	stdy|  d S  tk
r2   dS X dS )z@Returns the file with highest priority in configuration
        Nz)Need to be specified a file to be editingr   )rE   AssertionError_get_parser_to_modify
IndexError)rJ   r"   r"   r#   get_file_to_edit   s    zConfiguration.get_file_to_editc             C   s
   | j  S )z`Returns key-value pairs like dict.items() representing the loaded
        configuration
        )_dictionaryitems)rJ   r"   r"   r#   rT      s    zConfiguration.itemsc             C   s2   y
| j | S  tk
r,   td| Y nX dS )z,Get a value from the configuration.
        zNo such key - N)rS   KeyErrorr	   )rJ   keyr"   r"   r#   	get_value   s    
zConfiguration.get_valuec             C   st   |    | jst|  \}}|dk	rTt|\}}||sF|| |||| || j| j |< | 	|| dS )z-Modify a value in the configuration.
        N)
_ensure_have_load_onlyrE   rO   rP   r*   has_sectionadd_sectionsetrH   _mark_as_modified)rJ   rV   valuefnameparsersectionr!   r"   r"   r#   	set_value   s    


zConfiguration.set_valuec             C   s   |    | jst|| j| j kr0td| |  \}}|dk	rt|\}}||rf|||sntd|	|s|
| | || | j| j |= dS )z#Unset a value in the configuration.zNo such key - Nz4Fatal Internal error [id=1]. Please report as a bug.)rX   rE   rO   rH   r	   rP   r*   rY   remove_optionrT   remove_sectionr\   )rJ   rV   r^   r_   r`   r!   r"   r"   r#   unset_value   s    



zConfiguration.unset_valuec          
   C   s\   |    xN| jD ]D\}}td| ttj| t|d}|	| W dQ R X qW dS )z*Save the current in-memory state.
        zWriting to %swN)
rX   rI   loggerinfor   r+   r,   dirnameopenwrite)rJ   r^   r_   fr"   r"   r#   save   s    zConfiguration.savec             C   s$   | j d krtdtd| j  d S )Nz'Needed a specific file to be modifying.z$Will be working with %s variant only)rE   r	   rf   debug)rJ   r"   r"   r#   rX      s    
z$Configuration._ensure_have_load_onlyc             C   s&   i }xt D ]}|| j|  q
W |S )z<A dictionary representing the loaded configuration.
        )rF   updaterH   )rJ   retvalr=   r"   r"   r#   rS      s    
zConfiguration._dictionaryc             C   s   t |  }|tj dd tjgkr4td dS xf| D ]Z\}}xP|D ]H}| j	dk	rt|| j	krttd|| qL| 
||}| j| ||f qLW q>W dS )z5Loads configuration from configuration files
        r   r&   zZSkipping loading configuration files due to environment's PIP_CONFIG_FILE being os.devnullNz Skipping file '%s' (variant: %s))dictiter_config_filesr8   r   r+   devnullrf   rm   rT   rE   
_load_filerG   append)rJ   config_filesr=   filesr^   r_   r"   r"   r#   rL      s    

z Configuration._load_config_filesc             C   sP   t d|| | |}x2| D ]&}||}| j| | || q"W |S )Nz'For variant '%s', will try loading '%s')rf   rm   _construct_parsersectionsrT   rH   rn   _normalized_keys)rJ   r=   r^   r_   r`   rT   r"   r"   r#   rs     s    

zConfiguration._load_filec          
   C   s   t  }tj|r|y|| W nX tk
rN   tdt	
d|dY n. t jk
rz } zt|dW d d }~X Y nX |S )Nzcontains invalid {} charactersF)reasonr^   )error)configparserRawConfigParserr+   r,   existsreadUnicodeDecodeErrorr
   r'   localegetpreferredencodingError)rJ   r^   r_   r{   r"   r"   r#   rw   "  s    
zConfiguration._construct_parserc             C   s"   | j tj | d|   dS )z7Loads configuration from environment variables
        z:env:N)rH   r8   r   rn   ry   get_environ_vars)rJ   r"   r"   r#   rM   9  s    z$Configuration._load_environment_varsc             C   s2   i }x(|D ] \}}|d t | }|||< q
W |S )zNormalizes items to construct a dictionary with normalized keys.

        This routine is where the names become keys and are made the same
        regardless of source - configuration files or environment.
        r%   )r$   )rJ   r`   rT   
normalizedr!   valrV   r"   r"   r#   ry   A  s
    zConfiguration._normalized_keysc             c   sH   xBt j D ]4\}}|dr|dd  }|tkr||fV  qW dS )z@Returns a generator with all environmental vars with prefix PIP_PIP_   N)r+   environrT   r    r   ENV_NAMES_IGNORED)rJ   rV   r   r!   r"   r"   r#   r   N  s
    
zConfiguration.get_environ_varsc             c   s   t jdd}|dk	r&tj|gfV  ntjg fV  t }tj|tj fV  | j ob|o`t j	| }|rztj
|tj
 fV  tj|tj fV  dS )zYields variant and configuration files associated with it.

        This should be treated like items of a dictionary.
        PIP_CONFIG_FILEN)r+   r   getr8   r   r;   r   rD   r,   r~   r   r   )rJ   config_fileru   should_load_user_configr"   r"   r#   rq   X  s    	zConfiguration.iter_config_filesc             C   s
   | j | S )z#Get values present in a config file)rH   )rJ   r=   r"   r"   r#   get_values_in_configw  s    z"Configuration.get_values_in_configc             C   s*   | j s
t| j| j  }|s"td|d S )Nz4Fatal Internal error [id=2]. Please report as a bug.)rE   rO   rG   r	   )rJ   parsersr"   r"   r#   rP   |  s    
z#Configuration._get_parser_to_modifyc             C   s"   ||f}|| j kr| j | d S )N)rI   rt   )rJ   r^   r_   file_parser_tupler"   r"   r#   r\     s    
zConfiguration._mark_as_modifiedc             C   s   | j j d| jdS )N())rK   __name__rS   )rJ   r"   r"   r#   __repr__  s    zConfiguration.__repr__)N)r   
__module____qualname____doc__r@   rN   rR   rT   rW   ra   rd   rl   rX   propertyrS   rL   rs   rw   rM   ry   r   rq   r   rP   r\   r   __classcell__r"   r"   )rK   r#   r<   ^   s,   	
r<   ),r   r|   r   loggingr+   r4   typingr   r   r   r   r   r   r   pip._internal.exceptionsr	   r
   pip._internal.utilsr   pip._internal.utils.compatr   pip._internal.utils.miscr   r   r}   strr   r.   r   r8   r   r   r   r   r   rF   rA   	getLoggerr   rf   r$   r*   r;   r<   r"   r"   r"   r#   <module>   s6   $


