σ
dςτ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 m	 Z
 d Z d e f d	     YZ e   Z d
   Z e Z d d  Z d   Z d   Z d d  Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d S(   u$   Misc. utility functions and classes.i    (   t   absolute_importt   divisiont   print_functiont   unicode_literals(   t   *Ni   (   t	   constantsu   /t   EmptyContextc           B` s)   e  Z d  Z d   Z d   Z d   Z RS(   u\  
  This class provides an empty context manager that can be used in `with`
  statements in place of a real context manager if a condition is not met:
    
    with context_manager if condition else EmptyContext():
      ...
  
  Or use the `empty_context` global instance:
    
    with context_manager if condition else empty_context:
      ...
  c         O` s   d  S(   N(    (   t   selft   argst   kwargs(    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   __init__   s    c         C` s   d  S(   N(    (   R   (    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt	   __enter__!   s    c         G` s   d  S(   N(    (   R   t   exc_info(    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   __exit__$   s    (   t   __name__t
   __module__t   __doc__R
   R   R   (    (    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyR      s   		c          O` s   d S(   u  
  Use this function when an empty function is desired to be passed as a
  parameter.
  
  For example, if you need to serialize a `collections.defaultdict` instance
  (e.g. via `pickle`) returning `None` for missing keys, you need to use a named
  function instead of `lambda: None`. To emphasize this particular intent, you
  may want to use the alias `return_none_func` instead.
  N(   t   None(   R   R	   (    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt
   empty_func+   s    
c         ` s     f d   } | S(   uD   
  Return an empty function returning the specified return value.
  c          ` s     S(   N(    (   R   R	   (   t   return_value(    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   _empty_func_with_return_value?   s    (    (   R   R   (    (   R   sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   create_empty_func;   s    c         C` s   t  |  d  o |  j d k	 S(   uC   
  Return `True` if `func` is a bound method, `False` otherwise.
  u   __self__N(   t   hasattrt   __self__R   (   t   func(    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   is_bound_methodE   s    c         C` s   d j  t |   j |  S(   uψ   
  Return a string representation of the specified object, using the specified
  name as a presumed unique identifier of the object. This can be used in the
  `__str__()` method to return a more readable string representation than the
  default.
  u	   <{} "{}">(   t   formatt   typeR   (   t   object_t   name(    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   stringify_objectL   s    c         C` s~   t  |   } t | d  r2 | j d | j } n	 | j } d j | | d k	 r_ d j |  n d t t |    j d   S(   uK  Return a string representation of the object useful for `repr()` calls.
  
  The first part of the string, the class path, starts from the `'pygimplib'`
  module. If the full class path is not available, only the class name is given.
  
  A custom `name`, if not `None`, replaces the default `'object'` inserted in
  the string.
  u
   __module__u   .u   <{} {} at {}>u   "{}"u   objectu   LN(	   R   R   R   R   R   R   t   hext   idt   rstrip(   R   R   t   object_typet   object_type_path(    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   reprify_objectV   s    		c         C` sG   |  j  d  } | | k r? | j |  } d j | | d   S|  Sd S(   u"  
  Return the part of the full module name (separated by '.' characters) from the
  beginning up to the matching module name component including that component.
  
  If `name_component_to_trim_after` does not match any name component from
  `full_module_name`, return `full_module_name`.
  u   .i   N(   t   splitt   indext   join(   t   full_module_namet   name_component_to_trim_aftert   module_name_componentst   name_component_index(    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   get_module_rootm   s
    c           C` s   t  t d  S(   uF   Returns the absolute module path to the root of the pygimplib library.u	   pygimplib(   R,   R   (    (    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   get_pygimplib_module_path~   s    c           C` s   t  j   d d S(   uH   
  Get the full path name of the module this function is called from.
  i   (   t   inspectt   stack(    (    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   get_current_module_filepath   s    c         C` s:   t  |  d | |  t  |  j | t d | d    d S(   u’   
  For the given `obj` object, create a private attribute named `_[name]` and a
  read-only property named `name` returning the value of the private attribute.
  u   _t   fgetc         S` s   t  |  d |  S(   Nu   _(   t   getattr(   t   objR   (    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   <lambda>   t    N(   t   setattrt	   __class__t   property(   R3   R   t   value(    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   create_read_only_property   s
    c         C` s!   |  d k	 r |  j |  Sd Sd S(   uG   Encodes a string. If the string is `None`, an empty string is returned.R5   N(   R   t   encode(   t   str_t   encoding(    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   safe_encode   s    c         C` s   t  |  t j  S(   uU   Encodes a string for GTK API. If the string is `None`, an empty string is
  returned.(   R>   t   pgconstantst   GTK_CHARACTER_ENCODING(   R<   (    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   safe_encode_gtk   s    c         C` s   t  |  t j  S(   uV   Encodes a string for GIMP API. If the string is `None`, an empty string is
  returned.(   R>   R?   t   GIMP_CHARACTER_ENCODING(   R<   (    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   safe_encode_gimp€   s    c         C` s!   |  d k	 r |  j |  Sd Sd S(   uG   Decodes a string. If the string is `None`, an empty string is returned.u    N(   R   t   decode(   R<   R=   (    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   safe_decodeͺ   s    c         C` s   t  |  t j  S(   uU   Decodes a string for GTK API. If the string is `None`, an empty string is
  returned.(   RE   R?   R@   (   R<   (    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   safe_decode_gtk²   s    c         C` s   t  |  t j  S(   uV   Decodes a string for GIMP API. If the string is `None`, an empty string is
  returned.(   RE   R?   RB   (   R<   (    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   safe_decode_gimpΈ   s    (    R   t
   __future__R    R   R   R   t   future.builtinsR.   R5   R   R?   t   GIMP_ITEM_PATH_SEPARATORt   objectR   t   empty_contextR   t   return_none_funcR   R   R   R   R$   R,   R-   R0   R:   R>   RA   RC   RE   RF   RG   (    (    (    sG   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/utils.pyt   <module>   s.   "
		
		
									                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             # -*- coding: utf-8 -*-

"""Management of version numbers (particularly incrementing)."""

from __future__ import absolute_import, division, print_function, unicode_literals
from future.builtins import *

import re


class Version(object):
  
  def __init__(
        self, major=None, minor=None, patch=None, prerelease=None, prerelease_patch=None):
    self.major = major
    self.minor = minor
    self.patch = patch
    self.prerelease = prerelease
    self.prerelease_patch = prerelease_patch
  
  def __str__(self):
    version_str = '{}.{}'.format(self.major, self.minor)
    
    if self.patch is not None:
      version_str += '.{}'.format(self.patch)
    
    if self.prerelease is not None:
      version_str += '-{}'.format(self.prerelease)
      if self.prerelease_patch is not None:
        version_str += '.{}'.format(self.prerelease_patch)
    
    return version_str
  
  def __repr__(self):
    return '{}({}, {}, {}, {}, {})'.format(
      self.__class__.__name__, self.major, self.minor, self.patch,
      '"' + self.prerelease + '"' if self.prerelease is not None else self.prerelease,
      self.prerelease_patch)
  
  def __lt__(self, other_version):
    this_version_main_components = self._get_main_components_tuple(self)
    other_version_main_components = self._get_main_components_tuple(other_version)
    
    if this_version_main_components < other_version_main_components:
      return True
    elif this_version_main_components > other_version_main_components:
      return False
    else:
      if self.prerelease is not None and other_version.prerelease is None:
        return True
      elif self.prerelease is not None and other_version.prerelease is not None:
        if self.prerelease < other_version.prerelease:
          return True
        elif self.prerelease > other_version.prerelease:
          return False
        else:
          return (
            self._get_default_number(self.prerelease_patch)
            < self._get_default_number(other_version.prerelease_patch))
      else:
        return False
  
  def __le__(self, other_version):
    return self.__lt__(other_version) or self.__eq__(other_version)
  
  def __eq__(self, other_version):
    return (
      (self._get_main_components_tuple(self)
       == self._get_main_components_tuple(other_version))
      and self.prerelease == other_version.prerelease
      and (self._get_default_number(self.prerelease_patch)
           == self._get_default_number(other_version.prerelease_patch)))
  
  def __ne__(self, other_version):
    return not self.__eq__(other_version)
  
  def __gt__(self, other_version):
    return not self.__le__(other_version)
  
  def __ge__(self, other_version):
    return not self.__lt__(other_version)
  
  def increment(self, component_to_increment, prerelease=None):
    """
    Increment the version as per `component_to_increment` and `prerelease`.
    
    `component_to_increment` can be `'major'`, `'minor'` or `'patch'`. Given the
    format `X.Y.Z`, `'major'` increments `X`, `'minor'` increments `Y` and
    `'patch'` increments `Z`. If `patch` attribute is `None` and `'patch'` is
    specified, `1` will be assigned (e.g. `3.3` becomes `3.3.1`).
    
    If the `prerelease` string is not `None` and non-empty, append the
    pre-release to the version. For example, `3.3` with `'major'` compoment and
    `'alpha'` as the pre-release string becomes `4.0-alpha`.
    
    If the version already has the same pre-release, append a number to the
    pre-release (e.g. `4.0-alpha` becomes `4.0-alpha.2`).
    
    If the version already has a different pre-release (lexically earlier than
    `prerelease`), replace the existing pre-release with `prerelease` (e.g.
    `4.0-alpha` with the `'beta'` pre-release becomes `4.0-beta`).
    
    Raises:
    
    * `ValueError`:
      
      * Invalid value for `component_to_increment`.
      * The specified `prerelease` contains non-alphanumeric characters or is
        lexically earlier than the existing `prerelease` attribute.
    """
    if component_to_increment not in ['major', 'minor', 'patch']:
      raise ValueError('invalid version component "{}"'.format(component_to_increment))
    
    if prerelease:
      if not re.search(r'^[a-zA-Z0-9]+$', prerelease):
        raise ValueError('invalid pre-release format "{}"'.format(prerelease))
      
      if prerelease < self.prerelease:
        raise ValueError(
          'the specified pre-release "{}" is lexically earlier than'
          ' the existing pre-release "{}"'.format(prerelease, self.prerelease))
    
    if not prerelease:
      prerelease = None
    
    def increment_major():
      self.major += 1
      self.minor = 0
      self.patch = None
    
    def increment_minor():
      self.minor += 1
      self.patch = None
    
    def increment_patch():
      if self.patch is None:
        self.patch = 0
      self.patch += 1
    
    def clear_prerelease():
      self.prerelease = None
      self.prerelease_patch = None
    
    def set_new_prerelease():
      self.prerelease = prerelease
      self.prerelease_patch = None
    
    def increment_prerelease():
      if self.prerelease_patch is None:
        self.prerelease_patch = 1
      self.prerelease_patch += 1
    
    if component_to_increment == 'major':
      increment_component_func = increment_major
    elif component_to_increment == 'minor':
      increment_component_func = increment_minor
    elif component_to_increment == 'patch':
      increment_component_func = increment_patch
    
    if prerelease is None:
      increment_component_func()
      clear_prerelease()
    else:
      if self.prerelease is None:
        increment_component_func()
        set_new_prerelease()
      else:
        if prerelease == self.prerelease:
          increment_prerelease()
        else:
          set_new_prerelease()
  
  @classmethod
  def parse(cls, version_str):
    """
    Parse the `version_str` string and return a `Version` instance.
    
    Raises:
    
    * `InvalidVersionFormatError` - `version_str` has invalid format.
    """
    ver = Version()
    cls._fill_version_components(ver, version_str)
    return ver
  
  @classmethod
  def _fill_version_components(cls, version_obj, version_str):
    version_str_components = version_str.split('-')
    
    if len(version_str_components) > 2:
      raise InvalidVersionFormatError
    
    cls._set_main_version_components(version_obj, version_str_components[0])
    
    if len(version_str_components) == 2:
      cls._set_prerelease_version_components(version_obj, version_str_components[1])
  
  @classmethod
  def _set_main_version_components(cls, version_obj, main_str_components):
    match = re.search(r'^([0-9]+?)\.([0-9]+?)$', main_str_components)
    
    if match is None:
      match = re.search(r'^([0-9]+?)\.([0-9]+?)\.([1-9][0-9]*)$', main_str_components)
      if match is None:
        raise InvalidVersionFormatError
    
    match_groups = match.groups()
    version_obj.major = int(match_groups[0])
    version_obj.minor = int(match_groups[1])
    if len(match_groups) == 3:
      version_obj.patch = int(match_groups[2])
  
  @classmethod
  def _set_prerelease_version_components(cls, version_obj, prerelease_str_components):
    match = re.search(r'^([a-zA-Z0-9]+?)$', prerelease_str_components)
    
    if match is None:
      match = re.search(
        r'^([a-zA-Z0-9]+?)\.([2-9]|[1-9][0-9]+)$', prerelease_str_components)
      if match is None:
        raise InvalidVersionFormatError
    
    match_groups = match.groups()
    version_obj.prerelease = match_groups[0]
    if len(match_groups) == 2:
      version_obj.prerelease_patch = int(match_groups[1])
  
  @staticmethod
  def _get_main_components_tuple(ver):
    return tuple(
      number if number is not None else -1
      for number in [ver.major, ver.minor, ver.patch])
  
  @staticmethod
  def _get_default_number(component):
    return component if component is not None else -1


class InvalidVersionFormatError(Exception):
  pass
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     