a
    |fOo                     @   s  d 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mZmZmZmZmZmZmZmZmZmZ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"m#Z#m$Z$ erd
dl%m&Z& dZ'e(dZ)e(dZ*e(dZ+e(dZ,e(dZ-G dd de.ej/Z0G dd de0Z1G dd de0Z2G dd de0Z3G dd de0Z4G dd de0Z5G dd  d e0Z6G d!d" d"e0Z7G d#d$ d$e0Z8G d%d& d&e0Z9G d'd( d(e0Z:G d)d* d*e0Z;G d+d, d,e0Z<eed-d.d/Z=eed-d0d1Z>eed-d2d3Z?ed4Z@ee@geAf ee@ e@d5d6d7ZBdee eAeeAeeeCeDef  d:d;d<ZEd8d9d8g fee eAeeAeeC eeeeCeDef   d=d>d?ZFeCeCe.d@dAdBZGe.eeCeCf dCdDdEZHeeCeDf ZIe.eeIeIf dCdFdGZJde.eeC ee.eCf dHdIdJZKe.eCdKdLdMZLedNe@f edNe@f dOdPdQZMe.e.dRdSdTZNe.e.dUdVdWZOdee eCeee dXdYdZZPdeee  eeC eeC eeee  d[d\d]ZQed^ eeee.   d_d`daZRde.e.e.e.dcdddeZde.ee. e.dfdgdhZSeeAdidjdkZTee.ef eee  eCeCeee  dldmdnZUe.ee.eDf dodpdqZVdeDeDeDe.dsdtduZWe.eAdvdwdxZXe.e.dvdydzZYg g gfee eee  eee.ee.eCeDf f  d{d|d}ZZe[d~krddl\Z\e\]  dS )zG
gspread.utils
~~~~~~~~~~~~~

This module contains utility functions.

    N)defaultdict)Sequence)wraps)chain)TYPE_CHECKINGAnyAnyStrCallableDictIterableListMappingOptionalTupleTypeVarUnion)quote)Credentials   )IncorrectCellLabelInvalidInputValueNoValidUrlKeyFound)Cell@   z([A-Za-z]+)([1-9]\d*)z([A-Za-z]+)?([1-9]\d*)?$z[A-Za-z]+\d+:[A-Za-z]+\d+zkey=([^&#]+)z /spreadsheets/d/([a-zA-Z0-9-_]+)c                       s,   e Zd Z fddZdd Zdd Z  ZS )StrEnumc                    sD   t |ttjfs(td|dt| t j| |g|R i |S )Nz$Values of StrEnums must be strings: z is a )
isinstancestrenumauto	TypeErrortypesuper__new__)clsvalueargskwargs	__class__ GD:\Projects\storyit_web\backend\venv\Lib\site-packages\gspread/utils.pyr"   3   s
    zStrEnum.__new__c                 C   s
   t | jS N)r   r$   )selfr)   r)   r*   __str__:   s    zStrEnum.__str__c                 G   s   | S r+   r)   )name_r)   r)   r*   _generate_next_value_=   s    zStrEnum._generate_next_value_)__name__
__module____qualname__r"   r-   r0   __classcell__r)   r)   r'   r*   r   2   s   r   c                   @   s   e Zd ZdZdZdS )	DimensionZROWSCOLUMNSN)r1   r2   r3   rowscolsr)   r)   r)   r*   r5   A   s   r5   c                   @   s   e Zd ZdZdZdZdS )	MergeTypeZ	MERGE_ALLZMERGE_COLUMNSZ
MERGE_ROWSN)r1   r2   r3   Z	merge_allZmerge_columnsZ
merge_rowsr)   r)   r)   r*   r9   F   s   r9   c                   @   s   e Zd ZdZdZdZdS )ValueRenderOptionZFORMATTED_VALUEZUNFORMATTED_VALUEZFORMULAN)r1   r2   r3   	formattedZunformattedformular)   r)   r)   r*   r:   L   s   r:   c                   @   s   e Zd ZdZdZdS )ValueInputOptionZRAWZUSER_ENTEREDN)r1   r2   r3   rawZuser_enteredr)   r)   r)   r*   r=   R   s   r=   c                   @   s   e Zd ZdZdZdS )InsertDataOptionZ	OVERWRITEZINSERT_ROWSN)r1   r2   r3   	overwriteZinsert_rowsr)   r)   r)   r*   r?   W   s   r?   c                   @   s   e Zd ZdZdZdS )DateTimeOptionZSERIAL_NUMBERZFORMATTED_STRINGN)r1   r2   r3   Zserial_numberZformatted_stringr)   r)   r)   r*   rA   \   s   rA   c                   @   s(   e Zd ZdZdZdZdZdZdZdZ	dS )	MimeTypez'application/vnd.google-apps.spreadsheetzapplication/pdfzAapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetztext/csvz.application/vnd.oasis.opendocument.spreadsheetztext/tab-separated-valueszapplication/zipN)
r1   r2   r3   Zgoogle_sheetspdfexcelcsvopen_office_sheettsvzipr)   r)   r)   r*   rB   a   s   rB   c                   @   s0   e Zd ZejZejZejZ	ej
ZejZejZdS )ExportFormatN)r1   r2   r3   rB   rC   ZPDFrD   ZEXCELrE   ZCSVrF   ZOPEN_OFFICE_SHEETrG   ZTSVrH   ZZIPPED_HTMLr)   r)   r)   r*   rI   k   s   rI   c                   @   s(   e Zd ZdZdZdZdZdZdZdZ	dS )	PasteTypeZPASTE_NORMALZPASTE_VALUESZPASTE_FORMATZPASTE_NO_BORDERSZPASTE_DATA_VALIDATIONZPASTE_CONDITIONAL_FORMATTINGN)
r1   r2   r3   normalvaluesformatZ
no_bordersr<   Zdata_validationZconditional_formatingr)   r)   r)   r*   rJ   t   s   rJ   c                   @   s   e Zd ZdZdZdS )PasteOrientationZNORMALZ	TRANSPOSEN)r1   r2   r3   rK   Z	transposer)   r)   r)   r*   rN   ~   s   rN   c                   @   s   e Zd ZdZdZdS )GridRangeType
ValueRangeListOfListsN)r1   r2   r3   rP   rQ   r)   r)   r)   r*   rO      s   rO   c                   @   s   e 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dZdZdZ dZ!d Z"d!S )"ValidationConditionTypeZNUMBER_GREATERZNUMBER_GREATER_THAN_EQZNUMBER_LESSZNUMBER_LESS_THAN_EQZ	NUMBER_EQZNUMBER_NOT_EQZNUMBER_BETWEENZNUMBER_NOT_BETWEENZTEXT_CONTAINSZTEXT_NOT_CONTAINSZTEXT_STARTS_WITHZTEXT_ENDS_WITHZTEXT_EQZTEXT_IS_EMAILZTEXT_IS_URLZDATE_EQZDATE_BEFOREZ
DATE_AFTERZDATE_ON_OR_BEFOREZDATE_ON_OR_AFTERZDATE_BETWEENZDATE_NOT_BETWEENZDATE_IS_VALIDZONE_OF_RANGEZONE_OF_LISTZBLANKZ	NOT_BLANKZCUSTOM_FORMULABOOLEANZTEXT_NOT_EQZDATE_NOT_EQZFILTER_EXPRESSIONN)#r1   r2   r3   Znumber_greaterZnumber_greater_than_eqZnumber_lessZnumber_less_than_eqZ	number_eqZnumber_not_eqZnumber_betweenZnumber_not_betweenZtext_containsZtext_not_containsZtext_starts_withZtext_ends_withZtext_eqZtext_is_emailZtext_is_urlZdate_eqZdate_beforeZ
date_afterZdate_on_or_beforeZdate_on_or_afterZdate_betweenZdate_not_betweenZdate_is_validZone_of_rangeZone_of_listblankZ	not_blankZcustom_formulabooleanZtext_not_eqZdate_not_eqZfilter_expressionr)   r)   r)   r*   rR      s@   rR   )credentialsreturnc                 C   sX   | j }| jj}d|v r&|dkr&t| S d|v r>|dv r>t| S t| trL| S tdd S )NZoauth2clientServiceAccountCredentials)ZOAuth2CredentialsZAccessTokenCredentialsZGoogleCredentialszDCredentials need to be from either oauth2client or from google-auth.)r2   r(   r1   _convert_service_account_convert_oauthr   r   r   )rV   moduler#   r)   r)   r*   convert_credentials   s    
r\   c                 C   s"   t | j| j| j| j| j| j| jS r+   )UserCredentialsZaccess_tokenZrefresh_tokenZid_token	token_uriZ	client_idZclient_secretscopes)rV   r)   r)   r*   rZ      s    rZ   c                 C   s0   | j }| j|d< | j p ddg}tj||dS )Nr^   z%https://www.googleapis.com/auth/drivez%https://spreadsheets.google.com/feeds)r_   )Zserialization_datar^   Z_scopessplitrX   Zfrom_service_account_info)rV   datar_   r)   r)   r*   rY      s    

rY   T)funcseqrW   c                    s   t  fdd|D S )zFFinds and returns first item in iterable for which func(item) is True.c                 3   s   | ]} |r|V  qd S r+   r)   ).0itemrc   r)   r*   	<genexpr>       zfinditem.<locals>.<genexpr>)next)rc   rd   r)   rg   r*   finditem   s    rk   F )r$   
empty2zerodefault_blank%allow_underscores_in_numeric_literalsrW   c                 C   s   | }t | trd| v r*|s| S | dd} | dd}zt|}W nH ty   zt|}W n( ty   | dkr|r|d}n|}Y n0 Y n0 |S )a  Returns a value that depends on the input:

        - Float if input is a string that can be converted to Float
        - Integer if input is a string that can be converted to integer
        - Zero if the input is a string that is empty and empty2zero flag is set
        - The unmodified input value, otherwise.

    Examples::

        >>> numericise("faa")
        'faa'

    >>> numericise("3")
    3

    >>> numericise("3_2", allow_underscores_in_numeric_literals=False)
    '3_2'

    >>> numericise("3_2", allow_underscores_in_numeric_literals=True)
    32

    >>> numericise("3.1")
    3.1

    >>> numericise("2,000.1")
    2000.1

    >>> numericise("", empty2zero=True)
    0

    >>> numericise("", empty2zero=False)
    ''

    >>> numericise("", default_blank=None)
    >>>

    >>> numericise("", default_blank="foo")
    'foo'

    >>> numericise("")
    ''

    >>> numericise(None)
    >>>
    r/   rl   ,r   )r   r   replaceint
ValueErrorfloat)r$   rm   rn   ro   ZnumericisedZcleaned_valuer)   r)   r*   
numericise   s$    3
ru   )rL   rm   rn   ro   ignorerW   c                    s.   pg  fddt tD }|S )aK  Returns a list of numericised values from strings except those from the
    row specified as ignore.

    :param list values: Input row
    :param bool empty2zero: (optional) Whether or not to return empty cells
        as 0 (zero). Defaults to ``False``.
    :param str default_blank: Which value to use for blank cells,
        defaults to empty string.
    :param bool allow_underscores_in_numeric_literals: Whether or not to allow
        visual underscores in numeric literals
    :param list ignore: List of ints of indices of the row (index 1) to ignore
        numericising.
    c                    s4   g | ],}|d  v r| nt |  dqS )r   )rm   rn   ro   )ru   )re   indexro   rn   rm   rv   rL   r)   r*   
<listcomp>?  s   

z"numericise_all.<locals>.<listcomp>)rangelen)rL   rm   rn   ro   rv   Znumericised_listr)   rx   r*   numericise_all(  s
    
r|   )rowcolrW   c                 C   sp   | dk s|dk r t d| ||}d}|r`t|d\}}|dkrNd}|d8 }t|t | }q(d|| }|S )a  Translates a row and column cell address to A1 notation.

    :param row: The row of the cell to be converted.
        Rows start at index 1.
    :type row: int, str

    :param col: The column of the cell to be converted.
        Columns start at index 1.
    :type row: int, str

    :returns: a string containing the cell's coordinates in A1 notation.

    Example:

    >>> rowcol_to_a1(1, 1)
    A1

    r   z({}, {})rl      r   z{}{})r   rM   divmodchrMAGIC_NUMBER)r}   r~   divcolumn_labelmodlabelr)   r)   r*   rowcol_to_a1P  s    r   )r   rW   c                 C   sn   t | }|r^|d }t|d}d}tt|D ] \}}|t|t d|  7 }q:nt	| ||fS )aT  Translates a cell's address in A1 notation to a tuple of integers.

    :param str label: A cell label in A1 notation, e.g. 'B1'.
        Letter case is ignored.
    :returns: a tuple containing `row` and `column` numbers. Both indexed
              from 1 (one).
    :rtype: tuple

    Example:

    >>> a1_to_rowcol('A1')
    (1, 1)

    r      r   r   )
