
    %ex/                        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 d dlZd dlmZ d dlmZ d d	lmZ d d
lmZ e	rd dlmZ d dlmZ d dlmZ h dZh dZ  G d ded                   Z!dS )    )annotations)ChainMap)deepcopy)	timedelta)TYPE_CHECKINGListOptionalUnioncastN)BaseConnection)extract_from_dict)StreamlitAPIException)
cache_data)
Connection)EngineSession>   urlhostportdriverdialectdatabasepasswordusername>   r   r   r   c                      e Zd ZdZdddZdd	d	d	d	d
d dZd!dZed"d            Zed#d            Z	ed$d            Z
d#dZd	S )%SQLConnectiona  A connection to a SQL database using a SQLAlchemy Engine. Initialize using ``st.connection("<name>", type="sql")``.

    SQLConnection provides the ``query()`` convenience method, which can be used to
    run simple read-only queries with both caching and simple error handling/retries.
    More complex DB interactions can be performed by using the ``.session`` property
    to receive a regular SQLAlchemy Session.

    SQLConnections should always be created using ``st.connection()``, **not**
    initialized directly. Connection parameters for a SQLConnection can be specified
    using either ``st.secrets`` or ``**kwargs``. Some frequently used parameters include:

    - **url** or arguments for `sqlalchemy.engine.URL.create()
      <https://docs.sqlalchemy.org/en/20/core/engines.html#sqlalchemy.engine.URL.create>`_.
      Most commonly it includes a dialect, host, database, username and password.

    - **create_engine_kwargs** can be passed via ``st.secrets``, such as for
      `snowflake-sqlalchemy <https://github.com/snowflakedb/snowflake-sqlalchemy#key-pair-authentication-support>`_
      or `Google BigQuery <https://github.com/googleapis/python-bigquery-sqlalchemy#authentication>`_.
      These can also be passed directly as ``**kwargs`` to connection().

    - **autocommit=True** to run with isolation level ``AUTOCOMMIT``. Default is False.

    Example
    -------
    >>> import streamlit as st
    >>>
    >>> conn = st.connection("sql")
    >>> df = conn.query("select * from pet_owners")
    >>> st.dataframe(df)
    F
autocommitboolreturn'Engine'c           
     T   dd l }t          |          }t          t          |          }t	          || j                                                  }t          |          st          d          d|v r!|j	        
                    |d                   }nt          D ]}||vrt          d|           |d         d|v rd|d          ndz   }|j	        j                            ||d	         |                    d
          |d         d|v rt          |d                   nd |                    d                    }t	          || j                            di                     }	 |j        |fi |	}
|r$t#          d|
                    d                    S t#          d|
          S )Nr   zvMissing SQL DB connection configuration. Did you forget to set this in `secrets.toml` or as kwargs to `st.connection`?r   z!Missing SQL DB connection param: r   r   + r   r   r   r   r   )
drivernamer   r   r   r   r   create_engine_kwargsr   
AUTOCOMMIT)isolation_level)
sqlalchemyr   r   _ALL_CONNECTION_PARAMSr   _secretsto_dictlenr   enginemake_url_REQUIRED_CONNECTION_PARAMSURLcreategetintcreate_enginer   execution_options)selfr   kwargsr)   conn_param_kwargsconn_paramsr   pr%   r&   engs              Dlib/python3.11/site-packages/streamlit/connections/sql_connection.py_connectzSQLConnection._connectO   s   &!!-.DfMM0$-2G2G2I2IJJ; 	'`  
 K#,,[-?@@CC0 Y YK''/0WTU0W0WXXX ( %Y//7;/F/F+K)+++BJ #'..%$Z0$44 (17;1F1FSV,---D$44 /  C  (DM%%&<bAA 
  
 'j&sCC.BCC 	'#"7"7"7"U"UVVV#&&&    zRunning `sql.query(...)`.N)show_spinnerttl	index_col	chunksizeparamssqlstrr@   
