B
    <[dp                 @   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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mZmZ G d	d
 d
eZG dd deZG dd deZG dd deZG dd dejZG dd deZdd ZG dd deZG dd de Z!G dd de!Z"G dd de"Z#G dd  d e"Z$G d!d" d"e!Z%e&d#Z'e&d$Z(G d%d& d&e%Z)G d'd( d(e%Z*G d)d* d*e*Z+d+d, Z,dS )-zA simple configuration system.    N)literal_eval)filefind)	py3compat)DEFAULT_ENCODING)	text_type)	HasTraitsListAnyc               @   s   e Zd ZdS )ConfigErrorN)__name__
__module____qualname__ r   r   6lib/python3.7/site-packages/traitlets/config/loader.pyr
      s   r
   c               @   s   e Zd ZdS )ConfigLoaderErrorN)r   r   r   r   r   r   r   r      s   r   c               @   s   e Zd ZdS )ConfigFileNotFoundN)r   r   r   r   r   r   r   r   !   s   r   c               @   s   e Zd ZdS )ArgumentErrorN)r   r   r   r   r   r   r   r   $   s   r   c                   s.   e Zd ZdZd fdd	Zejjje_  ZS )ArgumentParserz?Simple argparse subclass that prints help to stdout by default.Nc                s   |d krt j}tt| |S )N)sysstdoutsuperr   
print_help)selffile)	__class__r   r   r   4   s    zArgumentParser.print_help)N)r   r   r   __doc__r   argparser   __classcell__r   r   )r   r   r   1   s   r   c               @   sl   e Zd ZdZdZe Ze Zdd Zdd Z	dd Z
e Zd	d
 Ze Zdd Zdd Zdd Zdd ZdS )LazyConfigValuezProxy object for exposing methods on configurable containers
    
    Exposes:
    
    - append, extend, insert on lists
    - update on dicts
    - update, add on sets
    Nc             C   s   | j | d S )N)_extendappend)r   objr   r   r   r    O   s    zLazyConfigValue.appendc             C   s   | j | d S )N)r   extend)r   otherr   r   r   r"   R   s    zLazyConfigValue.extendc             C   s   || j dd< dS )z#like list.extend, but for the frontNr   )_prepend)r   r#   r   r   r   prependU   s    zLazyConfigValue.prependc             C   s&   t |tstd| j||f d S )NzAn integer is required)
isinstanceint	TypeError_insertsr    )r   indexr#   r   r   r   insertZ   s    
zLazyConfigValue.insertc             C   s4   | j d kr$t|tri | _ nt | _ | j | d S )N)_updater&   dictsetupdate)r   r#   r   r   r   r/   b   s
    

zLazyConfigValue.updatec             C   s   |  |h d S )N)r/   )r   r!   r   r   r   addk   s    zLazyConfigValue.addc             C   s   | j dk	r| j S t|}t|tr`x| jD ]\}}||| q,W | j|dd< || j	 n:t|t
r~| jr|| j nt|tr| jr|| j || _ |S )zvconstruct the value from the initial one
        
        after applying any insert / extend / update changes
        Nr   )_valuecopydeepcopyr&   listr)   r+   r$   r"   r   r-   r,   r/   r.   )r   initialvalueidxr!   r   r   r   	get_valuen   s     




zLazyConfigValue.get_valuec             C   sJ   i }| j r| j |d< | jr$| j|d< | jr6| j|d< n| jrF| j|d< |S )zreturn JSONable dict form of my data
        
        Currently update as dict or set, extend, prepend as lists, and inserts as list of tuples.
        r/   r"   r%   Zinserts)r,   r   r$   r)   )r   dr   r   r   to_dict   s    


zLazyConfigValue.to_dict)r   r   r   r   r1   r   r   r$   r    r"   r%   r)   r+   r	   r,   r/   r0   r8   r:   r   r   r   r   r   ?   s   	r   c             C   s.   | r&| d   | d kr&| ds&dS dS dS )z>Is a Config key a section name (does it start with a capital)?r   _TFN)upper
startswith)keyr   r   r   _is_section_key   s    "r?   c                   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Z fddZ	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 Zdd Z  ZS ) Configz1An attribute based dict that can do smart merges.c             O   s   t j| f|| |   d S )N)r-   __init___ensure_subconfig)r   argskwdsr   r   r   rA      s    zConfig.__init__c             C   sF   x@| D ]8}| | }t |rt|trt|tst| |t| qW dS )zensure that sub-dicts that should be Config objects are
        
        casts dicts that are under section keys to Config objects,
        which is necessary for constructing Config objects from dict literals.
        N)r?   r&   r-   r@   setattr)r   r>   r!   r   r   r   rB      s    


zConfig._ensure_subconfigc             C   s   |  | dS )z$deprecated alias, use Config.merge()N)merge)r   r#   r   r   r   _merge   s    zConfig._mergec             C   sj   i }xV|  D ]J\}}|| kr(|||< qt|trPt| | trP| | | q|||< qW | | dS )z)merge another config object into this oneN)itemsr&   r@   rF   r/   )r   r#   Z	to_updatekvr   r   r   rF      s    
zConfig.mergec             C   s~   i }xt| D ]l}||krq
| | }|| }xL|D ]D}||kr.|| || kr.| |i  d|| || f || |< q.W q
W |S )zCheck for collisions between two config objects.
        
        Returns a dict of the form {"Class": {"trait": "collision message"}}`,
        indicating which values have been ignored.
        
        An empty dict indicates no collisions.
        z%r ignored, using %r)
