
    Ki`                     x   S r SSKrSSKrSSKJr  SSKJr  SSKJr  SSK	J
r
  SSKJrJrJrJrJrJrJrJrJrJrJrJr  SSKJr  SS	KJr  SS	KJr  SS	KJr   S
SK!J"r"J#r#J$r$  \(       a  S
SK%J&r&  Sr'\RP                  " S5      r)\RP                  " S5      r*\RP                  " S5      r+\RP                  " S5      r,\RP                  " S5      r- " S S\.\R^                  5      r0 " S S\05      r1 " S S\05      r2 " S S\05      r3 " S S\05      r4 " S S\05      r5 " S S \05      r6 " S! S"\05      r7 " S# S$\05      r8 " S% S&\05      r9 " S' S(\05      r: " S) S*\05      r; " S+ S,\05      r< " S- S.\05      r=S/\S0\4S1 jr>S/\S0\4S2 jr?S/\S0\4S3 jr@\" S45      rAS5\\A/\B4   S6\\A   S0\A4S7 jrC   S|S:\\   S;\BS<\S=\BS0\\\D\E\4      4
S> jjrFS8S9S8/ 4S?\\   S;\BS<\S=\BS@\\D   S0\\\\D\E\4         4SA jjrGSB\DSC\DS0\.4SD jrHSE\.S0\\D\D4   4SF jrI\\D\E4   rJSE\.S0\\J\J4   4SG jrKS}SH\.SI\\D   S0\\.\D4   4SJ jjrLSK\.S0\D4SL jrMSM\SN\A4   S0\SN\A4   4SO jrNSP\.S0\.4SQ jrOSR\.S0\.4SS jrPS~SB\\   ST\DSU\S0\\   4SV jjrQ   SSW\\\      SX\\D   SY\\D   SU\S0\\\      4
SZ jjrRS[\S\   S0\\\\.         4S] jrSSS:\.S^\.S_\.S0\.4S` jjrS}Sa\.Sb\\.   S0\.4Sc jjrTSd\S0\B4Se jrUSf\\.\4   S?\\\      Sg\DSh\DS0\\\      4
Si jrVSj\.S0\\.\E4   4Sk jrW SSl\ESm\ESn\ES0\.4So jjrXSb\.S0\B4Sp jrYSb\.S0\.4Sq jrZ/ / /4Sr\\   S?\\\      S0\\\.\\.\D\E4   4      4Ss jjr[S?\\\.      St\DSu\DSB\DS0\D4
Sv jr\S?\\\.      St\DSu\DSC\DS0\D4
Sw jr]\=R                  4S?\\\.      Sx\.Sy\=S0\\\.      4Sz jjr_\`S{:X  a  SSKara\aR                  " 5         gg)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                   4   ^  \ rS rSrU 4S jrS rS rSrU =r$ )StrEnum2   c                    > [        U[        [        R                  45      (       d  [	        SU< S[        U5       35      e[        TU ]  " X/UQ70 UD6$ )Nz$Values of StrEnums must be strings: z is a )
isinstancestrenumauto	TypeErrortypesuper__new__)clsvalueargskwargs	__class__s       `C:\Users\julio\OneDrive\Documentos\Trabajo\Ideas Frescas\venv\Lib\site-packages\gspread/utils.pyr&   StrEnum.__new__3   sU    %#tyy!1226uivd5k]S  ws;D;F;;    c                 ,    [        U R                  5      $ N)r    r(   )selfs    r,   __str__StrEnum.__str__:   s    4::r.   c                     U $ r0    )name_s     r,   _generate_next_value_StrEnum._generate_next_value_=   s    r.   r5   )	__name__
__module____qualname____firstlineno__r&   r2   r8   __static_attributes____classcell__)r+   s   @r,   r   r   2   s    < r.   r   c                       \ rS rSrSrSrSrg)	DimensionA   ROWSCOLUMNSr5   N)r:   r;   r<   r=   rowscolsr>   r5   r.   r,   rA   rA   A   s    DDr.   rA   c                        \ rS rSrSrSrSrSrg)	MergeTypeF   	MERGE_ALLMERGE_COLUMNS
MERGE_ROWSr5   N)r:   r;   r<   r=   	merge_allmerge_columns
merge_rowsr>   r5   r.   r,   rH   rH   F   s    I#MJr.   rH   c                        \ rS rSrSrSrSrSrg)ValueRenderOptionL   FORMATTED_VALUEUNFORMATTED_VALUEFORMULAr5   N)r:   r;   r<   r=   	formattedunformattedformular>   r5   r.   r,   rQ   rQ   L   s    !I%KGr.   rQ   c                       \ rS rSrSrSrSrg)ValueInputOptionR   RAWUSER_ENTEREDr5   N)r:   r;   r<   r=   rawuser_enteredr>   r5   r.   r,   rZ   rZ   R   s    
C!Lr.   rZ   c                       \ rS rSrSrSrSrg)InsertDataOptionW   	OVERWRITEINSERT_ROWSr5   N)r:   r;   r<   r=   	overwriteinsert_rowsr>   r5   r.   r,   ra   ra   W   s    IKr.   ra   c                       \ rS rSrSrSrSrg)DateTimeOption\   SERIAL_NUMBERFORMATTED_STRINGr5   N)r:   r;   r<   r=   serial_numberformatted_stringr>   r5   r.   r,   rh   rh   \   s    #M)r.   rh   c                   0    \ rS rSrSrSrSrSrSrSr	Sr
S	rg
)MimeTypea   z'application/vnd.google-apps.spreadsheetzapplication/pdfzAapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetztext/csvz.application/vnd.oasis.opendocument.spreadsheetztext/tab-separated-valueszapplication/zipr5   N)r:   r;   r<   r=   google_sheetspdfexcelcsvopen_office_sheettsvzipr>   r5   r.   r,   ro   ro   a   s&    =M
COE
CH
%C
Cr.   ro   c                       \ rS rSr\R
                  r\R                  r\R                  r