bool | strrA   &Optional[Union[float, int, timedelta]]rB   Optional[Union[str, List[str]]]rC   Optional[int]pd.DataFramec          
         ddl m ddlm}m}	m}
 ddlm}m}m	}m
}  | fd |d          d |||	|
f           |d          	          	 	 	 dd fd            }t          |                              dd          }|j         d j         d| |_         t          ||          |          } ||f|||d|S )a!
  Run a read-only query.

        This method implements both query result caching (with caching behavior
        identical to that of using ``@st.cache_data``) as well as simple error handling/retries.

        .. note::
            Queries that are run without a specified ttl are cached indefinitely.

        Aside from the ``ttl`` kwarg, all kwargs passed to this function are passed down
        to |pandas.read_sql|_
        and have the behavior described in the pandas documentation.

        .. |pandas.read_sql| replace:: ``pandas.read_sql``
        .. _pandas.read_sql: https://pandas.pydata.org/docs/reference/api/pandas.read_sql.html

        Parameters
        ----------
        sql : str
            The read-only SQL query to execute.
        show_spinner : boolean or string
            Enable the spinner. The default is to show a spinner when there is a
            "cache miss" and the cached resource is being created. If a string, the value
            of the show_spinner param will be used for the spinner text.
        ttl : float, int, timedelta or None
            The maximum number of seconds to keep results in the cache, or
            None if cached results should not expire. The default is None.
        index_col : str, list of str, or None
            Column(s) to set as index(MultiIndex). Default is None.
        chunksize : int or None
            If specified, return an iterator where chunksize is the number of
            rows to include in each chunk. Default is None.
        params : list, tuple, dict or None
            List of parameters to pass to the execute method. The syntax used to pass
            parameters is database driver dependent. Check your database driver
            documentation for which of the five syntax styles, described in `PEP 249
            paramstyle <https://peps.python.org/pep-0249/#paramstyle>`_, is supported.
            Default is None.
        **kwargs: dict
            Additional keyword arguments are passed to |pandas.read_sql|_.

            .. |pandas.read_sql| replace:: ``pandas.read_sql``
            .. _pandas.read_sql: https://pandas.pydata.org/docs/reference/api/pandas.read_sql.html

        Returns
        -------
        pandas.DataFrame
            The result of running the query, formatted as a pandas DataFrame.

        Example
        -------
        >>> import streamlit as st
        >>>
        >>> conn = st.connection("sql")
        >>> df = conn.query("select * from pet_owners where owner = :owner", ttl=3600, params={"owner":"barbara"})
        >>> st.dataframe(df)
        r   )text)DatabaseErrorInternalErrorOperationalError)retryretry_if_exception_typestop_after_attempt