setdefault)r   r#   
collisionsZsectionZmineZtheirsr>   r   r   r   rL      s    

$zConfig.collisionsc                s@   d|kr0| dd\}}|| kr$dS || | kS tt| |S )N.   F)splitr   r@   __contains__)r   r>   firstZ	remainder)r   r   r   rP      s    zConfig.__contains__c             C   s   t |o|| kS )N)r?   )r   r>   r   r   r   _has_section   s    zConfig._has_sectionc             C   s   t | t| S )N)typer-   r2   )r   r   r   r   r2      s    zConfig.copyc             C   s   |   S )N)r2   )r   r   r   r   __copy__   s    zConfig.__copy__c             C   sf   t |  }xV|  D ]J\}}t|ttfr8t||}nt |ttt	t
hkrVt|}|||< qW |S )N)rS   rH   r&   r@   r   r2   r3   r-   r4   r.   tuple)r   memoZ
new_configr>   r6   r   r   r   __deepcopy__   s    

zConfig.__deepcopy__c             C   sl   yt | |S  tk
rf   t|r<t }t | || |S |ds^t }t | || |S tY nX d S )Nr;   )r-   __getitem__KeyErrorr?   r@   __setitem__r=   r   )r   r>   crJ   r   r   r   rX      s    
zConfig.__getitem__c             C   s4   t |r"t|ts"td||f t| || d S )NzOvalues whose keys begin with an uppercase char must be Config instances: %r, %r)r?   r&   r@   
ValueErrorr-   rZ   )r   r>   r6   r   r   r   rZ     s
    
zConfig.__setitem__c          
   C   sP   | drt| |S y
| |S  tk
rJ } zt|W d d }~X Y nX d S )N__)r=   r-   __getattr__rX   rY   AttributeError)r   r>   er   r   r   r^     s    

zConfig.__getattr__c          
   C   sX   | drt| ||S y| || W n* tk
rR } zt|W d d }~X Y nX d S )Nr]   )r=   r-   __setattr__rZ   rY   r_   )r   r>   r6   r`   r   r   r   ra     s    
zConfig.__setattr__c          
   C   sV   | drt| |S yt| | W n* tk
rP } zt|W d d }~X Y nX d S )Nr]   )r=   r-   __delattr____delitem__rY   r_   )r   r>   r`   r   r   r   rb   #  s    
zConfig.__delattr__)r   r   r   r   rA   rB   rG   rF   rL   rP   Zhas_keyrR   r2   rT   rW   rX   rZ   r^   ra   rb   r   r   r   )r   r   r@      s"   r@   c               @   s2   e Zd ZdZdd ZdddZdd Zd	d
 ZdS )ConfigLoadera1  A object for loading configurations from just about anywhere.

    The resulting configuration is packaged as a :class:`Config`.

    Notes
    -----
    A :class:`ConfigLoader` does one thing: load a config from a source
    (file, command line arguments) and returns the data as a :class:`Config` object.
    There are lots of things that :class:`ConfigLoader` does not do.  It does
    not implement complex logic for finding config files.  It does not handle
    default values or merge multiple configs.  These things need to be
    handled elsewhere.
    c             C   s   ddl m} | S )Nr   )