\R                  r\R                  r\R                  rSrg)ExportFormatk   r5   N)r:   r;   r<   r=   ro   rr   PDFrs   EXCELrt   CSVru   OPEN_OFFICE_SHEETrv   TSVrw   ZIPPED_HTMLr>   r5   r.   r,   ry   ry   k   s;    
,,CNNE
,,C 22
,,C,,Kr.   ry   c                   0    \ rS rSrSrSrSrSrSrSr	Sr
Srg	)
	PasteTypet   PASTE_NORMALPASTE_VALUESPASTE_FORMATPASTE_NO_BORDERSPASTE_DATA_VALIDATIONPASTE_CONDITIONAL_FORMATTINGr5   N)r:   r;   r<   r=   normalvaluesformat
no_bordersrX   data_validationconditional_formatingr>   r5   r.   r,   r   r   t   s&    FFF#J G-O:r.   r   c                       \ rS rSrSrSrSrg)PasteOrientation~   NORMAL	TRANSPOSEr5   N)r:   r;   r<   r=   r   	transposer>   r5   r.   r,   r   r   ~   s    FIr.   r   c                       \ rS rSrSrSrSrg)GridRangeType   
ValueRangeListOfListsr5   N)r:   r;   r<   r=   r   r   r>   r5   r.   r,   r   r      s    JKr.   r   c                       \ rS rSrSrSrSrSrSrSr	Sr
S	rS
rSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSrSr Sr!S r"S!r#S"r$g#)$ValidationConditionType   NUMBER_GREATERNUMBER_GREATER_THAN_EQNUMBER_LESSNUMBER_LESS_THAN_EQ	NUMBER_EQNUMBER_NOT_EQNUMBER_BETWEENNUMBER_NOT_BETWEENTEXT_CONTAINSTEXT_NOT_CONTAINSTEXT_STARTS_WITHTEXT_ENDS_WITHTEXT_EQTEXT_IS_EMAILTEXT_IS_URLDATE_EQDATE_BEFORE
DATE_AFTERDATE_ON_OR_BEFOREDATE_ON_OR_AFTERDATE_BETWEENDATE_NOT_BETWEENDATE_IS_VALIDONE_OF_RANGEONE_OF_LISTBLANK	NOT_BLANKCUSTOM_FORMULABOOLEANTEXT_NOT_EQDATE_NOT_EQFILTER_EXPRESSIONr5   N)%r:   r;   r<   r=   number_greaternumber_greater_than_eqnumber_lessnumber_less_than_eq	number_eqnumber_not_eqnumber_betweennumber_not_betweentext_containstext_not_containstext_starts_withtext_ends_withtext_eqtext_is_emailtext_is_urldate_eqdate_before
date_afterdate_on_or_beforedate_on_or_afterdate_betweendate_not_betweendate_is_validone_of_rangeone_of_listblank	not_blankcustom_formulabooleantext_not_eqdate_not_eqfilter_expressionr>   r5   r.   r,   r   r      s    %N5K/I#M%N-#M+)%NG#MKGKJ+)!L)#M!LKEI%NGKK+r.   r   c                        \ rS rSrSrSrSrSrg)TableDirection   TABLEDOWNRIGHTr5   N)r:   r;   r<   r=   tabledownrightr>   r5   r.   r,   r   r      s    EDEr.   r   credentialsreturnc                     U R                   nU R                  R                  nSU;   a  US:X  a  [        U 5      $ SU;   a  US;   a  [	        U 5      $ [        U [        5      (       a  U $ [        S5      e)Noauth2clientServiceAccountCredentials)OAuth2CredentialsAccessTokenCredentialsGoogleCredentialszDCredentials need to be from either oauth2client or from google-auth.)r;   r+   r:   _convert_service_account_convert_oauthr   r   r#   )r   moduler'   s      r,   convert_credentialsr      s}    ##F