CELL_ADDR_REmatchgroupupperrr   	enumeratereversedordr   r   r   mr   r}   r~   icr)   r)   r*   a1_to_rowcolu  s    
r   c                 C   s   t | }|rv| \}}|rVd}tt| D ] \}}|t|t d|  7 }q2ntd}|rlt	|}q~td}nt
| ||fS )a1  Translates a cell's address in A1 notation to a tuple of integers.

    Same as `a1_to_rowcol()` but allows for missing row or column part
    (e.g. "A" for the first column)

    :returns: a tuple containing `row` and `column` numbers. Both indexed
        from 1 (one).
    :rtype: tuple

    Example:

    >>> _a1_to_rowcol_unbounded('A1')
    (1, 1)

    >>> _a1_to_rowcol_unbounded('A')
    (inf, 1)

    >>> _a1_to_rowcol_unbounded('1')
    (1, inf)

    >>> _a1_to_rowcol_unbounded('ABC123')
    (123, 731)

    >>> _a1_to_rowcol_unbounded('ABC')
    (inf, 731)

    >>> _a1_to_rowcol_unbounded('123')
    (123, inf)

    >>> _a1_to_rowcol_unbounded('1A')
    Traceback (most recent call last):
        ...
    gspread.exceptions.IncorrectCellLabel: 1A

    >>> _a1_to_rowcol_unbounded('')
    (inf, inf)

    r   r   inf)A1_ADDR_ROW_COL_REr   groupsr   r   r   r   r   rt   rr   r   r   r)   r)   r*   _a1_to_rowcol_unbounded  s    '