get_logger)Ztraitlets.logre   )r   re   r   r   r   _log_default@  s    zConfigLoader._log_defaultNc             C   s2   |    |dkr(|  | _| jd n|| _dS )ae  A base class for config loaders.

        log : instance of :class:`logging.Logger` to use.
              By default loger of :meth:`traitlets.config.application.Application.instance()`
              will be used

        Examples
        --------

        >>> cl = ConfigLoader()
        >>> config = cl.load_config()
        >>> config
        {}
        NzUsing default logger)clearrf   logdebug)r   rh   r   r   r   rA   D  s
    
zConfigLoader.__init__c             C   s   t  | _d S )N)r@   config)r   r   r   r   rg   Z  s    zConfigLoader.clearc             C   s   |    | jS )a  Load a config from somewhere, return a :class:`Config` instance.

        Usually, this will cause self.config to be set and then returned.
        However, in most cases, :meth:`ConfigLoader.clear` should be called
        to erase any previous state.
        )rg   rj   )r   r   r   r   load_config]  s    zConfigLoader.load_config)N)r   r   r   r   rf   rA   rg   rk   r   r   r   r   rd   1  s
   
rd   c                   s*   e Zd ZdZd fdd	Zdd Z  ZS )FileConfigLoaderzA base class for file based configurations.

    As we add more file based config loaders, the common logic should go
    here.
    Nc                s(   t t| jf | || _|| _d| _dS )a.  Build a config loader for a filename and path.

        Parameters
        ----------
        filename : str
            The file name of the config file.
        path : str, list, tuple
            The path to search for the config file on, or a sequence of
            paths to try in order.
         N)r   rl   rA   filenamepathfull_filename)r   rn   ro   kw)r   r   r   rA   o  s    zFileConfigLoader.__init__c             C   s   t | j| j| _dS )z,Try to find the file by searching the paths.N)r   rn   ro   rp   )r   r   r   r   
_find_file  s    zFileConfigLoader._find_file)N)r   r   r   r   rA   rr   r   r   r   )r   r   rl   h  s   rl   c               @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )JSONFileConfigLoadera  A JSON file loader for config

    Can also act as a context manager that rewrite the configuration file to disk on exit.

    Example::

        with JSONFileConfigLoader('myapp.json','/home/jupyter/configurations/') as c:
            c.MyNewConfigurable.new_value = 'Updated'

    c          
   C   s^   |    y|   W n. tk
