ó
âdc           @` 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 e
 f d „  ƒ  YZ e j d d d	 d
 d d g ƒ Z d S(   u9   Class to filter objects according to the specified rules.i    (   t   absolute_importt   divisiont   print_functiont   unicode_literals(   t   *Nt   ObjectFilterc           B` s2  e  Z d  Z d Z \ Z Z e j d d ƒ Z e d d „ Z	 e
 d „  ƒ Z e
 d „  ƒ Z d „  Z d	 „  Z d
 „  Z d „  Z d d d d „ Z d „  Z d „  Z d d d d d „ Z e j d d d d „ ƒ Z e j d d d d d „ ƒ Z d „  Z d „  Z d „  Z d d d d „ Z d „  Z d „  Z RS(   uë  Class containing a list of rules determining whether an object matches
  given rules.
  
  Attributes:
  
  * `match_type` (read-only) - Match type. Possible match types:
    
    * MATCH_ALL - For `is_match()` to return `True`, an object must match
      all rules.
    
    * MATCH_ANY - For `is_match()` to return `True`, an object must match
      at least one rule.
  
  * `name` (read-only) - Name of the filter. The name does not have to be unique
    and can be used to manipulate multiple rules (functions or nested filters)
    with the same name at once (e.g. by removing them with `remove()`).
  
  A rule can be a callable (function) or a nested `ObjectFilter` instance (with
  its own rules and different matching type if needed).
  i    i   t   startu    c         C` s%   | |  _  | |  _ t j ƒ  |  _ d  S(   N(   t   _match_typet   _namet   collectionst   OrderedDictt   _rules(   t   selft
   match_typet   name(    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt   __init__'   s    		c         C` s   |  j  S(   N(   R   (   R   (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyR   /   s    c         C` s   |  j  S(   N(   R   (   R   (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyR   3   s    c         C` s   t  |  j ƒ S(   u=   Returns `True` if the filter is not empty, `False` otherwise.(   t   boolR   (   R   (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt   __bool__7   s    c         C` s   | |  j  k S(   uš   Returns `True` if the filter contains the given rule, `False` otherwise.
    
    Parameters:
    
    * `rule_id` -  rule ID as returned by `add()`.
    (   R   (   R   t   rule_id(    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt   __contains__;   s    c         C` s   |  j  | S(   uã   Returns the specified rule - a `_Rule` instance or a nested filter.
    
    Parameters:
    
    * `rule_id` -  rule ID as returned by `add()`.
    
    Raises
    
    * `KeyError` - `rule_id` is not found in the filter.
    (   R   (   R   R   (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt   __getitem__D   s    c         C` s   t  |  j ƒ S(   ub   Returns the number of rules in the filter.
    
    Rules within nested filters do not count.
    (   t   lenR   (   R   (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt   __len__Q   s    c         C` s¼   | d k	 r | n d } | d k	 r* | n i  } |  j ƒ  } t | t ƒ r\ | |  j | <| St | ƒ r£ | } t | | | |  j | | ƒ | ƒ } | |  j | <| St d j	 | ƒ ƒ ‚ d S(   u²  Adds the specified callable or a nested filter as a rule to the filter.
    
    Parameters:
    
    * `func_or_filter` - A callable (function) or nested filter to filter
      objects by. If a callable, it must have at least one argument - the object
      to match (used by `is_match()`).
    
    * `args` - Arguments for `func_or_filter` if it is a callable.
    
    * `kwargs` - Keyword arguments for `func_or_filter` if it is a callable.
    
    * `name` - Name of the added rule if `func_or_filter` is a callable. If an
      empty string, the `__name__` attribute is used if it exists. `name` does
      not have to be unique and can be used to manipulate multiple rules with
      the same name at once (e.g. by removing them with `remove()`).
    
    Returns:
      
      If `func_or_filter` is a callable, a `_Rule` instance is returned,
      containing the input parameters and a unique identifier. If
      `func_or_filter` is a nested filter, a unique identifier is used. The
      identifier can be used to e.g. access (via `__getitem__`) or remove a
      rule.
    
    Raises:
    
    * `TypeError` - `func_or_filter` is not a callable or an `ObjectFilter`
      instance.
    u-   "{}": not a callable or ObjectFilter instanceN(    (
   t   Nonet   _get_rule_idt
   isinstanceR   R   t   callablet   _Rulet   _get_rule_name_for_funct	   TypeErrort   format(   R   t   func_or_filtert   argst   kwargsR   R   t   funct   rule(    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt   addX   s"    	c         C` s%   | r t  | d ƒ r | j S| Sd  S(   Nu   __name__(   t   hasattrt   __name__(   R   R"   R   (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyR   Ž   s    c         C` s   |  j  j ƒ  S(   N(   t   _rule_id_countert   next(   R   (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyR   ”   s    c         C` sÉ   | d k r3 | d k r3 | d k r3 t d ƒ ‚ n  g  } | d k	 sQ | d k	 rr |  j d | d | d | ƒ } n  | |  k rš | | k rš | j | ƒ n  g  | D] } |  j j | ƒ ^ q¡ } | | f S(   uî  Removes rules from the filter matching one or more criteria.
    
    Parameters:
    
    * `rule_id` -  rule ID as returned by `add()`.
    
    * `name` - See `find()`.
    
    * `func_or_filter` - See `find()`.
    
    * `count` - See `find()`.
    
    Raises:
      
    * `ValueError` - If `rule_id`, `name` and `func_or_filter` are all `None`.
    
    Returns:
      
      A list of removed removed rules (callables or nested filters) and a list
      of the corresponding IDs.
    u0   at least one removal criterion must be specifiedR   R   t   countN(   R   t
   ValueErrort   findt   appendR   t   pop(   R   R   R   R   R)   t   matching_idst   id_t   matching_rules(    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt   remove—   s    $!%c         c` sˆ   | d k	 r | n d } | d k	 r* | n i  } |  j | | | | ƒ } z	 | VWd t | t ƒ rv |  j | j ƒ n |  j | ƒ Xd S(   u  Temporarily adds a callable or nested filter as a rule to the filter.
    
    Use this function as a context manager:
    
      with filter.add_temp(func_or_filter) as rule_or_id:
        # do stuff
    
    See `add()` for further information about parameters and exceptions.
    N(    (   R   R$   R   R   R1   t   id(   R   R   R    R!   R   t
   rule_or_id(    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt   add_temp¼   s    	c      	   c` sn   |  j  d | d | d | d | ƒ \ } } z | | f VWd x* t | | ƒ D] \ } } | |  j | <qL WXd S(   u¦  Temporarily removes rules from the filter matching one or more criteria.
    
    Use as a context manager:
      
      rule_id = filter.add(...)
      
      with filter.remove_temp(rule_id=rule_id) as rules_and_ids:
        # do stuff
    
    The identifiers (IDs) of the temporarily removed rules are preserved once
    added back.
    
    See `remove()` for further information about parameters and exceptions.
    R   R   R   R)   N(   R1   t   zipR   (   R   R   R   R   R)   R0   R.   R#   (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt   remove_tempÔ   s    	!c         C` sO   |  j  s t S|  j |  j k r, |  j | ƒ S|  j |  j k rK |  j | ƒ Sd S(   u  Returns `True` if the specified object matches the rules, `False`
    otherwise.
    
    If `match_type` is `MATCH_ALL`, `True` is returned if the object matches all
    rules and all top-level nested filters return `True`. Otherwise, `False` is
    returned.
    
    If `match_type` is `MATCH_ANY`, `True` is returned if the object matches at
    least one rule or at least one top-level nested filter returns `True`.
    Otherwise, `False` is returned.
    
    If no rules are specified, `True` is returned.
    N(   R   t   TrueR   t	   MATCH_ALLt   _is_match_allt	   MATCH_ANYt   _is_match_any(   R   t   obj(    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt   is_matchí   s    	c         C` s|   t  } xo |  j j ƒ  D]^ } t | t ƒ rC | o= | j | ƒ } n' | } | og | j | | j | j Ž } | s Pq q W| S(   N(	   R7   R   t   valuesR   R   R=   t   functionR    R!   (   R   R<   R=   t   valueR#   (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyR9     s    !c         C` s|   t  } xo |  j j ƒ  D]^ } t | t ƒ rC | p= | j | ƒ } n' | } | pg | j | | j | j Ž } | r Pq q W| S(   N(	   t   FalseR   R>   R   R   R=   R?   R    R!   (   R   R<   R=   R@   R#   (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyR;     s    !c         C` s  | d k r' | d k r' t d ƒ ‚ n  t j ƒ  } xž |  j j ƒ  D] \ } } | d k	 rz | j | k rz d | | <qz n  | d k	 rC t | t ƒ r´ | j	 | k rÍ d | | <qÍ qÐ | | k rÐ d | | <qÐ qC qC Wt
 | ƒ } | d k rð | S| d k r| |  S| | Sd S(   u  Finds rule IDs matching the specified name or object (callable or nested
    filter).
    
    Both `name` and `func_or_filter` can be specified at the same time.
    
    Parameters:
    
    * `name` - Name of the added rule (callable or nested filter).
    
    * `func_or_filter` - Callable (e.g. a function) or a nested `ObjectFilter`
      instance.
    
    * `count` - If 0, return all occurrences. If greater than 0, return up to
      the first `count` occurrences. If less than 0, return up to the last
      `count` occurrences.
    
    Returns:
    
      List of IDs of matching `_Rule` instances or nested filters, or an empty
      list if there is no match.
    
    Raises:
      
    * `ValueError` - If both `name` and `func_or_filter` are `None`.
    u+   at least a name or object must be specifiedi    N(   R   R*   R	   R
   R   t   itemsR   R   R   R?   t   list(   R   R   R   R)   t   matching_rule_idsR   t   rule_or_filter(    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyR+     s&    c         C` s   t  j |  j ƒ S(   u.   Returns a dictionary of (rule ID, rule) pairs.(   R	   R
   R   (   R   (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt
   list_rulesV  s    c         C` s   |  j  j ƒ  d S(   uC   Resets the filter, removing all rules. The match type is preserved.N(   R   t   clear(   R   (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt   reset[  s    (   i    i   N(    R&   t
   __module__t   __doc__t   _MATCH_TYPESR8   R:   t	   itertoolsR)   R'   R   t   propertyR   R   R   R   R   R   R   R$   R   R   R1   t
   contextlibt   contextmanagerR4   R6   R=   R9   R;   R+   RF   RH   (    (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyR      s0   					6		%			7	u   _Ruleu   functionu   argsu   kwargsu   nameu   id(   RJ   t
   __future__R    R   R   R   t   future.builtinsR	   RN   RL   t   objectR   t
   namedtupleR   (    (    (    sN   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/objectfilter.pyt   <module>   s   "
ÿ T                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          # -*- coding: utf-8 -*-

"""Handling of conflicting files - overwrite, skip, etc."""

from __future__ import absolute_import, division, print_function, unicode_literals
from future.builtins import *
import future.utils

import abc
import os

from . import path as pgpath


class OverwriteChooser(future.utils.with_metaclass(abc.ABCMeta, object)):
  """
  This class is an interface to indicate how to handle existing files.
  
  Attributes:
  
  * `overwrite_mode` (read-only) - Overwrite mode chosen by the user.
  """
  
  @abc.abstractmethod
  def overwrite_mode(self):
    pass
  
  @abc.abstractmethod
  def choose(self, filepath=None):
    """
    Return a value indicating how to handle the conflicting file
    by letting the user choose the value.
    
    The actual overwrite modes (possible values one of which the user chooses)
    and the implementation of handling conflicting files are left to the
    programmer using the return value provided by this method.
    
    Parameters:
    
    * `filepath` - File path that conflicts with an existing file. This class
      uses the file path to simply display it to the user. Defaults to `None`.
    """
    pass


class NoninteractiveOverwriteChooser(OverwriteChooser):
  """
  This class simply stores overwrite mode specified upon the object
  instantiation. The object is suitable to use in a non-interactive environment,
  i.e. with no user interaction.
  """
  
  def __init__(self, overwrite_mode):
    super().__init__()
    self._overwrite_mode = overwrite_mode
  
  @property
  def overwrite_mode(self):
    return self._overwrite_mode
  
  def choose(self, filepath=None):
    return self._overwrite_mode


class InteractiveOverwriteChooser(
        future.utils.with_metaclass(abc.ABCMeta, OverwriteChooser)):
  """
  This class is an interface for interactive overwrite choosers, requiring
  the user choose the overwrite mode.
  
  Additional attributes:
  
  * `values_and_display_names` - List of (value, display name) tuples which
    define overwrite modes and their human-readable names.
  
  * `default_value` - Default value. Must be one of the values in the
    `values_and_display_names` list.
  
  * `default_response` - Default value to return if the user made a choice that
    returns a value not in `values_and_display_names`. `default_response` does
    not have to be any of the values in `values_and_display_names`.
  
  * `is_apply_to_all` (read-only) - Whether the user-made choice applies to the
    current file (`False`) or to the current and all subsequent files (`True`).
  """
  
  def __init__(self, values_and_display_names, default_value, default_response):
    super().__init__()
    
    self.values_and_display_names = values_and_display_names
    self._values = [value for value, unused_ in self.values_and_display_names]
    
    if default_value not in self._values:
      raise ValueError(
        'invalid default value "{}"; must be one of the following: {}'.format(
          default_value, self._values))
    
    self.default_value = default_value
    self.default_response = default_response

    self._overwrite_mode = self.default_value
    self._is_apply_to_all = False
  
  @property
  def overwrite_mode(self):
    return self._overwrite_mode
  
  @property
  def is_apply_to_all(self):
    return self._is_apply_to_all
  
  def choose(self, filepath=None):
    if self._overwrite_mode is None or not self._is_apply_to_all:
      return self._choose(filepath)
    else:
      return self._overwrite_mode
  
  @abc.abstractmethod
  def _choose(self, filepath):
    """
    Let the user choose the overwrite mode and return it.
    
    If the choice results in a value that is not in `values_and_display_names`,
    return `default_response`.
    """
    pass


def handle_overwrite(filepath, overwrite_chooser, position=None):
  """
  If a file with the specified file path exists, handle the file path conflict
  via `overwrite_chooser` (an `OverwriteChooser` instance).
  `filepath` indicates a file path for a new file to be saved.
  
  `overwrite_chooser` should support all overwrite modes specified in
  `OverwriteModes`. `RENAME_NEW` mode renames `filepath`.
  `RENAME_EXISTING` renames the existing file in the file system.
  
  If the overwrite mode indicates that the file path should be renamed and
  `position` is not `None`, the `position` specifies where in the file path to
  insert a unique substring (`' (number)'`). By default, the substring is
  inserted at the end of the file path to be renamed.
  
  Returns:
  
    * the overwrite mode as returned by `overwrite_chooser`, which the caller
      of this function can further use (especially `SKIP` or `CANCEL` values),
    
    * the file path passed as the argument, modified if `RENAME_NEW` mode is
      returned.
  """
  if os.path.exists(filepath):
    overwrite_chooser.choose(filepath=os.path.abspath(filepath))
    
    if overwrite_chooser.overwrite_mode in (
         OverwriteModes.RENAME_NEW, OverwriteModes.RENAME_EXISTING):
      uniq_filepath = pgpath.uniquify_filepath(filepath, position)
      if overwrite_chooser.overwrite_mode == OverwriteModes.RENAME_NEW:
        filepath = uniq_filepath
      else:
        os.rename(filepath, uniq_filepath)
  
    return overwrite_chooser.overwrite_mode, filepath
  else:
    return OverwriteModes.DO_NOTHING, filepath


class OverwriteModes(object):
  """
  This class defines common overwrite modes for convenience.
  
  `SKIP` should be used if a file path already exists and no action should be
  taken.
  
  `DO_NOTHING` should be used if a file path does not exist and no action should
  be taken.
  
  `CANCEL` should be used if the user terminated the overwrite chooser (e.g.
  closed the overwrite dialog when an interactive chooser is used).
  """
  
  OVERWRITE_MODES = REPLACE, SKIP, RENAME_NEW, RENAME_EXISTING, CANCEL, DO_NOTHING = (
    0, 1, 2, 3, 4, 5)
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     