r   )r.   sheet_idrW   c                 C   s   |  d\}}}t|\}}t|p$|\}}||kr>|| }}||krP|| }}|d ||d |d}	dd |	 D }
|dur||
d< |
S )a2  Converts a range defined in A1 notation to a dict representing
    a `GridRange`_.

    All indexes are zero-based. Indexes are half open, e.g the start
    index is inclusive and the end index is exclusive: [startIndex, endIndex).

    Missing indexes indicate the range is unbounded on that side.

    .. _GridRange: https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#GridRange

    Examples::

        >>> a1_range_to_grid_range('A1:A1')
        {'startRowIndex': 0, 'endRowIndex': 1, 'startColumnIndex': 0, 'endColumnIndex': 1}

    >>> a1_range_to_grid_range('A3:B4')
    {'startRowIndex': 2, 'endRowIndex': 4, 'startColumnIndex': 0, 'endColumnIndex': 2}

    >>> a1_range_to_grid_range('A:B')
    {'startColumnIndex': 0, 'endColumnIndex': 2}

    >>> a1_range_to_grid_range('A5:B')
    {'startRowIndex': 4, 'startColumnIndex': 0, 'endColumnIndex': 2}

    >>> a1_range_to_grid_range('A1')
    {'startRowIndex': 0, 'endRowIndex': 1, 'startColumnIndex': 0, 'endColumnIndex': 1}

    >>> a1_range_to_grid_range('A')
    {'startColumnIndex': 0, 'endColumnIndex': 1}

    >>> a1_range_to_grid_range('1')
    {'startRowIndex': 0, 'endRowIndex': 1}

    >>> a1_range_to_grid_range('A1', sheet_id=0)
    {'sheetId': 0, 'startRowIndex': 0, 'endRowIndex': 1, 'startColumnIndex': 0, 'endColumnIndex': 1}
    :r   )startRowIndexendRowIndexstartColumnIndexendColumnIndexc                 S   s    i | ]\}}t |tr||qS r)   r   rr   )re   keyr$   r)   r)   r*   