rB } ztt|W dd}~X Y nX |  }| || _| jS )z=Load the config from a file and return it as a Config object.N)rg   rr   IOErrorr   str_read_file_as_dict_convert_to_configrj   )r   r`   Zdctr   r   r   rk     s    z JSONFileConfigLoader.load_configc          	   C   s    t | j}t|S Q R X d S )N)openrp   jsonload)r   fr   r   r   rv     s    z'JSONFileConfigLoader._read_file_as_dictc             C   s<   d|kr| d}nd}|dkr(t|S tdj|dd S )NversionrN   z.Unknown version of JSON config file: {version})r|   )popr@   r\   format)r   Z
dictionaryr|   r   r   r   rw     s    z'JSONFileConfigLoader._convert_to_configc             C   s   |    | jS )N)rk   rj   )r   r   r   r   	__enter__  s    zJSONFileConfigLoader.__enter__c          	   C   s>   d| j _tj| j dd}t| jd}|| W dQ R X dS )z
        Exit the context manager but do not handle any errors.

        In case of any error, we do not want to write the potentially broken
        configuration to disk.
        rN      )indentwN)rj   r|   ry   dumpsrx   rp   write)r   exc_type	exc_value	tracebackZjson_configr{   r   r   r   __exit__  s    zJSONFileConfigLoader.__exit__N)	r   r   r   r   rk   rv   rw   r   r   r   r   r   r   rs     s   
rs   c               @   s*   e Zd ZdZdd Zd	ddZdd ZdS )
PyFileConfigLoaderzA config loader for pure python files.

    This is responsible for locating a Python config file by filename and
    path, then executing it to construct a Config object.
    c          
   C   sR   |    y|   W n. tk
rB } ztt|W dd}~X Y nX |   | jS )z=Load the config from a file and return it as a Config object.N)rg   rr   rt   r   ru   rv   rj   )r   r`   r   r   r   rk     s    zPyFileConfigLoader.load_configNc             C   sL   |dkr| j }| ||}y| }W n tk
r:   Y nX | j| dS )z5Injected into config file namespace as load_subconfigN)ro   r   rk   r   rj   rF   )r   fnamero   loaderZ
sub_configr   r   r   load_subconfig  s    z!PyFileConfigLoader.load_subconfigc                sJ    fdd}t  j j| jd}t p,d} j|}t|| dS )z>Load the config file into self.config, with recursive loading.c                  s    j S )zKUnnecessary now, but a deprecation warning is more trouble than it's worth.)rj   r   )r   r   r   
get_config  s    z9PyFileConfigLoader._read_file_as_dict.<locals>.get_config)r[   r   r   __file__asciiN)	r-   rj   r   rp   r   getfilesystemencodingencoder   Zexecfile)r   r   	namespaceZfs_encodingZconf_filenamer   )r   r   rv     s    
z%PyFileConfigLoader._read_file_as_dict)N)r   r   r   r   rk   r   rv   r   r   r   r   r     s   

r   c               @   s    e Zd ZdZdd Zdd ZdS )CommandLineConfigLoaderzA config loader for command line arguments.

    As we add more command line based loaders, the common logic should go
    here.
    c          
   C   sH   t j|}yt|}W n tttfk
r6   |}Y nX td|  dS )a0  execute self.config.<lhs> = <rhs>
        
        * expands ~ with expanduser
        * tries to assign with literal_eval, otherwise assigns with just the string,
          allowing `--C.a=foobar` and `--C.a="foobar"` to be equivalent.  *Not*
          equivalent are `--C.a=4` and `--C.a='4'`.
        zself.config.%s = valueN)osro   
expanduserr   	NameErrorSyntaxErrorr\   exec)r   lhsrhsr6   r   r   r   _exec_config_str  s    
z(CommandLineConfigLoader._exec_config_strc             C   sF   t |ttfr6x2| D ]\}}| j| | qW ntd| dS )z=update self.config from a flag, which can be a dict or ConfigzInvalid flag: %rN)r&   r-   r@   rH   rj   r/   r(   )r   cfgZsecr[   r   r   r   
_load_flag  s    z"CommandLineConfigLoader._load_flagN)r   r   r   r   r   r   r   r   r   r   r     s   r   z#\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*z\-\-?\w+[\-\w]*$c                   sB   e Zd ZdZd fdd	Z fddZdddZdd	d
Z  ZS )KeyValueConfigLoaderzA config loader that loads key value pairs from the command line.

    This allows command line options to be gives in the following form::

        ipython --profile="foo" --InteractiveShell.autocall=False
    Nc                sF   t t| jf | |dkr(tjdd }|| _|p4i | _|p>i | _dS )a  Create a key value pair config loader.

        Parameters
        ----------
        argv : list
            A list that has the form of sys.argv[1:] which has unicode
            elements of the form u"key=value". If this is None (default),
            then sys.argv[1:] will be used.
        aliases : dict
            A dict of aliases for configurable traits.
            Keys are the short aliases, Values are the resolved trait.
            Of the form: `{'alias' : 'Configurable.trait'}`
        flags : dict
            A dict of flags, keyed by str name. Vaues can be Config objects,
            dicts, or "key=value" strings.  If Config or dict, when the flag
            is triggered, The flag is loaded as `self.config.update(m)`.

        Returns
        -------
        config : Config
            The resulting Config object.

        Examples
        --------

            >>> from traitlets.config.loader import KeyValueConfigLoader
            >>> cl = KeyValueConfigLoader()
            >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
            >>> sorted(d.items())
            [('A', {'name': 'brian'}), ('B', {'number': 0})]
        NrN   )r   r   rA   r   argvaliasesflags)r   r   r   r   rq   )r   r   r   rA   +  s     