(
(CC+F$F'44	6	!c . '
 k**	K	-	-
N r.   c           	          [        U R                  U R                  U R                  U R                  U R
                  U R                  U R                  5      $ r0   )UserCredentialsaccess_tokenrefresh_tokenid_token	token_uri	client_idclient_secretscopes)r   s    r,   r   r      sN      !!!! r.   c                     U R                   nU R                  US'   U R                  R                  5       =(       d    SS/n[        R
                  " XS9$ )Nr   z%https://www.googleapis.com/auth/drivez%https://spreadsheets.google.com/feeds)r   )serialization_datar   _scopessplitr   from_service_account_info)r   datar   s      r,   r   r      sT    ))D#--D  &&( //-F
 %>>tSSr.   Tfuncseqc                 .   ^  [        U 4S jU 5       5      $ )zFFinds and returns first item in iterable for which func(item) is True.c              3   F   >#    U  H  nT" U5      (       d  M  Uv   M     g 7fr0   r5   ).0itemr  s     r,   	<genexpr>finditem.<locals>.<genexpr>   s     3T
s   !	!)next)r  r  s   ` r,   finditemr     s    3333r.   F r(   
empty2zerodefault_blank%allow_underscores_in_numeric_literalsc                 @   U n[        U [        5      (       aA  SU ;   a  U(       d  U $ U R                  SS5      n U R                  SS5      n [        U5      nU$ U$ ! [         a8     [        U5      n U$ ! [         a    U S:X  a  U(       a  Sn O
Un  U$ f = f U$ f = f)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)
>>>
r7   r  ,r   )r   r    replaceint
ValueErrorfloat)r(   r  r  r  numericisedcleaned_values         r,   
numericiser     s    f 8=K%%<8MM#r*E c2.
	4m,K ;  	44#M2   4B;!&'&34 $ 	4s<   A 
B&A44BBBBBBBr   ignorec           
          U=(       d    / n[        [        U 5      5       Vs/ s H  nUS-   U;   a  X   O[        X   UUUS9PM      nnU$ s  snf )a  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 Any 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.
r   )r  r  r  )rangelenr  )r   r  r  r  r  indexnumericised_lists          r,   numericise_allr   .  st    * \rF 3v;' (E qyF" M%+6[	 (   s   %Arowcolc                     U S:  d  US:  a  [        SR                  X5      5      eUnSnU(       a9  [        US5      u  p$US:X  a  SnUS-  n[        U[        -   5      U-   nU(       a  M9  SR                  X05      nU$ )am  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({}, {})r     r   z{}{})r   r   divmodchrMAGIC_NUMBER)r!  r"  divcolumn_labelmodlabels         r,   rowcol_to_a1r,  V  s    & Qw#' !2!23!<==
CL
C_
!8C1HC3-.= # MM,,ELr.   r+  c                 <   [         R                  U 5      nU(       av  UR                  S5      R                  5       n[	        UR                  S5      5      nSn[        [        U5      5       H   u  pVU[        U5      [        -
  SU-  -  -  nM"     X44$ [        U 5      e)a0  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upperr  	enumeratereversedordr'  r   r+  mr)  r!  r"  ics          r,   a1_to_rowcolr:  {  s     	5!Awwqz'')!''!*oh|45DACF\)b!e44C 6
 : !''r.   c                 r   [         R                  U 5      nU(       a  UR                  5       u  p#U(       aI  Sn[        [	        UR                  5       5      5       H   u  pVU[        U5      [        -
  SU-  -  -  nM"     O[        S5      nU(       a  [        U5      nX44$ [        S5      n X44$ [        U 5      e)a  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_REr0  groupsr3  r4  r2  r5  r'  r  r  r   r6  s          r,   _a1_to_rowcol_unboundedr?    s    N 	  'AHHJ C!(<+=+=+?"@AA-"a%88 B ,Cc(C :	 ,C : !''r.   r6   sheet_idc                 :   U R                  S5      u  p#n[        U5      u  pV[        U=(       d    U5      u  pxXW:  a  XupuXh:  a  XpUS-
  UUS-
  US.n	U	R                  5        V
Vs0 s H  u  p[        U[        5      (       d  M  X_M      nn
nUb  XS'   U$ s  snn
f )a  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endColumnIndexsheetId)	partitionr?  itemsr   r  )r6   r@  start_labelr7   	end_labelstart_row_indexstart_column_indexend_row_indexend_column_index
grid_rangekeyr(   filtered_grid_ranges                r,   a1_range_to_grid_rangerS    s    J !%s 3KI*A+*N'O&=i>V;&W#M&)6,/?, )1,$.2*	J (2'7'7'9+'9|Zs=S

'9  + )1I&+s   &BBcolumnc                      [        U 5      u  p[	        U[
        5      (       d  [        SR                  U 5      5      eU$ ! [         a    [        SR                  U 5      5      ef = f)a  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   r   r   r  )rT  r7   r  s      r,   column_letter_to_indexrV    sr    2
,V4
 eS!!8??G
 	
 L  
  8??G
 	

s   A   %A%method.c           	         ^ ^ S[         [        S4   S[        4S jm[        T 5      S[        S[        S[        S[        4UU 4S jj5       nU$ )zQDecorator function casts wrapped arguments to A1 notation in range
method calls.
r)   .r   c                     [        U S   [        5      =(       aG    [        U S   [        5      =(       a-    [        U S   [        5      =(       a    [        U S   [        5      $ )Nr   r   r.     )r   r  )r)   s    r,   contains_row_cols.cast_to_a1_notation.<locals>.contains_row_colsI  sP    tAw$ )47C()47C() 47C(		
r.   r1   r*   c                    >  [        U5      S:  a>  T" U5      (       a1  [        US S 6 n[        USS 6 nSR                  X445      nU4USS  -   nT" U /UQ70 UD6$ ! [         a     Nf = f)N   r.  rB  )r  r,  joinr  )r1   r)   r*   range_start	range_end
range_namer[  rW  s         r,   wrapper$cast_to_a1_notation.<locals>.wrapperQ  s    	4yA~"3D"9"9 +D!H5($q)4	 XX{&>?
"}tABx/ d,T,V,,  		s   AA 
A)(A))r   r   boolr   )rW  rc  r[  s   ` @r,   cast_to_a1_notationrf  D  sY    

