o
    ˷eL                     @   s   d dl Z d dlZd dlmZ d dlmZ d dlmZ d dlm	Z	 d dl
mZ d dlmZ G dd	 d	eZG d
d deZG dd deZG dd deZeZG dd deZdd Zdd Zdd ZdddZdS )    N)OrderedDict)total_ordering)chain)FieldDoesNotExist)models)format_html_joinc                   @   s   e Zd ZdZdd ZdS )Sequencea  
    Represents a column sequence, e.g. ``('first_name', '...', 'last_name')``

    This is used to represent `.Table.Meta.sequence` or the `.Table`
    constructors's *sequence* keyword argument.

    The sequence must be a list of column names and is used to specify the
    order of the columns on a table. Optionally a '...' item can be inserted,
    which is treated as a *catch-all* for column names that are not explicitly
    specified.
    c                 C   s   |  d}|dkrtd|dkr| d t|}g }g }|}| D ]}|dkr+|}q"|| ||v r<||| q"t|||| dd< | S )aR  
        Expands the ``'...'`` item in the sequence into the appropriate column
        names that should be placed there.

        arguments:
            columns (list): list of column names.
        returns:
            The current instance.

        raises:
            `ValueError` if the sequence is invalid for the columns.
        z...   z.'...' must be used at most once in a sequence.r   N)count
ValueErrorappendlistpopindexr   )selfcolumnsellipsesheadtailtargetname r   K/var/www/ideatree/venv/lib/python3.10/site-packages/django_tables2/utils.pyexpand   s&   


zSequence.expandN)__name__
__module____qualname____doc__r   r   r   r   r   r      s    r   c                       s\   e Zd ZdZdZ fddZedd Zedd Zed	d
 Z	edd Z
dd Z  ZS )OrderByz}
    A single item in an `.OrderByTuple` object.

    This class is essentially just a `str` with some extra properties.
    __c                    s6   t  | |}tj|v rd|}tj|tdd |S NzvUse '__' to separate path components, not '.' in accessor '{}' (fallback will be removed in django_tables2 version 3).   )
stacklevel)super__new__AccessorLEGACY_SEPARATORformatwarningswarnDeprecationWarningclsvalueinstancemessage	__class__r   r   r$   G   s   
zOrderBy.__new__c                 C   s$   | dd dkrt | dd S | S )z
        Returns:
            `.OrderBy`: the bare form.

        The *bare form* is the non-prefixed form. Typically the bare form is
        just the ascending form.

        Example: ``age`` is the bare form of ``-age``

        Nr	   -)r   r   r   r   r   bareS   s   $zOrderBy.barec                 C   s"   | j rt| dd S td|  S )a  
        Provides the opposite of the current sorting direction.

        Returns:
            `.OrderBy`: object with an opposite sort influence.

        Example::

            >>> order_by = OrderBy('name')
            >>> order_by.opposite
            '-name'

        r	   Nr2   )is_descendingr   r3   r   r   r   oppositea   s   "zOrderBy.oppositec                 C   s
   |  dS )zN
        Returns `True` if this object induces *descending* ordering.
        r2   )
startswithr3   r   r   r   r5   r   s   
zOrderBy.is_descendingc                 C   s   | j  S )zM
        Returns `True` if this object induces *ascending* ordering.
        )r5   r3   r   r   r   is_ascendingy   s   zOrderBy.is_ascendingc                 C   s   |  tjtjS )zf
        Returns the current instance usable in Django QuerySet's order_by
        arguments.
        )replacer%   r&   r   QUERYSET_SEPARATORr3   r   r   r   for_queryset   s   zOrderBy.for_queryset)r   r   r   r   r:   r$   propertyr4   r6   r5   r8   r;   __classcell__r   r   r0   r   r   >   s    



r   c                       s\   e Zd ZdZ fddZdd Zdd Z fdd	Zed
d Z	dd Z
edd Z  ZS )OrderByTuplea  
    Stores ordering as (as `.OrderBy` objects).

    The `~.Table.order_by` property is always converted to an `.OrderByTuple` object.
    This class is essentially just a `tuple` with some useful extras.

    Example::

        >>> x = OrderByTuple(('name', '-age'))
        >>> x['age']
        '-age'
        >>> x['age'].is_descending
        True
        >>> x['age'].opposite
        'age'

    c                    s8   g }|D ]}t |tst|}|| qt | |S N)
