U
    3dC!                     @   s   d Z ddlmZmZ ddlZddlmZmZ ddlm	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mZ ddgZG dd deedZG dd deZdd ZdddZdS )zUtilities for meta-estimators    )ListAnyN)ABCMetaabstractmethod)
attrgetter)suppress   )_safe_indexing)
_safe_tags)BaseEstimator   )available_if_AvailableIfDescriptorr   if_delegate_has_methodc                       sX   e Zd ZU dZee ed< edd Zd fdd	Z	 fdd	Z
d
d Zdd Z  ZS )_BaseCompositionzJHandles parameter management for classifiers composed of named estimators.Zstepsc                 C   s   d S N )selfr   r   @/tmp/pip-unpacked-wheel-zrfo1fqw/sklearn/utils/metaestimators.py__init__   s    z_BaseComposition.__init__Tc           	   	      s   t  j|d}|s|S t| |}z|| W n ttfk
rJ   | Y S X |D ]<\}}t|drP|jdd D ]\}}||d||f < qrqP|S )Ndeep
get_paramsTz%s__%s)superr   getattrupdate	TypeError
ValueErrorhasattritems)	r   attrr   outZ
estimatorsname	estimatorkeyvalue	__class__r   r   _get_params   s    


z_BaseComposition._get_paramsc              	      s   ||krt | ||| t| |}t|tr|rttH t| \}}t| D ](}d|krT||krT| 	|||| qTW 5 Q R X t
 jf | | S )N__)setattrpopr   
isinstancelistr   r   zipkeys_replace_estimatorr   Z
set_params)r   r    paramsr   Z
item_names_r"   r&   r   r   _set_params4   s    

 z_BaseComposition._set_paramsc                 C   sL   t t| |}t|D ]$\}\}}||kr||f||<  q<qt| || d S r   )r-   r   	enumerater*   )r   r    r"   new_valZnew_estimatorsiZestimator_namer2   r   r   r   r0   I   s    z#_BaseComposition._replace_estimatorc                 C   sv   t t|t |kr&tdt|t|| jdd}|rRtdt|dd |D }|rrtd|d S )Nz$Names provided are not unique: {0!r}Fr   z:Estimator names conflict with constructor arguments: {0!r}c                 S   s   g | ]}d |kr|qS )r)   r   ).0r"   r   r   r   
<listcomp>\   s      z4_BaseComposition._validate_names.<locals>.<listcomp>z.Estimator names must not contain __: got {0!r})lensetr   formatr-   intersectionr   sorted)r   namesinvalid_namesr   r   r   _validate_namesR   s    z _BaseComposition._validate_names)T)__name__
__module____qualname____doc__r   r   __annotations__r   r   r(   r3   r0   r@   __classcell__r   r   r&   r   r      s   

	r   )	metaclassc                       s(   e Zd ZdZ fddZdd Z  ZS )_IffHasAttrDescriptorat  Implements a conditional property using the descriptor protocol.

    Using this class to create a decorator will raise an ``AttributeError``
    if none of the delegates (specified in ``delegate_names``) is an attribute
    of the base object or the first found delegate does not have an attribute
    ``attribute_name``.

    This allows ducktyping of the decorated method based on
    ``delegate.attribute_name``. Here ``delegate`` is the first item in
    ``delegate_names`` for which ``hasattr(object, delegate) is True``.

    See https://docs.python.org/3/howto/descriptor.html for an explanation of
    descriptors.
    c                    s   t  || j| || _d S r   )r   r   _checkdelegate_names)r   fnrJ   attribute_namer&   r   r   r   t   s    z_IffHasAttrDescriptor.__init__c              	   C   sh   t dt d }| jD ]4}zt||}W  qLW q tk
rH   Y qY qX q|d krXdS t|| j dS )Nzrif_delegate_has_method was deprecated in version 1.1 and will be removed in version 1.3. Use available_if instead.FT)warningswarnFutureWarningrJ   r   AttributeErrorr   rL   )r   objdelegateZdelegate_namer   r   r   rI   x   s    

z_IffHasAttrDescriptor._check)rA   rB   rC   rD   r   rI   rF   r   r   r&   r   rH   d   s   rH   c                    s.   t  trt  t  ts" f  fddS )a%  Create a decorator for methods that are delegated to a sub-estimator.

    .. deprecated:: 1.3
        `if_delegate_has_method` is deprecated in version 1.1 and will be removed in
        version 1.3. Use `available_if` instead.

    This enables ducktyping by hasattr returning True according to the
    sub-estimator.

    Parameters
    ----------
    delegate : str, list of str or tuple of str
        Name of the sub-estimator that can be accessed as an attribute of the
        base object. If a list or a tuple of names are provided, the first
        sub-estimator that is an attribute of the base object will be used.

    Returns
    -------
    callable
        Callable makes the decorated method available if the delegate
        has a method with the same name as the decorated method.
    c                    s   t |  | jdS )N)rL   )rH   rA   )rK   rR   r   r   <lambda>       z(if_delegate_has_method.<locals>.<lambda>)r,   r-   tuplerS   r   rS   r   r      s
    

c                 C   s   t | ddrft|dstd|jd |jd kr:td|dkrT|t|| }qp|t|| }n
t||}|dk	rt||}nd}||fS )	a  Create subset of dataset and properly handle kernels.

    Slice X, y according to indices for cross-validation, but take care of
    precomputed kernel-matrices or pairwise affinities / distances.

    If ``estimator._pairwise is True``, X needs to be square and
    we slice rows and columns. If ``train_indices`` is not None,
    we slice rows using ``indices`` (assumed the test set) and columns
    using ``train_indices``, indicating the training set.

    Labels y will always be indexed only along the first axis.

    Parameters
    ----------
    estimator : object
        Estimator to determine whether we should slice only rows or rows and
        columns.

    X : array-like, sparse matrix or iterable
        Data to be indexed. If ``estimator._pairwise is True``,
        this needs to be a square array-like or sparse matrix.

    y : array-like, sparse matrix or iterable
        Targets to be indexed.

    indices : array of int
        Rows to select from X and y.
        If ``estimator._pairwise is True`` and ``train_indices is None``
        then ``indices`` will also be used to slice columns.

    train_indices : array of int or None, default=None
        If ``estimator._pairwise is True`` and ``train_indices is not None``,
        then ``train_indices`` will be use to slice the columns of X.

    Returns
    -------
    X_subset : array-like, sparse matrix or list
        Indexed data.

    y_subset : array-like, sparse matrix or list
        Indexed targets.

    Zpairwise)r$   shapezXPrecomputed kernels or affinity matrices have to be passed as arrays or sparse matrices.r   r   z"X should be a square kernel matrixN)r
   r   r   rW   npZix_r	   )r#   XyindicesZtrain_indicesZX_subsetZy_subsetr   r   r   _safe_split   s    ,

r\   )N)rD   typingr   r   rM   abcr   r   operatorr   ZnumpyrX   
contextlibr   utilsr	   Zutils._tagsr
   baser   Z_available_ifr   r   __all__r   rH   r   r\   r   r   r   r   <module>   s   O,