wait_fixedc                ,                                     S )N)reset)_r7   s    r=   <lambda>z%SQLConnection.query.<locals>.<lambda>   s    DJJLL r?      T   )afterstopreraiserQ   waitNrE   rF   r    rK   c                v    j                                         }t          j         |           |f|||d|S )NrB   rC   rD   )	_instanceconnectpdread_sql)rE   rB   rC   rD   r8   instancer7   rM   s         r=   _queryz#SQLConnection.query.<locals>._query   sY      ~--//H;S		 $#    r?   .rW   )r@   rA   r`   )NNN)rE   rF   r    rK   )r)   rM   sqlalchemy.excrN   rO   rP   tenacityrQ   rR   rS   rT   rF   replace__qualname___connection_namer   )r7   rE   r@   rA   rB   rC   rD   r8   rN   rO   rP   rQ   rR   rS   rT   rf   ttl_strrM   s   `                @r=   queryzSQLConnection.queryz   s   H 	$#####QQQQQQQQQQ	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 
((((##A&&))/?@  A

 

 

 		 	 	 	 	 	 	

 

	* 
 

'#s

 	 "(!4XXt7LXXwXX
%
 
 
  
 v
	
 

 
 
 	
r?   'SQLAlchemyConnection'c                4    | j                                         S )a_  Call ``.connect()`` on the underlying SQLAlchemy Engine, returning a new        ``sqlalchemy.engine.Connection`` object.

        Calling this method is equivalent to calling ``self._instance.connect()``.

        NOTE: This method should not be confused with the internal ``_connect`` method used
        to implement a Streamlit Connection.
        )ra   rb   r7   s    r=   rb   zSQLConnection.connect   s     ~%%'''r?   c                    | j         S )zgThe underlying SQLAlchemy Engine.

        This is equivalent to accessing ``self._instance``.
        )ra   rq   s    r=   r.   zSQLConnection.engine  s     ~r?   c                    | j         j        S )zThe name of the driver used by the underlying SQLAlchemy Engine.

        This is equivalent to accessing ``self._instance.driver``.
        )ra   r   rq   s    r=   r   zSQLConnection.driver	  s     ~$$r?   	'Session'c                .    ddl m}  || j                  S )aP  Return a SQLAlchemy Session.

        Users of this connection should use the contextmanager pattern for writes,
        transactions, and anything more complex than simple read queries.

        See the usage example below, which assumes we have a table ``numbers`` with a
        single integer column ``val``. The `SQLAlchemy
        <https://docs.sqlalchemy.org/en/20/orm/session_basics.html>`_ docs also contain
        much more information on the usage of sessions.

        Example
        -------
        >>> import streamlit as st
        >>> conn = st.connection("sql")
        >>> n = st.slider("Pick a number")
        >>> if st.button("Add the number!"):
        ...     with conn.session as session:
        ...         session.execute("INSERT INTO numbers (val) VALUES (:n);", {"n": n})
        ...         session.commit()
        r   r   )sqlalchemy.ormr   ra   )r7   r   s     r=   sessionzSQLConnection.session  s(    , 	+*****wt~&&&r?   c                .   t          | dd           }t          |           j        }t          | j                  rd| j         dnd}| j        5 }|j        |j        j        j	        nd}d d d            n# 1 swxY w Y   d| j         d| d| d	| d
| dS )N
__module__z - Configured from `[connections.z]`r$   unknownz
---
**st.connection z built from `rg   z`**
z
- Dialect: `z%`
- Learn more using `st.help()`
---
)
getattrtype__name__r-   r+   rl   rw   bindr   name)r7   module_name
class_namecfgsr   s         r=   _repr_html_zSQLConnection._repr_html_.  s,   dL$77$ZZ(
 4=!!Ht/DHHHH 	 \ 	OQ-.V-?afn))YG	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O& 5@ CM    	   	s   A55A9<A9)F)r   r   r    r!   )rE   rF   r@   rG   rA   rH   rB   rI   rC   rJ   r    rK   )r    ro   )r    r!   )r    rF   )r    rt   )r}   ry   rk   __doc__r>   rn   rb   propertyr.   r   rw   r    r?   r=   r   r   /   s         >)' )' )' )' )'^ $?6:59#'z
 z
 z
 z
 z
 z
x	( 	( 	( 	(    X % % % X% ' ' ' X'8     r?   r   r   )"
__future__r   collectionsr   copyr   datetimer   typingr   r   r	   r
   r   pandasrc   streamlit.connectionsr   streamlit.connections.utilr   streamlit.errorsr   streamlit.runtime.cachingr   sqlalchemy.enginer   SQLAlchemyConnectionsqlalchemy.engine.baser   rv   r   r*   r0   r   r   r?   r=   <module>r      sn   # " " " " "                         = = = = = = = = = = = = = =     0 0 0 0 0 0 8 8 8 8 8 8 2 2 2 2 2 2 0 0 0 0 0 0 'DDDDDD------&&&&&&	 	 	  >== S S S S SN8, S S S S Sr?   