<dictcomp>
  s   z*a1_range_to_grid_range.<locals>.<dictcomp>NZsheetId)	partitionr   items)r.   r   Zstart_labelr/   Z	end_labelstart_row_indexZstart_column_indexZend_row_indexZend_column_indexZ
grid_rangeZfiltered_grid_ranger)   r)   r*   a1_range_to_grid_range  s$    %

r   )columnrW   c                 C   sN   zt | \}}W n  ty0   td| Y n0 t|tsJtd| |S )aT  Converts a column letter to its numerical index.

    This is useful when using the method :meth:`gspread.worksheet.Worksheet.col_values`.
    Which requires a column index.

    This function is case-insensitive.

    Raises :exc:`gspread.exceptions.InvalidInputValue` in case of invalid input.

    Examples::

        >>> column_letter_to_index("a")
        1

    >>> column_letter_to_index("A")
    1

    >>> column_letter_to_index("AZ")
    52

    >>> column_letter_to_index("!@#$%^&")
    ...
    gspread.exceptions.InvalidInputValue: invalid value: !@#$%^&, must be a column letter
    z*invalid value: {}, must be a column letter)r   r   r   rM   r   rr   )r   r/   rw   r)   r)   r*   column_letter_to_index  s    

r   .)methodrW   c                    s>   t tdf tddd tttttd fdd}|S )zYDecorator function casts wrapped arguments to A1 notation in range
    method calls.
    .)r%   rW   c                 S   s8   t | d to6t | d to6t | d to6t | d tS )Nr   r   r      r   )r%   r)   r)   r*   contains_row_colsC  s    z.cast_to_a1_notation.<locals>.contains_row_cols)r,   r%   r&   rW   c                    s   zXt |dkrV |rVt|d d  }t|dd  }d||f}|f|dd   }W n tyj   Y n0 | g|R i |S )N   r   r   )r{   r   joinrs   )r,   r%   r&   Zrange_startZ	range_end