c3h 
D 
 6]-c -# - - - -  Nr.   urlc                     [         R                  U 5      nU(       a  UR                  S5      $ [        R                  U 5      nU(       a  UR                  S5      $ [        e)Nr   )URL_KEY_V2_REsearchr1  URL_KEY_V1_REr   )rg  m2m1s      r,   extract_id_from_urlrn  e  sJ    			c	"B	xx{			c	"B	xx{
r.   widc                     [        U 5      S:  a  U SS OU n[        U 5      S:  a  SOSn[        [        US5      U-  5      $ )z*Calculate gid of a worksheet from its wid.rZ  r   Ni  iZ{  $   )r  r    r  )ro  widvalxorvals      r,   
wid_to_gidrt  q  s@    C1SW#FHqLSeFs62'((r.   max_lenpadding_valuec                 >    U[        U 5      -
  nUS:w  a  X/U-  -   $ U $ )Nr   r  )r!  ru  rv  pad_lens       r,   rightpadrz  x  s+    C G0713/G+,E#Er.   LrE   rF   c           	           Uc  [        S U  5       5      OUnUc  [        U 5      OUnU[        U 5      -
  nU(       a	  U / /U-  -   n U  Vs/ s H  n[        XtUS9PM     sn$ s  snf ! [         a    / /s $ f = f)a  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]]:
