
ddc           @` s	  d  Z  d d l m Z m Z m Z m Z d d l Td 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 Z y d d l Z Wn e k
 r d d l Z n Xy d d l Z Wn e k
 r e Z n Xe 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$ Td d d d d g Z% d e j j& e	 j' e(  f d     YZ) d e) f d     YZ* d e) f d     YZ+ d e) f d     YZ, d e) f d     YZ- d S(   u   Loading and saving settings.i    (   t   absolute_importt   divisiont   print_functiont   unicode_literals(   t   *Ni   (   t	   constants(   t   utilsi   (   t   group(   t   settingsu   Sourceu   GimpShelfSourceu   GimpParasiteSourceu   PickleFileSourceu   JsonFileSourcet   Sourcec           B` s  e  Z d  Z d Z d Z d Z d   Z e d    Z d   Z	 d   Z
 d   Z d	   Z d
   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z  d   Z! d   Z" d    Z# d!   Z$ e% e d"   Z& e' j( d#    Z) e' j( d$    Z* e' j( d%    Z+ e' j( d&    Z, RS('   u  Abstract class for reading and writing settings to a source.
  
  Attributes:
  
  * `source_name` - A unique identifier to distinguish entries from different
    GIMP plug-ins or procedures.
  
  * `source_type` - If `'persistent'`, this indicates that the setting source
    should store settings permanently. If `'session'`, this indicates that the
    source should store settings within a single GIMP session (i.e. until the
    currently running GIMP instance is closed).
  u   ignore_loadu   ignore_savei   c         C` s   | |  _  | |  _ g  |  _ d  S(   N(   t   source_namet   source_typet   _settings_not_loaded(   t   selfR
   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyt   __init__F   s    		c         C` s   t  |  j  S(   u   List of all settings and groups that were not found in the data or their
    `setting_source` attribute is not `None` and does does not contain
    `source_type`.
    (   t   listR   (   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyt   settings_not_loadedL   s    c         C` sV   |  j    } | d k r9 t t d  j |  j    n  g  |  _ |  j | |  d S(   ue  Reads setting attributes from data and assigns them to existing settings
    specified in the `settings_or_groups` iterable, or creates settings within
    groups specified in `settings_or_groups`.
    
    If a setting value from the source is invalid, the setting will be reset to
    its default value.
    
    All settings that were not loaded in the source will be stored in the
    `settings_not_loaded` property. This property is reset on each call to
    `read()`.
    
    The following criteria determine whether a setting specified in
    `setting_or_groups` is not loaded:
    
    * The setting is not found in the source.
    
    * The setting or any of its parent groups contains 'ignore_load' in its
      `tags` attribute.
    
    * The setting does not contain `source_type` in its `setting_sources`
      attribute.
    
    Raises:
    
    * `SourceNotFoundError` - Could not find the source having the `source_name`
      attribute as its name.
    
    * `SourceInvalidFormatError` - Existing data in the source have an invalid
      format. This could happen if the source was edited manually.
    u#   Could not find setting source "{}".N(   t   read_data_from_sourcet   Nonet   SourceNotFoundErrort   _t   formatR
   R   t   _update_settings(   R   t   settings_or_groupst   data(    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyt   readT   s    	c         C` s   |  j  |  } x | D] } | j   } | | k r | | } t | t j  rs |  j | |  |  j | |  q t | t j  r |  j	 | |  |  j
 | | | |  q t d   q |  j j |  q Wd  S(   Nu?   settings_or_groups must contain only Setting or Group instances(   t   _create_data_dictt   get_patht
   isinstancet	   settings_t   Settingt    _check_if_setting_dict_has_valuet   _update_settingt   group_t   Groupt#   _check_if_setting_dict_has_settingst   _update_groupt	   TypeErrorR   t   append(   R   R   R   t	   data_dictt   setting_or_groupt   setting_patht   setting_dict(    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   |   s    
c   
      C` s'  t  j   } | | d  <g  } |  j |  x* t |  D] } | j d | g  f  q6 Wx | r"| j d  \ } } |  j |  |  j |  t	 j
 j | | d g  } | | | <d | k rY | j | d  | d } |  j |  x3 t |  D]" }	 | j d |	 t |  f  q WqY qY W| S(   Ni    u   nameu   settings(   t   collectionst   OrderedDictR   t   _check_if_is_listt   reversedt   insertt   popt   _check_if_is_dictt    _check_if_dict_has_required_keyst   utils_t   SETTING_PATH_SEPARATORt   joinR&   R   (
   R   R   R'   t   current_list_and_parentst   dict_t   current_dictt   parentst   keyt
   child_listt
   child_dict(    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR      s&    
	

'c   
      C` s&  |  j  |  s d  S|  j | |  } t   } |  j | | | |  } |  j | | |  } x | j   D] \ } }	 d |	 k r | | k r |  j | | |  |  j | | |	  q|  j |	 | |  qh d |	 k r| | k r |  j	 | | |  q|  j
 |	 | |  qh t d   qh Wd  S(   Nu   valueu   settingsum   Error while parsing data from a source: every dictionary must always contain either "value" or "settings" key(   t   _should_group_be_loadedt"   _get_matching_dicts_for_group_patht   sett   _get_matching_childrent   _filter_matching_dictst   itemst   _check_if_is_settingR    t   _add_setting_to_parent_groupt   _check_if_is_groupt   _add_group_to_parent_groupt   SourceInvalidFormatError(
   R   R   t
   group_dictt
   group_pathR'   t   matching_dictst   prefixes_to_ignoret   matching_childrent   pathR7   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR$      s(    	c         ` s#   t  j   f d   | j   D  S(   Nc         3` sH   |  ]> \ } } | d  k	 r | j    r |   k r | | f Vq d  S(   N(   R   t
   startswith(   t   .0RM   R7   (   RI   (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pys	   <genexpr>   s    	(   R+   R,   RB   (   R   R'   RI   (    (   RI   sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR>      s    c         ` s   t  j   } x | j d t  D] } | j     |  j | j k rS | j    n  t   f d   | D  ru q n  | |   <  | k r t	 | t
 j  r t |  d k r |  j j |  q q |  j j |  q q W| | | <| S(   Nt   include_groupsc         3` s   |  ] }   j  |  Vq d  S(   N(   RN   (   RO   t   prefix(   t
   child_path(    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pys	   <genexpr>   s    i    (   R+   R,   t   walkt   TrueR   t   _IGNORE_LOAD_TAGt   tagst   addt   anyR   R!   R"   t   lenR   R&   (   R   R   RI   RJ   RK   RL   t   child(    (   RR   sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR@      s    

c         ` s   t  j   } x} | j   D]o \   } |  j | j d g   k r\   | k r\ | j    n  t   f d   | D  r~ q n  | |   <q W| S(   Nu   tagsc         3` s   |  ] }   j  |  Vq d  S(   N(   RN   (   RO   RQ   (   RM   (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pys	   <genexpr>   s    (   R+   R,   RB   RU   t   getRW   RX   (   R   RJ   RL   RK   t   filtered_matching_dictsR7   (    (   RM   sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRA      s    'c         C` sM   |  j  |  s d  Sy | j | d  Wn t j k
 rH | j   n Xd  S(   Nu   value(   t   _should_setting_be_loadedt	   set_valueR   t   SettingValueErrort   reset(   R   t   settingR*   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR       s    c         C` sO   |  j  | j k r t S| j d  k	 rK |  j | j k rK |  j j |  t St S(   N(	   RU   RV   t   Falset   setting_sourcesR   R   R   R&   RT   (   R   Ra   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR]     s    !c         C` s   |  j  | j k S(   N(   RU   RV   (   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR=     s    c         C` s5   | j  d d   } | d  k	 r1 |  j | k r1 t St S(   Nu   setting_sources(   R[   R   R   Rb   RT   (   R   R7   Rc   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyt   _should_dict_be_loaded  s    c         C` s   |  j  |  s d  S| j t j d  d } | | k s> t  | | } t |  } | j d d   | j | g  | | d } d | k r |  j	 | |  n  | | | j
   <d  S(   Ni   i    u   valueu   name(   Rd   t   rsplitR3   R4   t   AssertionErrort   dictR0   R   RW   R    R   (   R   R7   RM   RL   t   parent_patht   parent_groupt   child_setting_dictt   child_setting(    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRD     s    
c         C` s   | j  t j d  d } | | k s+ t  | | } t |  } | j d  t j |   } | j | g  | | | j	   <d  S(   Ni   i    u   settings(
   Re   R3   R4   Rf   Rg   R0   R!   R"   RW   R   (   R   R7   RM   RL   Rh   Ri   t   child_group_kwargst   child_group(    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRF   5  s    
c         C` sB   |  j    } | d k r! g  } n  |  j | |  |  j |  d S(   u  Writes data representing settings specified in the `settings_or_groups`
    iterable.
    
    Settings in the source but not specified in `settings_or_groups` are kept
    intact.
    
    Some settings may not be saved. The following criteria determine whether a
    setting is not saved:
    
    * The setting or any of its parent groups contains 'ignore_save' in its
      `tags` attribute.
    
    * The setting does not contain `source_type` in its `setting_sources`
      attribute.
    
    Raises:
    
    * `SourceInvalidFormatError` - Existing data in the source have an invalid
      format. This could happen if the source was edited manually.
    N(   R   R   t   _update_datat   write_data_to_source(   R   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyt   writeH  s
    	c         C` s   x | D] } | } xe | j  D]Z } |  j | |  d } | d  k rm t d g  | j    } | j |  n  | d } q Wt | t j  r |  j	 | |  q t | t
 j  r |  j | |  q t d   q Wd  S(   Ni    R   u   settingsu?   settings_or_groups must contain only Setting or Group instances(   R9   t
   _find_dictR   Rg   t   to_dictR&   R   R   R   t   _setting_to_dataR!   R"   t   _group_to_dataR%   (   R   R   R   R(   t   current_listt   parentt   parent_dict(    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRn   e  s    c         C` ss   |  j  |  s d  S|  j | |  \ } } | d  k	 rS | j d |  j  | | <n | j | j d |  j   d  S(   NR   (   t   _should_setting_be_savedRq   R   Rr   R   R&   (   R   t
   group_listRa   R*   t   index(    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRs   {  s    c         C` s.  |  j  |  s d  S|  j | |  | | f g } x | r)| j d  \ } } t | t j  ru |  j | |  q5 t | t j  r|  j  |  s q5 n  |  j	 | |  d } | d  k r t d g  | j    } | j |  n  x= t |  D]  } | j d | | d f  q Wq5 t d   q5 Wd  S(   Ni    R   u   settingsu@   only Setting or Group instances are allowed as the first element(   t   _should_group_be_savedt   _clear_group_in_dataR0   R   R   R   Rs   R!   R"   Rq   R   Rg   Rr   R&   R.   R/   R%   (   R   Ry   R   t   settings_or_groups_and_dictsR(   t   parent_listt   current_group_dictt   child_setting_or_group(    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRt     s&    	c         C` s?   |  j  | j k r t S| j d  k	 r; |  j | j k r; t St S(   N(   t   _IGNORE_SAVE_TAGRV   Rb   Rc   R   R   RT   (   R   Ra   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRx     s
    !c         C` s   |  j  | j k S(   N(   R   RV   (   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR{     s    c         C` s9   |  j  | |  \ } } | d  k	 r5 g  | | d <n  d  S(   Nu   settings(   Rq   R   (   R   R   R~   t   group_in_parentRz   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR|     s    c         C` s   |  j  |  t | t j  r( d } n d } x\ t |  D]N \ } } |  j |  d | k r; | d | j k r; | | k r; | | f Sq; Wd S(   Nu   valueu   settingsu   name(   NN(   R-   R   R   R   t	   enumerateR1   t   nameR   (   R   t	   data_listR(   R:   t   iR7   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRq     s    	+c         C` sY   t  | t j  s4 t  | t j  s4 t  | t  rU t d j |  j |     n  d  S(   Nu6   Error while parsing data from a source: Not a list: {}(	   R   R+   t   Iterablet   typest   StringTypesRg   RG   R   t   _truncate_str(   R   t   list_(    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR-     s    c         C` s4   t  | t  s0 t d j |  j |     n  d  S(   Nu<   Error while parsing data from a source: Not a dictionary: {}(   R   Rg   RG   R   R   (   R   R7   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR1     s    c         C` s^   d | k r t  d   n  d | k r3 d | k sK d | k rZ d | k rZ t  d   n  d  S(   Nu   nameuW   Error while parsing data from a source: every dictionary must always contain "name" keyu   valueu   settingsum   Error while parsing data from a source: every dictionary must always contain either "value" or "settings" key(   RG   (   R   R7   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR2     s    c         C` s(   d | k r$ t  d j |    n  d  S(   Nu   valueue   Error while parsing data from a source: "value" key not found in dictionary representing setting "{}"(   RG   R   (   R   R*   R)   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    c         C` s(   d | k r$ t  d j |    n  d  S(   Nu   settingsun   Error while parsing data from a source: "settings" key not found in dictionary representing setting group "{}"(   RG   R   (   R   R*   R)   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR#     s    c         C` s.   t  | t j  s* t d j |    n  d  S(   Nu6   expected a Setting instance, found Group instead: "{}"(   R   R   R   RG   R   (   R   Ra   R)   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRC     s    c         C` s.   t  | t j  s* t d j |    n  d  S(   Nu6   expected a Group instance, found Setting instead: "{}"(   R   R!   R"   RG   R   (   R   R   RI   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRE     s    c         C` s3   t  |   } t |  | k r/ | |  d } n  | S(   Nu   ... (truncated)(   t   strRY   (   t   objt
   max_lengtht   str_(    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    c         C` s   d S(   u   Removes all settings from the source.
    
    Settings not belonging to `source_name` are kept intact.
    
    This method is useful if settings are renamed, since the old settings would
    not be removed and would thus lead to bloating the source.
    N(    (   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyt   clear  s    	c         C` s   d S(   u>   Returns `True` if the source contains data, `False` otherwise.N(    (   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyt   has_data
  s    c         C` s   d S(   u  Reads data representing settings from the source.
    
    Usually you do not need to call this method. Use `read()` instead which
    assigns values to existing settings or creates settings dynamically from the
    data.
    
    If the source does not exist, `None` is returned.
    
    Raises:
    
    * `SourceInvalidFormatError` - Data could not be read due to being corrupt.
    N(    (   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    c         C` s   d S(   uq  Writes data representing settings to the source.
    
    The entire setting source is overwritten by the specified data.
    Settings not specified thus will be removed.
    
    Usually you do not need to call this method. Use `write()` instead which
    creates an appropriate persistent representation of the settings that can
    later be loaded via `read()`.
    N(    (   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRo     s    (-   t   __name__t
   __module__t   __doc__RU   R   t/   _MAX_LENGTH_OF_OBJECT_AS_STRING_ON_ERROR_OUTPUTR   t   propertyR   R   R   R   R$   R>   R@   RA   R    R]   R=   Rd   RD   RF   Rp   Rn   Rs   Rt   Rx   R{   R|   Rq   R-   R1   R2   R   R#   RC   RE   t   staticmethodR   t   abct   abstractmethodR   R   R   Ro   (    (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR	   3   sP   		(		"	 						
																				t   GimpShelfSourcec           B` sG   e  Z d  Z d d  Z d   Z d   Z d   Z d   Z d   Z RS(   u   Class for reading and writing settings to the GIMP shelf.
  
  This class is appropriate to maintain settings within a single GIMP session
  as the GIMP shelf is reset when closing GIMP.
  u   sessionc         C` s   t    j | |  d  S(   N(   t   superR   (   R   R
   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   4  s    c         C` s   d  t j |  j   <d  S(   N(   R   t	   gimpshelft   shelft   _get_key(   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   7  s    c         C` s<   y t  j |  j    } Wn t k
 r- t SXt |  Sd  S(   N(   t   gimpt   get_dataR   t	   ExceptionRb   t   bool(   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   :  s
    c         C` sP   y t  j |  j   SWn4 t k
 r) d  St k
 rK t t d    n Xd  S(   Nu]   Settings for this plug-in may be corrupt.
To fix this, save the settings again or reset them.(   R   R   R   t   KeyErrorR   R   RG   R   (   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   B  s    c         C` s   | t  j |  j   <d  S(   N(   R   R   R   (   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRo   L  s    c         C` s   t  j |  j  S(   N(   t   pgutilst   safe_encode_gimpR
   (   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   O  s    (	   R   R   R   R   R   R   R   Ro   R   (    (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   -  s   			
	t   GimpParasiteSourcec           B` s>   e  Z d  Z d d  Z d   Z d   Z d   Z d   Z RS(   u   Class reading and writing settings to the `parasiterc` file maintained by
  GIMP.
  
  This class is useful as a persistent source (i.e. permanent storage) of
  settings.
  u
   persistentc         C` s2   t    j | |  t j j t j d  |  _ d  S(   Nu
   parasiterc(   R   R   t   osRM   R5   R   t	   directoryt   _parasite_filepath(   R   R
   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   [  s    c         C` s0   t  j |  j  d  k r d  St  j |  j  d  S(   N(   R   t   parasite_findR
   R   t   parasite_detach(   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   `  s    c         C` s   t  j |  j  d  k	 S(   N(   R   R   R
   R   (   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   f  s    c         C` sn   t  j |  j  } | d  k r" d  Sy t j | j  } Wn/ t k
 ri t t	 d  j
 |  j    n X| S(   Nu   Settings for this plug-in stored in "{}" may be corrupt. This could happen if the file was edited manually.
To fix this, save the settings again or reset them.(   R   R   R
   R   t   picklet   loadsR   R   RG   R   R   R   (   R   t   parasiteR   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   i  s    c         C` s/   t  j t  j |  j t j t j |    d  S(   N(   R   t   parasite_attacht   ParasiteR
   t	   gimpenumst   PARASITE_PERSISTENTR   t   dumps(   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRo   y  s    (   R   R   R   R   R   R   R   Ro   (    (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   S  s   			t   PickleFileSourcec           B` sw   e  Z d  Z d Z d d  Z e d    Z d   Z d   Z d   Z	 d   Z
 d	   Z d
   Z d   Z d   Z RS(   u  Class reading and writing settings to a file, formatted using the Python
  `pickle` module.
  
  This class is useful as a persistent source (i.e. permanent storage) of
  settings. This class is appropriate to use when saving settings to a file path
  chosen by the user.
  u    u
   persistentc         C` s    t    j | |  | |  _ d  S(   N(   R   R   t	   _filepath(   R   R
   t   filepathR   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    c         C` s   |  j  S(   N(   R   (   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    c         C` sE   |  j    } | d  k	 rA |  j | k rA | |  j =|  j |  n  d  S(   N(   t   read_all_dataR   R
   t   write_all_data(   R   t   all_data(    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    
c         C` s3   y |  j    } Wn t k
 r$ d SX| d k	 Sd S(   uY  Returns `True` if the source contains data and the data have a valid
    format, `'invalid_format'` if the source contains some data, but the data
    have an invalid format, and `False` otherwise.
    
    `'invalid_format'` represents an ambiguous value since there is no way to
    determine if there are data under `source_name` or not.
    u   invalid_formatN(   R   t   SourceErrorR   (   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s
    c         C` sC   |  j    } | d  k	 r; |  j | k r; |  j | |  j  Sd  Sd  S(   N(   R   R   R
   t   _get_settings_from_pickled_data(   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    c         C` sc   |  j  |  } |  j   } | d  k rE t j |  j | f g  } n | | |  j <|  j |  d  S(   N(   t   _pickle_settingsR   R   R+   R,   R
   R   (   R   R   t   raw_dataR   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRo     s    c         C` s   t  j j |  j  s d St j   } y| t j |  j d d t	 j
 X } xN | D]F } | j |  j d  } t |  d k rP | \ } } | | | <qP qP WWd QXWn# t k
 r t t j     n X| Sd S(   u   Reads the contents of the entire file into a dictionary of
    (source name, contents) pairs.
    
    The dictionary also contains contents from other source names if they exist.
    u   rt   encodingi   i   N(   R   RM   t   isfileR   R   R+   R,   t   iot   opent   pgconstantst   TEXT_FILE_ENCODINGt   splitt   _SOURCE_NAME_CONTENTS_SEPARATORRY   R   t   SourceReadErrort	   tracebackt
   format_exc(   R   R   t   ft   lineR   R
   t   contents(    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    !c         C` s   yd t  j |  j d d t j @ } x6 | j   D]( \ } } | j | |  j | d  q1 WWd QXWn# t k
 r t	 t
 j     n Xd S(   u   Writes `all_data` into the file, overwriting the entire file contents.
    
    `all_data` is a dictionary of (source name, contents) pairs.
    u   wR   u   
N(   R   R   R   R   R   RB   Rp   R   R   t   SourceWriteErrorR   R   (   R   R   R   R
   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    !*c         C` sD   y t  j t j |   SWn# t k
 r? t t j     n Xd  S(   N(   R   R   t   astt   literal_evalR   RG   R   R   (   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    c         C` sA   y t  t j |   SWn# t k
 r< t t j     n Xd  S(   N(   t   reprR   R   R   RG   R   R   (   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    (   R   R   R   R   R   R   R   R   R   R   Ro   R   R   R   R   (    (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   ~  s   							t   JsonFileSourcec           B` s_   e  Z d  Z d d  Z e d    Z d   Z d   Z d   Z d   Z	 d   Z
 d	   Z RS(
   uV  Class reading and writing settings to a JSON file.
  
  This class is useful as a persistent source (i.e. permanent storage) of
  settings. This class is appropriate to use when saving settings to a file path
  chosen by the user.
  
  Compared to `PickleFileSource`, JSON files are more readable and, if need be,
  easy to modify by hand.
  u
   persistentc         C` s5   t  s t d   n  t   j | |  | |  _ d  S(   Nu   "json" module not found(   t   _json_module_foundt   RuntimeErrorR   R   R   (   R   R
   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    c         C` s   |  j  S(   N(   R   (   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    c         C` sE   |  j    } | d  k	 rA |  j | k rA | |  j =|  j |  n  d  S(   N(   R   R   R
   R   (   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    
c         C` s3   y |  j    } Wn t k
 r$ d SX| d k	 Sd S(   uY  Returns `True` if the source contains data and the data have a valid
    format, `'invalid_format'` if the source contains some data, but the data
    have an invalid format, and `False` otherwise.
    
    `'invalid_format'` represents an ambiguous value since there is no way to
    determine if there are data under `source_name` or not.
    u   invalid_formatN(   R   R   R   (   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s
    c         C` s:   |  j    } | d  k	 r2 |  j | k r2 | |  j Sd  Sd  S(   N(   R   R   R
   (   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s    c         C` sT   |  j    } | d  k r6 t j |  j | f g  } n | | |  j <|  j |  d  S(   N(   R   R   R+   R,   R
   R   (   R   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyRo     s
    c         C` s   t  j j |  j  s d St j   } y: t j |  j d d t	 j
  } t j |  } Wd QXWn# t k
 r t t j     n X| Sd S(   u   Reads the contents of the entire file into a dictionary of
    (source name, contents) pairs.
    
    The dictionary also contains contents from other source names if they exist.
    u   rR   N(   R   RM   R   R   R   R+   R,   R   R   R   R   t   jsont   loadR   R   R   R   (   R   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   '  s    !c         C` s   yb t  j |  j d d t j > } t j | | d t d d d d
 } | j t	 |   Wd	 QXWn# t
 k
 r t t j     n Xd	 S(   u   Writes `all_data` into the file, overwriting the entire file contents.
    
    `all_data` is a dictionary of (source name, contents) pairs.
    u   wR   t	   sort_keyst   indenti   t
   separatorsu   ,u   : N(   u   ,u   : (   R   R   R   R   R   R   R   Rb   Rp   t   unicodeR   R   R   R   (   R   R   R   R   (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR   :  s    !$(   R   R   R   R   R   R   R   R   R   Ro   R   R   (    (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyR     s   							(.   R   t
   __future__R    R   R   R   t   future.builtinst   future.utilst   futureR   R   R+   R   R   R   R   t   cPickleR   t   ImportErrorR   Rb   R   RT   R   R   R   t    R   R   R   R   R   R!   R   R   R3   t   _sources_errorst   __all__t   with_metaclasst   ABCMetat   objectR	   R   R   R   R   (    (    (    sQ   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/sources.pyt   <module>   sN   "


	( &+l                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         # -*- coding: utf-8 -*-

"""Helper classes and functions for modules in the `setting` package."""

from __future__ import absolute_import, division, print_function, unicode_literals
from future.builtins import *

import collections
import itertools
import types

__all__ = [
  'SETTING_PATH_SEPARATOR',
  'SETTING_ATTRIBUTE_SEPARATOR',
  'SettingParentMixin',
  'SettingEventsMixin',
  'get_pdb_name',
  'get_setting_name',
  'value_to_str_prefix',
  'get_processed_display_name',
  'generate_display_name',
  'get_processed_description',
  'generate_description',
  'get_setting_path',
  'check_setting_name',
]


SETTING_PATH_SEPARATOR = '/'
SETTING_ATTRIBUTE_SEPARATOR = '.'


class SettingParentMixin(object):
  """
  This mixin provides `Setting` and `Group` instances with a parent reference,
  allowing settings and groups to form a tree-like structure.
  """
  
  def __init__(self):
    super().__init__()
    
    self._parent = None
  
  @property
  def parent(self):
    return self._parent
  
  @property
  def parents(self):
    """
    Return a list of parents (setting groups), starting from the topmost parent.
    """
    parent = self._parent
    parents = []
    
    while parent is not None:
      parents.insert(0, parent)
      parent = parent.parent
    
    return parents
  
  def _set_as_parent_for_setting(self, setting):
    setting._parent = self


class SettingEventsMixin(object):
  """
  This mixin provides `Setting` and `Group` instances with the capability of
  setting up and invoking events.
  """
  
  _event_handler_id_counter = itertools.count(start=1)
  
  def __init__(self):
    super().__init__()
    
    # key: event type
    # value: collections.OrderedDict{
    #   event handler ID: [event handler, arguments, keyword arguments, is enabled]}
    self._event_handlers = collections.defaultdict(collections.OrderedDict)
    
    # This allows faster lookup of events via IDs.
    # key: event handler ID; value: event type
    self._event_handler_ids_and_types = {}
  
  def connect_event(
        self, event_type, event_handler, *event_handler_args, **event_handler_kwargs):
    """
    Connect an event handler.
    
    `event_type` can be an arbitrary string. To invoke an event manually, call
    `invoke_event`.
    
    Several event types are invoked automatically. For the list of such event
    types, consult the documentation for `Setting` or `Group` classes.
    
    The `event_handler` function must always contain at least one argument -
    the instance this method is called from (a setting or a setting group).
    
    Multiple event handlers can be connected. Each new event handler is invoked
    as the last.
    
    Parameters:
    
    * `event_type` - Event type as a string.
    
    * `event_handler` - Function to be called when the event given by
      `event_type` is invoked.
    
    * `*event_handler_args` - Arguments to `event_handler`.
    
    * `**event_handler_kwargs` - Keyword arguments to `event_handler`.
    
    Returns:
    
    * `event_id` - Numeric ID of the event handler (can be used to remove the
      event via `remove_event`).
    
    Raises:
    
    * `TypeError` - `event_handler` is not a function or the wrong number of
      arguments was passed in `event_handler_args`.
    """
    if not callable(event_handler):
      raise TypeError('not a function')
    
    event_id = self._event_handler_id_counter.next()
    self._event_handlers[event_type][event_id] = [
      event_handler, event_handler_args, event_handler_kwargs, True]
    self._event_handler_ids_and_types[event_id] = event_type
    
    return event_id
  
  def remove_event(self, event_id):
    """
    Remove the event handler specified by its ID as returned by
    `connect_event()`.
    """
    if event_id not in self._event_handler_ids_and_types:
      raise ValueError('event handler with ID {} does not exist'.format(event_id))
    
    event_type = self._event_handler_ids_and_types[event_id]
    del self._event_handlers[event_type][event_id]
    del self._event_handler_ids_and_types[event_id]
  
  def set_event_enabled(self, event_id, enabled):
    """
    Enable or disable the event handler specified by its ID.
    
    If the event ID is already enabled and `enabled` is `True` or is already
    disabled and `enabled` is `False`, do nothing.
    
    Raises:
    
    * `ValueError` - Event ID is invalid.
    """
    if not self.has_event(event_id):
      raise ValueError('event ID {} is invalid'.format(event_id))
    
    event_type = self._event_handler_ids_and_types[event_id]
    self._event_handlers[event_type][event_id][3] = enabled
  
  def has_event(self, event_id):
    """
    Return `True` if the event handler specified by its ID is connected to the
    setting, `False` otherwise.
    """
    return event_id in self._event_handler_ids_and_types
  
  def invoke_event(self, event_type, *additional_args, **additional_kwargs):
    """
    Call all connected event handlers of the specified event type.
    
    Additional arguments and keyword arguments are passed via
    `*additional_args` and `**additional_kwargs`, respectively. These arguments
    are prepended to the arguments specified in `connect_event` (if any).
    The same keyword arguments in `connect_event` override keyword arguments in
    `**additional_kwargs`.
    """
    for (event_handler,
         args,
         kwargs,
         enabled) in self._event_handlers[event_type].values():
      if enabled:
        event_handler_args = additional_args + tuple(args)
        event_handler_kwargs = dict(additional_kwargs, **kwargs)
        event_handler(self, *event_handler_args, **event_handler_kwargs)


def get_pdb_name(setting_name):
  """
  Return name suitable for the description of the setting in the GIMP PDB.
  """
  return setting_name.replace('_', '-')


def get_setting_name(pdb_name):
  """
  Return setting name based on the specified name from GIMP PDB.
  """
  return pdb_name.replace('-', '_')


def value_to_str_prefix(value):
  """
  Return stringified setting value useful as a prefix to an error message.
  
  If `value` is empty or `None`, return empty string.
  """
  if value:
    return '"{}": '.format(value)
  else:
    return ''


def get_processed_display_name(setting_display_name, setting_name):
  if setting_display_name is not None:
    return setting_display_name
  else:
    return generate_display_name(setting_name)


def generate_display_name(setting_name):
  return setting_name.replace('_', ' ').capitalize()


def get_processed_description(setting_description, setting_display_name):
  if setting_description is not None:
    return setting_description
  else:
    return generate_description(setting_display_name)


def generate_description(display_name):
  """
  Generate setting description from a display name.
  
  Underscores in display names used as mnemonics are usually undesired in
  descriptions, hence their removal.
  """
  return display_name.replace('_', '')


def get_setting_path(setting, relative_path_group=None):
  """
  Get the full setting path consisting of names of parent setting groups and the
  specified setting. The path components are separated by '/'.
  
  If `relative_path_group` is specified, the setting group is used to
  relativize the setting path. If the path of the setting group to the topmost
  parent does not match, return the full path.
  
  If `relative_path_group` is equal to `'root'` and the setting has at
  least one parent, omit the topmost group.
  """
  def _get_setting_path(path_components):
    return SETTING_PATH_SEPARATOR.join([setting.name for setting in path_components])
  
  if relative_path_group == 'root':
    if setting.parents:
      setting_path_without_root = _get_setting_path(
        (setting.parents + [setting])[1:])
      return setting_path_without_root
    else:
      return setting.name
  else:
    setting_path = _get_setting_path(setting.parents + [setting])
    
    if relative_path_group is not None:
      root_path = _get_setting_path(
        relative_path_group.parents + [relative_path_group])
      if setting_path.startswith(root_path):
        return setting_path[len(root_path + SETTING_PATH_SEPARATOR):]
    
    return setting_path


def check_setting_name(setting_name):
  """
  Check if the specified setting name is valid. If not, raise `ValueError`.
  
  A setting name must not contain `SETTING_PATH_SEPARATOR` or
  `SETTING_ATTRIBUTE_SEPARATOR`.
  """
  if not isinstance(setting_name, types.StringTypes):
    raise TypeError('setting name must be a string')
  
  if (SETTING_PATH_SEPARATOR in setting_name
      or SETTING_ATTRIBUTE_SEPARATOR in setting_name):
    raise ValueError('setting name "{}" is not valid'.format(setting_name))
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                