range_namer   r   r)   r*   wrapperK  s    z$cast_to_a1_notation.<locals>.wrapper)r   r   boolr   )r   r   r)   r   r*   cast_to_a1_notation>  s    r   )urlrW   c                 C   s8   t | }|r|dS t| }|r0|dS td S )Nr   )URL_KEY_V2_REsearchr   URL_KEY_V1_REr   )r   m2m1r)   r)   r*   extract_id_from_url_  s    



r   )widrW   c                 C   sB   t | dkr| dd n| }t | dkr,dnd}tt|d|A S )z*Calculate gid of a worksheet from its wid.r   r   Ni  iZ{  $   )r{   r   rr   )r   ZwidvalZxorvalr)   r)   r*   
wid_to_gidk  s    r   )r}   max_lenpadding_valuerW   c                 C   s&   |t |  }|dkr"| |g|  S | S )Nr   r{   )r}   r   r   Zpad_lenr)   r)   r*   rightpadr  s    r   )Lr7   r8   r   rW   c                    s   zf|du rt dd | D n| |du r0t| n|}|t|  }|rR| g g|  }  fdd| D W S  ty~   g g Y S 0 dS )a7  Fill gaps in a list of lists.
    e.g.,::

        >>> L = [
        ... [1, 2, 3],
        ... ]
        >>> fill_gaps(L, 2, 4)
        [
            [1, 2, 3, ""],
            ["", "", "", ""]
        ]

    :param L: List of lists to fill gaps in.
    :param rows: Number of rows to fill.
    :param cols: Number of columns to fill.
    :param padding_value: Default value to fill gaps with.

    :type L: list[list[T]]
    :type rows: int
    :type cols: int
    :type padding_value: T

    :return: List of lists with gaps filled.
    :rtype: list[list[T]]:
    Nc                 s   s   | ]}t |V  qd S r+   r   re   r}   r)   r)   r*   rh     ri   zfill_gaps.<locals>.<genexpr>c                    s   g | ]}t | d qS ))r   )r   r   Zmax_colsr   r)   r*   ry     ri   zfill_gaps.<locals>.<listcomp>)maxr{   rs   )r   r7   r8   r   Zmax_rowsZpad_rowsr)   r   r*   	fill_gapsw  s    r   r   )	cell_listrW   c                    s   | sg S t ttdd | D }tdd | D }| D ]*}t|j| i }|j||j| < q8slg S t	dd 
 D }tt|d  tt d } fdd|D S )Nc                 s   s   | ]}|j V  qd S r+   )r}   re   r   r)   r)   r*   rh     ri   z$cell_list_to_rect.<locals>.<genexpr>c                 s   s   | ]}|j V  qd S r+   )r~   r   r)   r)   r*   rh     ri   c                 s   s   | ]}|  V  qd S r+   )keysr   r)   r)   r*   rh     ri   r   c                    s    g | ]  fd dD qS )c                    s   g | ]}   |qS r)   )get)re   j)r   r7   r)   r*   ry     ri   z0cell_list_to_rect.<locals>.<listcomp>.<listcomp>r)   )re   Z	rect_colsr7   )r   r*   ry     ri   z%cell_list_to_rect.<locals>.<listcomp>)r   dictmin