isinstancer   r   r#   r$   )r,   iterabletransformeditemr0   r   r   r$      s   
zOrderByTuple.__new__c                 C   s
   d | S )N,)joinr3   r   r   r   __str__      
zOrderByTuple.__str__c                 C   s(   t |j}| D ]
}|j|kr dS qdS )a  
        Determine if a column has an influence on ordering.

        Example::

            >>> x = OrderByTuple(('name', ))
            >>> 'name' in  x
            True
            >>> '-name' in x
            True

        Arguments:
            name (str): The name of a column. (optionally prefixed)

        Returns:
            bool: `True` if the column with `name` influences the ordering.
        TF)r   r4   )r   r   order_byr   r   r   __contains__   s   

zOrderByTuple.__contains__c                    s>   t |tr| D ]}||ks|j|kr|  S qtt |S )a  
        Allows an `.OrderBy` object to be extracted via named or integer
        based indexing.

        When using named based indexing, it's fine to used a prefixed named::

            >>> x = OrderByTuple(('name', '-age'))
            >>> x[0]
            'name'
            >>> x['age']
            '-age'
            >>> x['-age']
            '-age'

        Arguments:
            index (int): Index to query the ordering for.

        Returns:
            `.OrderBy`: for the ordering at the index.
        )r@   strr4   KeyErrorr#   __getitem__)r   r   rH   r0   r   r   rL      s   
zOrderByTuple.__getitem__c                    sJ   g  g | D ]}  t|j  |j qtG  fddd}|S )Nc                       s.   e Zd Zdd Z fddZ fddZdS )z$OrderByTuple.key.<locals>.Comparatorc                 S   s
   || _ d S r?   )obj)r   rM   r   r   r   __init__   rG   z-OrderByTuple.key.<locals>.Comparator.__init__c                    s<    D ]}|j | jdd}|j |jdd}||ks dS qdS NTquietF)resolverM   )r   otheraccessorab)	accessorsr   r   __eq__   s   z+OrderByTuple.key.<locals>.Comparator.__eq__c              	      s   t  D ]^\}}|j| jdd}|j|jdd}||krq|r%||}}z||k W   S  tyc   t|t|urGt|t|k  Y   S t|}t|}t|t|ft|t|fk  Y   S w dS rO   )ziprR   rM   	TypeErrorbooltypereprid)r   rS   rT   reverserU   rV   a_typeb_typerW   	reversingr   r   __lt__   s"   
(z+OrderByTuple.key.<locals>.Comparator.__lt__N)r   r   r   rN   rX   rd   r   rb   r   r   
Comparator   s    re   )r   r%   r4   r5   r   )r   rH   re   r   rb   r   key   s   %zOrderByTuple.keyc              	   C   s&   z| | W S  t tfy   | Y S w )zJ
        Identical to `__getitem__`, but supports fallback value.
        )rK   
IndexError)r   rf   fallbackr   r   r   get
  s
   
zOrderByTuple.getc                 C   s   t | dd | D S )z
        Return version with each `.OrderBy` prefix toggled::

            >>> order_by = OrderByTuple(('name', '-age'))
            >>> order_by.opposite
            ('-name', 'age')
        c                 s   s    | ]}|j V  qd S r?   )r6   ).0or   r   r   	<genexpr>  s    z(OrderByTuple.opposite.<locals>.<genexpr>)r\   r3   r   r   r   r6     s   	zOrderByTuple.opposite)r   r   r   r   r$   rF   rI   rL   r<   rf   ri   r6   r=   r   r   r0   r   r>      s    
/	r>   c                       sX   e Zd ZdZdZdZdZdZ fddZdd
dZ	e
dd Zdd ZdddZ  ZS )r%   a  
    A string describing a path from one object to another via attribute/index
    accesses. For convenience, the class has an alias `.A` to allow for more concise code.

    Relations are separated by a ``__`` character.

    To support list-of-dicts from ``QuerySet.values()``, if the context is a dictionary,
    and the accessor is a key in the dictionary, it is returned right away.
    .r   z9Refusing to call {method}() because `.alters_data = True`zRFailed lookup for key [{key}] in {context}, when resolving the accessor {accessor}c                    s>   t  | |}| j|v r| j|_d|}tj|tdd |S r    )r#   r$   r&   	SEPARATORr'   r(   r)   r*   r+   r0   r   r   r$   2  s   