zKeyValueConfigLoader.__init__c                s   t t|   g | _d S )N)r   r   rg   
extra_args)r   )r   r   r   rg   S  s    zKeyValueConfigLoader.clearc             C   s@   g }|dkrt }x*|D ]"}t|ts.||}|| qW |S )zGdecode argv if bytes, using stdin.encoding, falling back on default encN)r   r&   r   decoder    )r   r   encuargvargr   r   r   _decode_argvX  s    


z!KeyValueConfigLoader._decode_argvc          	   C   s  |    |dkr| j}|dkr$| j}|dkr2| j}| |}x>t|D ]0\}}|d}|dkr~| j||d d  P t	
|r|dd\}}	||kr|| }d|kr| jd| y| ||	 W n  tk
r   td| Y nX qHt
|r.||kr || \}
}| |
 ntd	| qH|drnd| }t	
|r`td
||f ntd| qH| j| qHW | jS )a  Parse the configuration and generate the Config object.

        After loading, any arguments that are not key-value or
        flags will be stored in self.extra_args - a list of
        unparsed command-line arguments.  This is used for
        arguments such as input files or subcommands.

        Parameters
        ----------
        argv : list, optional
            A list that has the form of sys.argv[1:] which has unicode
            elements of the form u"key=value". If this is None (default),
            then self.argv will be used.
        aliases : dict
            A dict of aliases for configurable traits.
            Keys are the short aliases, Values are the resolved trait.
            Of the form: `{'alias' : 'Configurable.trait'}`
        flags : dict
            A dict of flags, keyed by str name. Values can be Config objects
            or dicts.  When the flag is triggered, The config is loaded as
            `self.config.update(cfg)`.
        N-z--rN   =rM   z:Unrecognized alias: '%s', it will probably have no effect.zInvalid argument: '%s'zUnrecognized flag: '%s'z*Invalid argument: '%s', did you mean '%s'?)rg   r   r   r   r   	enumeratelstripr   r"   
kv_patternmatchrO   rh   Zwarningr   	Exceptionr   flag_patternr   r=   r    rj   )r   r   r   r   r   r7   rawitemr   r   r   helpZkvr   r   r   rk   e  sF    



z KeyValueConfigLoader.load_config)NNN)N)NNN)	r   r   r   r   rA   rg   r   rk   r   r   r   )r   r   r   #  s
   (
r   c                   sX   e Zd ZdZd fdd	ZdddZdd Zdd	d
ZdddZdd Z	dd Z
  ZS )ArgParseConfigLoaderzEA loader that uses the argparse module to load from the command line.Nc                s~   t t| j|d |   |dkr0tjdd }|| _|p<i | _|pFi | _|| _|	dd| _
ttjd}|| || _dS )az  Create a config loader for use with argparse.

        Parameters
        ----------

        argv : optional, list
          If given, used to read command-line arguments from, otherwise
          sys.argv[1:] is used.

        parser_args : tuple
          A tuple of positional arguments that will be passed to the
          constructor of :class:`argparse.ArgumentParser`.

        parser_kw : dict
          A tuple of keyword arguments that will be passed to the
          constructor of :class:`argparse.ArgumentParser`.

        Returns
        -------
        config : Config
            The resulting Config object.
        )rh   NrN   r|   )Zargument_default)r   r   rA   rg   r   r   r   r   parser_argsr}   r|   r-   r   ZSUPPRESSr/   	parser_kw)r   r   r   r   rh   r   r   kwargs)r   r   r   rA     s    


zArgParseConfigLoader.__init__c             C   sV   |    |dkr| j}|dkr$| j}|dkr2| j}| || | | |   | jS )aC  Parse command line arguments and return as a Config object.

        Parameters
        ----------

        args : optional, list
          If given, a list with the structure of sys.argv[1:] to parse
          arguments from. If not given, the instance's self.argv attribute
          (given at construction time) is used.N)rg   r   r   r   _create_parser_parse_argsrw   rj   )r   r   r   r   r   r   r   rk     s    

z ArgParseConfigLoader.load_configc             C   s   t | dr| jS g S d S )Nr   )hasattrr   )r   r   r   r   get_extra_args  s    
z#ArgParseConfigLoader.get_extra_argsc             C   s    t | j| j| _| || d S )N)r   r   r   parser_add_arguments)r   r   r   r   r   r   r     s    z#ArgParseConfigLoader._create_parserc             C   s   t dd S )Nz(subclasses must implement _add_arguments)NotImplementedError)r   r   r   r   r   r   r     s    z#ArgParseConfigLoader._add_argumentsc                s.   t   fdd|D }| j|\| _| _dS )zself.parser->self.parsed_datac                s   g | ]}t | qS r   )r   Zcast_unicode).0a)r   r   r   
<listcomp>  s    z4ArgParseConfigLoader._parse_args.<locals>.<listcomp>N)r   r   Zparse_known_argsparsed_datar   )r   rC   Zuargsr   )r   r   r     s    z ArgParseConfigLoader._parse_argsc             C   s4   x.t | j D ]\}}td| t t  qW dS )zself.parsed_data->self.configzself.config.%s = vN)varsr   rH   r   localsglobals)r   rI   rJ   r   r   r   rw     s    z'ArgParseConfigLoader._convert_to_config)NNNN)NNN)NN)NN)r   r   r   r   rA   rk   r   r   r   r   rw   r   r   r   )r   r   r     s   %


r   c               @   s"   e Zd ZdZdddZdd ZdS )KVArgParseConfigLoadera  A config loader that loads aliases and flags with argparse,
    but will use KVLoader for the rest.  This allows better parsing
    of common args, such as `ipython -c 'print 5'`, but still gets
    arbitrary config with `ipython --InteractiveShell.use_readline=False`Nc             C   s  i | _ |d kr| j}|d kr"| j}| jj}xb| D ]V\}}||krJd}nd }t|dkrv|d| d| t||d q4|d| t||d q4W xp| D ]d\}\}}|| jkr|| j | j| < qt|dkr|d| d| dd|d q|d| dd|d qW d S )	N?rN   r   z--)rS   destnargsZappend_const_flags)actionr   Zconst)alias_flagsr   r   r   add_argumentrH   lenr   )r   r   r   Zpaar>   r6   r   r   r   r   r   r     s(    
z%KVArgParseConfigLoader._add_argumentsc             C   s   d| j kr| j j}| j `ng }x@t| j  D ].\}}|dkrP|| j|  q.| || q.W x|D ]}| | qfW | jrt	| j
d}|| j | j|j |j| _dS )zJself.parsed_data->self.config, parse unrecognized extra args via KVLoader.r   N)rh   )r   r   r   rH   r    r   r   r   r   r   rh   rk   rj   rF   )r   ZsubcsrI   rJ   ZsubcZ
sub_parserr   r   r   rw   )  s    

z)KVArgParseConfigLoader._convert_to_config)NN)r   r   r   r   r   rw   r   r   r   r   r     s   
r   c          	   C   s\   t  }xP| D ]H}t||d}y| }W n  tk
r<   Y q    Y qX || qW |S )a  Load multiple Python config files, merging each of them in turn.

    Parameters
    ==========
    config_files : list of str
        List of config files names to load and merge into the config.
    path : unicode
        The full path to the location of the config files.
    )ro   )r@   r   rk   r   rF   )Zconfig_filesro   rj   Zcfr   Znext_configr   r   r   load_pyconfig_filesD  s    

r   )-r   r   r2   Zloggingr   rer   ry   Zastr   Zipython_genutils.pathr   Zipython_genutilsr   Zipython_genutils.encodingr   Zsixr   Ztraitlets.traitletsr   r   r	   r   r
   r   r   r   r   r   r?   r-   r@   objectrd   rl   rs   r   r   compiler   r   r   r   r   r   r   r   r   r   <module>   sD   W 781-

 W=