setdefaultrr   r}   r$   r~   r   from_iterablerL   rz   r   r   )r   
row_offset
col_offsetcellr}   Zall_row_keysZ	rect_rowsr)   r   r*   cell_list_to_rect  s    r   utf-8)r$   safeencodingrW   c                 C   s   t | ||S r+   )uquoteencode)r$   r   r   r)   r)   r*   r     s    r   )
sheet_namer   rW   c                 C   s*   d | dd} |r"d | |S | S dS )a  Return an absolutized path of a range.

    >>> absolute_range_name("Sheet1", "A1:B1")
    "'Sheet1'!A1:B1"

    >>> absolute_range_name("Sheet1", "A1")
    "'Sheet1'!A1"

    >>> absolute_range_name("Sheet1")
    "'Sheet1'"

    >>> absolute_range_name("Sheet'1")
    "'Sheet''1'"

    >>> absolute_range_name("Sheet''1")
    "'Sheet''''1'"

    >>> absolute_range_name("''sheet12''", "A1:B2")
    "'''''sheet12'''''!A1:B2"
    z'{}''z''z{}!{}N)rM   rq   )r   r   r)   r)   r*   absolute_range_name  s    r   )xrW   c                 C   s   t | tpt | t S )a1  Return True if the value is scalar.

    A scalar is not a sequence but can be a string.

    >>> is_scalar([])
    False

    >>> is_scalar([1, 2])
    False

    >>> is_scalar(42)
    True

    >>> is_scalar('nice string')
    True

    >>> is_scalar({})
    True

    >>> is_scalar(set())
    True
    )r   r   r   )r   r)   r)   r*   	is_scalar  s    r   )worksheet_metadatarL   r   start_col_indexrW   c                 C   s   |  dg }dd |D }t|d }t|d d }|D ]}|d |d  }	}
|d |d	  }}|	|8 }	|
|8 }
||8 }||8 }|	|ks:||krq:|	dk s:|dk rq:||	 | }t|	|
}t||}|D ],}|D ]"}||ks||krq||| |< qqq:|S )
a  For each merged region, replace all values with the value of the top-left cell of the region.
    e.g., replaces
    [
    [1, None, None],
    [None, None, None],
    ]
    with
    [
    [1, 1, None],
    [1, 1, None],
    ]
    if the top-left four cells are merged.

    :param worksheet_metadata: The metadata returned by the Google API for the worksheet.
        Should have a "merges" key.

    :param values: The values returned by the Google API for the worksheet. 2D array.

    :param start_row_index: The index of the first row of the values in the worksheet.
        e.g., if the values are in rows 3-5, this should be 2.

    :param start_col_index: The index of the first column of the values in the worksheet.
        e.g., if the values are in columns C-E, this should be 2.

    :returns: matrix of values with merged coordinates filled according to top-left value
    :rtype: list(list(any))
    mergesc                 S   s   g | ]}t |qS r)   )listr   r)   r)   r*   ry     ri   z)combined_merge_values.<locals>.<listcomp>r   r   r   r   r   r   )r   r{   rz   )r   rL   r   r   r   
new_valuesZmax_row_indexZmax_col_indexmergeZmerge_start_rowZmerge_end_rowZmerge_start_colZmerge_end_colZtop_left_valueZrow_indicesZcol_indicesZ	row_indexZ	col_indexr)   r)   r*   combined_merge_values  s4    !

r   )	hex_colorrW   c              
   C   s   |  d} t| dkr"| dd } t| dkrBddd | D } t| d	krVtd
zHt| dd dd t| dd dd t| dd	 dd d}|W S  ty } ztd|  |W Y d}~n
d}~0 0 dS )a  Convert a hex color code to RGB color values.

    :param str hex_color: Hex color code in the format "#RRGGBB".

    :returns: Dict containing the color's red, green and blue values between 0 and 1.
    :rtype: dict

    :raises:
        ValueError: If the input hex string is not in the correct format or length.

    Examples:
        >>> convert_hex_to_colors_dict("#3300CC")
        {'red': 0.2, 'green': 0.0, 'blue': 0.8}

        >>> convert_hex_to_colors_dict("#30C")
        {'red': 0.2, 'green': 0.0, 'blue': 0.8}

    #   Nr   rl   c                 S   s   g | ]}|d  qS )r   r)   )re   charr)   r)   r*   ry   ]  ri   z.convert_hex_to_colors_dict.<locals>.<listcomp>   z/Hex color code must be in the format '#RRGGBB'.r   r         r   )redgreenbluez(Invalid character in hex color string: #)lstripr{   r   rs   rr   )r   Z	rgb_colorexr)   r)   r*   convert_hex_to_colors_dict@  s    