c              3   8   #    U  H  n[        U5      v   M     g 7fr0   rx  r  r!  s     r,   r	  fill_gaps.<locals>.<genexpr>  s     -1Cs3xx1   )rv  )maxr  rz  r  )r{  rE   rF   rv  max_colsmax_rowspad_rowsr!  s           r,   	fill_gapsr  }  s    >153-1--4!\3q6tc!f$bTH_%APQRPQmDPQRRR ts$   A	A' A"A' "A' 'A76A7	cell_listr   c           
      t   U (       d  / $ [        [        5      n[        S U  5       5      n[        S U  5       5      nU  HF  nUR                  [	        UR
                  5      U-
  0 5      nUR                  XTR                  U-
  '   MH     U(       d  / $ [        R                  " S UR                  5        5       5      n[        [        U5      S-   5      n[        [        UR                  5       5      S-   5      nU V	V
s/ s H&  o V
s/ s H  oU	   R                  U
5      PM     sn
PM(     sn
n	$ s  sn
f s  sn
n	f )Nc              3   8   #    U  H  oR                   v   M     g 7fr0   )r!  r  r9  s     r,   r	  $cell_list_to_rect.<locals>.<genexpr>       .IqUUIr  c              3   8   #    U  H  oR                   v   M     g 7fr0   )r"  r  s     r,   r	  r    r  r  c              3   @   #    U  H  oR                  5       v   M     g 7fr0   )keysr~  s     r,   r	  r    s     &K]cxxzz]s   r   )r   dictmin
setdefaultr  r!  r(   r"  r   from_iterabler   r  r  r  get)r  rE   
row_offset
col_offsetcellr!  all_row_keys	rect_cols	rect_rowsr8  js              r,   cell_list_to_rectr    s    	0;D0AD.I..J.I..Jooc$((mj8"=%)ZZHHz!"  	&&&KT[[]&KKLc,'!+,Ic$))+&*+I :CCAY/Y!W[[^Y/CC/Cs   >	D4D/$D4/D4safeencodingc                 8    [        U R                  U5      U5      $ r0   )uquoteencode)r(   r  r  s      r,   r   r     s    %,,x($//r.   
sheet_namerb  c                 x    SR                  U R                  SS5      5      n U(       a  SR                  X5      $ U $ )ay  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{}!{})r   r  )r  rb  s     r,   absolute_range_namer    s7    * z11#t<=J~~j55r.   xc                 Z    [        U [        5      =(       d    [        U [        5      (       + $ )zReturn 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  s    r,   	is_scalarr    s     . a<Z8%<!<<r.   worksheet_metadatarL  start_col_indexc                    U R                  S/ 5      nU Vs/ s H  n[        U5      PM     nn[        U5      S-
  n[        US   5      S-
  nU H  n	U	S   U	S   pU	S   U	S   pX-  n
X-  nX-  nX-  nX:  d  X:  a  M1  U
S:  d  US:  a  M?  X   U   n[        X5      n[        X5      nU H!  nU H  nUU:  d  UU:  a  M  XU   U'   M     M#     M     U$ s  snf )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))
mergesr   r   rC  rD  rE  rF  )r  listr  r  )r  r   rL  r  r  r!  
new_valuesmax_row_indexmax_col_indexmergemerge_start_rowmerge_end_rowmerge_start_colmerge_end_coltop_left_valuerow_indicescol_indices	row_index	col_indexs                      r,   combined_merge_valuesr     s&   B  ##Hb1F'-.v$s)vJ. K!OMq	NQ&M).)?}AU$%"# '
 	*(*(*o.MQ/A"50AO;O;$I(	},	M0I3A9%i0	 ) %' 4 A /s   C	hex_colorc                    U R                  S5      n [        U 5      S:X  a  U SS n [        U 5      S:X  a$  SR                  U  Vs/ s H  oS-  PM	     sn5      n [        U 5      S:w  a  [        S	5      e [	        U S
S S5      S-  [	        U SS S5      S-  [	        U SS S5      S-  S.nU$ s  snf ! [         a  n[        SU  35      UeSnAff = f)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}

#   NrZ  r  r.     z/Hex color code must be in the format '#RRGGBB'.r         r^  )redgreenbluez(Invalid character in hex color string: #)lstripr  r_  r  r  )r  char	rgb_colorexs       r,   convert_hex_to_colors_dictr  F  s    &   %I
 9~crN	 9~GG)<)$AX)<=	
9~JKK	Yy1~r*S01Q,s2	!A+c1
	  =  YCI;OPVXXYs   B,47B1 1
C;C

Cr  r  r  c                     S[         S[        4S jn[        S XU4 5       5      (       a  [        S5      eSU" U 5       U" U5       U" U5       3$ )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(   r   c                 t    [        [        U S-  5      5      SS nUR                  5       R                  S5      $ )z7
Convert an integer to a 2-digit uppercase hex string.
r  r.  N)hexroundr2  zfill)r(   	hex_values     r,   to_hex+convert_colors_to_hex_value.<locals>.to_hex  s6     eck*+AB/	 &&q))r.   c              3   B   #    U  H  oS :  =(       d    US:  v   M     g7f)r   r   Nr5   )r  r(   s     r,   r	  .convert_colors_to_hex_value.<locals>.<genexpr>  s      
B/Ae19!	!/As   z&Color value out of accepted range 0-1.r  )r  r    anyr  )r  r  r  r  s       r,   convert_colors_to_hex_valuer  t  sZ    0*e * * 
BD/A
BBBABBvc{mF5M?6$<.99r.   c                 0    [         R                  U 5      SL$ )ad  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_RErj  rb  s    r,   is_full_a1_notationr    s    & !!*-T99r.   c                 :    SU ;   a  U R                  S5      S   $ U $ )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  s    r,   get_a1_from_absolute_ranger    s(     j$Q''r.   headersc           	      V    U Vs/ s H  n[        [        X5      5      PM     sn$ s  snf )az  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",
        },
    ]
)r  rw   )r  r   r!  s      r,   
to_recordsr    s&    4 066vDW"#v666s   &startendc                 V     X   R                  SX5      S-
  $ ! [         a    Us $ f = f)zThis is a private function, returning the column index of the last non empty cell
on the given row.

Search starts from ``start`` index column.
Search ends on ``end`` index column.
Searches only in the row pointed by ``row``.
r  r   )r  r  )r   r  r  r!  s       r,   _expand_rightr    s5    {  U0144 
s    ((c                     [        X5       HE  nU[        U 5      :  a  [        U 5      S-
  s  $ U[        X   5      :  d  X   U   S:X  d  M@  US-
  s  $    US-
  $ )zThis is a private function, returning the row index of the last non empty cell
on the given column.

Search starts from ``start`` index row.
Search ends on ``end`` index row.
Searches only in the column pointed by ``col``.
r   r  )r  r  )r   r  r  r"  rE   s        r,   _expand_bottomr    s`     e!3v;v;?" #fl##v|C'8B'>!8O " 7Nr.   start_range	directionc           	         [        U5      u  p4US-  nUS-  nU[        U 5      :  a$  [        SR                  U[        U 5      5      5      eU[        X   5      :  a&  [        SR                  U[        X   5      5      5      eU[        R
                  :X  a  Un[        X[        U 5      U5      nU[        R                  :X  a  Un[        X[        X   5      U5      nU[        R                  :X  a.  [        X[        X   5      U5      n[        X[        U 5      U5      n/ nXWS-     H  nUR                  XWS-    5        M     U$ )a  Expands a list of values based on non-null adjacent cells.

Expand can be done in 3 directions defined in :class:`~gspread.utils.TableDirection`

    * ``TableDirection.right``: expands right until the first empty cell
    * ``TableDirection.down``: expands down until the first empty cell
    * ``TableDirection.table``: expands right until the first empty cell and down until first empty cell

In case of empty result an empty list is restuned.

When the given ``start_range`` is outside the given matrix of values the exception
:class:`~gspread.exceptions.InvalidInputValue` is raised.

Example::

    values = [
        ['', '',   '',   '', ''  ],
        ['', 'B2', 'C2', '', 'E2'],
        ['', 'B3', 'C3', '', 'E3'],
        ['', ''  , ''  , '', 'E4'],
    ]
    >>> utils.find_table(TableDirection.table, 'B2')
    [
        ['B2', 'C2'],
        ['B3', 'C3'],
    ]


.. note::

   the ``TableDirection.table`` will look right from starting cell then look down from starting cell.
   It will not check cells located inside the table. This could lead to
   potential empty values located in the middle of the table.

.. warning::

   Given values must be padded with `''` empty values.

:param list[list] values: values where to find the table.
:param gspread.utils.TableDirection direction: the expand direction.
:param str start_range: the starting cell range.
:rtype list(list): the resulting matrix
r   z\given row for start_range is outside given values: start range row ({}) >= rows in values {}zegiven column for start_range is outside given values: start range column ({}) >= columns in values {})r:  r  r   r   r   r   r  r   r  r   append)	r   r  r  r!  r"  	rightMost
bottomMostresultrE   s	            r,   
find_tabler    sG   ` K(HC 1HC1HC
c&kjqqS[
 	
 c&+szzS%
 	
 N'''	#FVcB
N(((
!&s6;/?E	N(((!&s6;/?E	#FVcB
F Z!^,dQ/0 - Mr.   __main__)Fr  Fr0   )r  )NNr  )r  zutf-8)        r  r  )c__doc__r!   recollectionsr   collections.abcr   	functoolsr   	itertoolsr   typingr   r   r	   r
   r   r   r   r   r   r   r   r   urllib.parser   r  google.auth.credentialsr   google.oauth2.credentialsr   google.oauth2.service_accountr   
exceptionsr   r   r   r  r   r'  compiler/  r=  r  rk  ri  r    Enumr   rA   rH   rQ   rZ   ra   rh   ro   ry   r   r   r   r   r   r   r   r   r  re  r  r  r  r  r   r,  r:  IntOrInfr?  rS  rV  rf  rn  rt  rz  r  r  r  r  r  r  r  r  r  r  r  r  r   r  r:   doctesttestmodr5   r.   r,   <module>r     sD    	 # $      ) > D R Q Q zz23ZZ ;< **9:

?+

>?c499  
  "w "
 w  
*W *
w 7 ; ;w 
 G  
 ,g  ,FW [ [ &	 	 	T# T+ T CL48QCI& 4Xa[ 4Q 4 27	HFHH H ,0	H
 eC&'(HZ 27%L%% % ,0	%
 I% 
(5eV+,
-.%P"c " " "J c3h : e:3 :581C+D :z? ? ?cSVh ?D'3 '3 'Ta 0 Xc1f5E B	S 	S 	)C )C )F$s) Fc F# FtCy F 	*DI*
3-* 3-* 	*
 
$s)_*ZDf D$tHSM7J2K D60 0C 0 0# 0C Xc] c := = =4CS)CcOC C 	C
 
$s)_CL+Y# +Y'#u*2E +Y^ 9<":	":"":05":":J:C :D :,3 3 "  B47c]7)1(3-)@7	$sE#sE/**
+,7:$tCy/ # C c c 4S	? 3 S s s . !/ 4 4VcOVV V 
$s)_	Vl zOO r.   