zAccessor.__new__TFc                 C   s>  t |tr| |v r||  S z|}| jD ]{}z|| }W nJ tttfye   zt||}W n6 ttfyb   z|t| }W n" tt	ttfy_   t |t
jrRt|n|}t	| jj||| dw Y nw Y nw t|r|r}t|ddr}t	| jjt|dt|dds| }|du r |W S q|W S  ty   |s Y dS w )a  
        Return an object described by the accessor by traversing the attributes of *context*.

        Lookups are attempted in the following order:

         - dictionary (e.g. ``obj[related]``)
         - attribute (e.g. ``obj.related``)
         - list-index lookup (e.g. ``obj[int(related)]``)

        Callable objects are called, and their result is used, before
        proceeding with the resolving.

        Example::

            >>> x = Accessor("__len__")
            >>> x.resolve("brad")
            4
            >>> x = Accessor("0__upper")
            >>> x.resolve("brad")
            "B"

        If the context is a dictionary and the accessor-value is a key in it,
        the value for that key is immediately returned::

            >>> x = Accessor("user__first_name")
            >>> x.resolve({"user__first_name": "brad"})
            "brad"


        Arguments:
            context : The root/first object to traverse.
            safe (bool): Don't call anything with `alters_data = True`
            quiet (bool): Smother all exceptions and instead return `None`

        Returns:
            target object

        Raises:
            TypeError`, `AttributeError`, `KeyError`, `ValueError`
            (unless `quiet` == `True`)
        )rf   contextrT   alters_dataF)methoddo_not_call_in_templatesN)r@   dictbitsrZ   AttributeErrorrK   getattrintrg   r   r   Modelr\   LOOKUP_ERROR_FMTr'   callableALTERS_DATA_ERROR_FMTr]   	Exception)r   ro   saferQ   currentbitcurrent_contextr   r   r   rR   @  s\   ,

zAccessor.resolvec                 C   s   | dkrdS |  | jS )N r   )splitrn   r3   r   r   r   rt     s   zAccessor.bitsc              	   C   sl   t |dsdS d}| jD ]'}z|j|}W n ty!   Y  |S w t |dr3t|dd}t|d|}q|S )zZ
        Return the django model field for model in context, following relations.
        _metaNremote_fieldmodel)hasattrrt   r   	get_fieldr   rv   )r   r   fieldr   relr   r   r   r     s   


zAccessor.get_fieldc                 C   s(   |  | j\}}}t|j||d|fS )a*  
        Split the accessor on the right-most separator ('__'), return a tuple with:
         - the resolved left part.
         - the remainder

        Example::

            >>> Accessor("a__b__c").penultimate({"a": {"a": 1, "b": {"c": 2, "d": 4}}})
            ({"c": 2, "d": 4}, "c")

        rP   )
rpartitionrn   ArR   )r   ro   rQ   path_	remainderr   r   r   penultimate  s   zAccessor.penultimate)TF)T)r   r   r   r   r&   rn   r{   ry   r$   rR   r<   rt   r   r   r=   r   r   r0   r   r%     s    

X
r%   c                   @   s$   e Zd ZdZdZdd Zdd ZdS )AttributeDicta$  
    A wrapper around `collections.OrderedDict` that knows how to render itself
    as HTML style tag attributes.

    Any key with ``value is None`` will be skipped.

    The returned string is marked safe, so it can be used safely in a template.
    See `.as_html` for a usage example.
    )thtd	_orderingtheadtbodytfootc                 c   sF    |   D ]\}}t|r| n|}|| jvr |d ur ||fV  qd S r?   )itemsrz   	blacklist)r   rf   vr-   r   r   r   
_iteritems  s   
zAttributeDict._iteritemsc                 C   s   t dd|  S )ay  
        Render to HTML tag attributes.

        Example:

        .. code-block:: python

            >>> from django_tables2.utils import AttributeDict
            >>> attrs = AttributeDict({'class': 'mytable', 'id': 'someid'})
            >>> attrs.as_html()
            'class="mytable" id="someid"'

        returns: `~django.utils.safestring.SafeUnicode` object

         z{}="{}")r   r   r3   r   r   r   as_html  s   zAttributeDict.as_htmlN)r   r   r   r   r   r   r   r   r   r   r   r     s
    
r   c           
      c   s    | s|sdS |  D ]R\}}|t|t|jt|ji}|  D ];\}}t| dt| t|kr\t|}||= | t|d }|rVt||D ]}	tt	|g|	V  qIq!t|gV  q!qdS )a  
    Translates a flat sequence of items into a set of prefixed aliases.

    This allows the value set by `.QuerySet.order_by` to be translated into
    a list of columns that would have the same result. These are called
    "order by aliases" which are optionally prefixed column names::

        >>> list(segment(('a', '-b', 'c'),
        ...              {'x': ('a'),
        ...               'y': ('b', '-c'),
        ...               'z': ('-b', 'c')}))
        [('x', '-y'), ('x', 'z')]

    N)
r   r>   r   r6   r   lenrs   segmenttupler   )
sequencealiasesaliaspartsvariantsvaliasvpartstail_aliasestail_sequencer   r   r   r   r     s(   r   c                 C   s\   t | }g }d}|j D ]}|j|jkr|j}q|j|jkr!q||j qt	||fS )z
    Returns:
        tuple: Returns a (arguments, kwarg_name)-tuple:
             - the arguments (positional or keyword)
             - the name of the ** kwarg catch all.

    The self-argument for methods is always removed.
    N)
inspect	signature
parametersvalueskindVAR_KEYWORDr   VAR_POSITIONALr   r   )fnr   argskeywordsargr   r   r   r     s   

r   c                    sL   t | \ }|s fddD tfdd D rdS | di S )aE  
    Calls the function ``fn`` with the keyword arguments from ``kwargs`` it expects

    If the kwargs argument is defined, pass all arguments, else provide exactly
    the arguments wanted.

    If one of the arguments of ``fn`` are not contained in kwargs, ``fn`` will not
    be called and ``None`` will be returned.
    c                    s   i | ]}| v r|| qS r   r   )rj   rf   r   kwargsr   r   
<dictcomp>6  s    z)call_with_appropriate.<locals>.<dictcomp>c                 3   s    | ]}| vV  qd S r?   r   )rj   r   r   r   r   rl   9  s    z(call_with_appropriate.<locals>.<genexpr>Nr   )r   any)r   r   kwargs_namer   r   r   call_with_appropriate)  s   
r   c                 C   sT   |pi }i }|   D ]\}}t|rt||d}t|tr#t||d}|||< q
|S )a#  
    Returns a new `dict` that has callable values replaced with the return values.

    Example::

        >>> compute_values({'foo': lambda: 'bar'})
        {'foo': 'bar'}

    Arbitrarily deep structures are supported. The logic is as follows:

    1. If the value is callable, call it and make that the new value.
    2. If the value is an instance of dict, use ComputableDict to compute its keys.

    Example::

        >>> def parents():
        ...     return {
        ...         'father': lambda: 'Foo',
        ...         'mother': 'Bar'
        ...      }
        ...
        >>> a = {
        ...     'name': 'Brad',
        ...     'parents': parents
        ... }
        ...
        >>> computed_values(a)
        {'name': 'Brad', 'parents': {'father': 'Foo', 'mother': 'Bar'}}

    Arguments:
        d (dict): The original dictionary.
        kwargs: any extra keyword arguments will be passed to the callables, if the callable
            takes an argument with such a name.

    Returns:
        dict: with callable values replaced.
    r   )r   rz   r   r@   rs   computed_values)dr   resultkr   r   r   r   r   ?  s   &

r   r?   )r   r(   collectionsr   	functoolsr   	itertoolsr   django.core.exceptionsr   	django.dbr   django.utils.htmlr   r   r   rJ   r   r   r>   r%   r   r   r   r   r   r   r   r   r   r   <module>   s(    2J  $&%