r           )r   r   r   rW   c                 C   sN   t tddd}tdd | ||fD r0tdd||  || || S )a  Convert RGB color values to a hex color code.

    :param float red: Red color value (0-1).
    :param float green: Green color value (0-1).
    :param float blue: Blue color value (0-1).

    :returns: Hex color code in the format "#RRGGBB".
    :rtype: str

    :raises:
        ValueError: If any color value is out of the accepted range (0-1).

    Example:

        >>> convert_colors_to_hex_value(0.2, 0, 0.8)
        '#3300CC'

        >>> convert_colors_to_hex_value(green=0.5)
        '#008000'
    )r$   rW   c                 S   s&   t t| d dd }| dS )zG
        Convert an integer to a 2-digit uppercase hex string.
        r   r   N)hexroundr   zfill)r$   Z	hex_valuer)   r)   r*   to_hex  s    z+convert_colors_to_hex_value.<locals>.to_hexc                 s   s   | ]}|d k p|dkV  qdS )r   r   Nr)   )re   r$   r)   r)   r*   rh     ri   z.convert_colors_to_hex_value.<locals>.<genexpr>z&Color value out of accepted range 0-1.r   )rt   r   anyrs   )r   r   r   r   r)   r)   r*   convert_colors_to_hex_valuen  s    r   )r   rW   c                 C   s   t | duS )a  Check if the range name is a full A1 notation.
    "A1:B2", "Sheet1!A1:B2" are full A1 notations
    "A1:B", "A1" are not

    Args:
        range_name (str): The range name to check.

    Returns:
        bool: True if the range name is a full A1 notation, False otherwise.

    Examples:

        >>> is_full_a1_notation("A1:B2")
        True

        >>> is_full_a1_notation("A1:B")
        False
    N)A1_ADDR_FULL_REr   r   r)   r)   r*   is_full_a1_notation  s    r   c                 C   s   d| v r|  dd S | S )zGet the A1 notation from an absolute range name.
    "Sheet1!A1:B2" -> "A1:B2"
    "A1:B2" -> "A1:B2"

    Args:
        range_name (str): The range name to check.

    Returns:
        str: The A1 notation of the range name stripped of the sheet.
    !r   )r`   r   r)   r)   r*   get_a1_from_absolute_range  s    r   )headersrL   rW   c                    s    fdd|D S )a  Builds the list of dictionaries, all of them have the headers sequence as keys set,
    each key is associated to the corresponding value for the same index in each list from
    the matrix ``values``.
    There are as many dictionaries as they are entry in the list of given values.

    :param list: headers the key set for all dictionaries
    :param list: values a matrix of values

    Examples::

        >>> to_records(["name", "City"], [["Spiderman", "NY"], ["Batman", "Gotham"]])
        [
            {
                "Name": "Spiderman",
                "City": "NY",
            },
            {
                "Name": "Batman",
                "City": "Gotham",
            },
        ]
    c                    s   g | ]}t t |qS r)   )r   rH   r   r   r)   r*   ry     ri   zto_records.<locals>.<listcomp>r)   )r   rL   r)   r   r*   
to_records  s    r   __main__)Frl   F)N)rl   )NNrl   )rl   r   )N)r   r   r   )^__doc__r   recollectionsr   collections.abcr   	functoolsr   	itertoolsr   typingr   r   r   r	   r
   r   r   r   r   r   r   r   urllib.parser   r   Zgoogle.auth.credentialsr   Zgoogle.oauth2.credentialsr]   Zgoogle.oauth2.service_accountrX   
exceptionsr   r   r   r   r   r   compiler   r   r   r   r   r   Enumr   r5   r9   r:   r=   r?   rA   rB   rI   rJ   rN   rO   rR   r\   rZ   rY   rb   r   rk   rr   rt   ru   r|   r   r   ZIntOrInfr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r1   doctesttestmodr)   r)   r)   r*   <module>   s   8





	
#    M(%= B* !   

- 


F/ %:
