streamlit-nightly 1.39.1.dev20241029__py2.py3-none-any.whl → 1.39.1.dev20241030__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- streamlit/connections/base_connection.py +4 -0
- streamlit/connections/snowflake_connection.py +310 -36
- streamlit/connections/snowpark_connection.py +1 -1
- streamlit/connections/sql_connection.py +140 -26
- streamlit/proto/MetricsEvent_pb2.py +30 -0
- streamlit/proto/MetricsEvent_pb2.pyi +200 -0
- streamlit/runtime/connection_factory.py +122 -37
- streamlit/static/asset-manifest.json +21 -19
- streamlit/static/index.html +1 -1
- streamlit/static/static/js/1504.51c32670.chunk.js +2 -0
- streamlit/static/static/js/223.7f54d4fe.chunk.js +1 -0
- streamlit/static/static/js/2601.677fbaac.chunk.js +1 -0
- streamlit/static/static/js/3224.919d670d.chunk.js +1 -0
- streamlit/static/static/js/3682.8ecb602d.chunk.js +1 -0
- streamlit/static/static/js/3978.58bcc6a4.chunk.js +2 -0
- streamlit/static/static/js/4133.5d5fe118.chunk.js +2 -0
- streamlit/static/static/js/{4942.e4db7877.chunk.js → 4942.cd41b09c.chunk.js} +1 -1
- streamlit/static/static/js/5361.913e291a.chunk.js +1 -0
- streamlit/static/static/js/5503.0917ff70.chunk.js +1 -0
- streamlit/static/static/js/7612.3f409b56.chunk.js +2 -0
- streamlit/static/static/js/783.403d1195.chunk.js +1 -0
- streamlit/static/static/js/8148.9b76a4cd.chunk.js +1 -0
- streamlit/static/static/js/8237.86c539f3.chunk.js +1 -0
- streamlit/static/static/js/8380.9d225c39.chunk.js +1 -0
- streamlit/static/static/js/8460.570de48a.chunk.js +1 -0
- streamlit/static/static/js/9923.14294b15.chunk.js +1 -0
- streamlit/static/static/js/9943.ac0530dc.chunk.js +1 -0
- streamlit/static/static/js/main.754d974e.js +28 -0
- streamlit/web/server/routes.py +1 -0
- {streamlit_nightly-1.39.1.dev20241029.dist-info → streamlit_nightly-1.39.1.dev20241030.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.39.1.dev20241029.dist-info → streamlit_nightly-1.39.1.dev20241030.dist-info}/RECORD +41 -37
- streamlit/static/static/js/223.2359dae5.chunk.js +0 -1
- streamlit/static/static/js/3224.a04b49ba.chunk.js +0 -1
- streamlit/static/static/js/3389.71902a75.chunk.js +0 -1
- streamlit/static/static/js/4096.178414b7.chunk.js +0 -2
- streamlit/static/static/js/4297.3afbdd03.chunk.js +0 -2
- streamlit/static/static/js/4856.03868952.chunk.js +0 -2
- streamlit/static/static/js/5849.e92568db.chunk.js +0 -1
- streamlit/static/static/js/6198.956025ac.chunk.js +0 -2
- streamlit/static/static/js/6360.50be2ff5.chunk.js +0 -1
- streamlit/static/static/js/783.788bb3ab.chunk.js +0 -1
- streamlit/static/static/js/8148.b29e43b5.chunk.js +0 -1
- streamlit/static/static/js/8237.58ae67da.chunk.js +0 -1
- streamlit/static/static/js/8460.8b3f792f.chunk.js +0 -1
- streamlit/static/static/js/9923.8dc9e5ed.chunk.js +0 -1
- streamlit/static/static/js/9943.51b39296.chunk.js +0 -1
- streamlit/static/static/js/main.8c705f66.js +0 -28
- /streamlit/static/static/css/{4096.8b8f33d6.chunk.css → 1504.8b8f33d6.chunk.css} +0 -0
- /streamlit/static/static/js/{4096.178414b7.chunk.js.LICENSE.txt → 1504.51c32670.chunk.js.LICENSE.txt} +0 -0
- /streamlit/static/static/js/{6198.956025ac.chunk.js.LICENSE.txt → 3978.58bcc6a4.chunk.js.LICENSE.txt} +0 -0
- /streamlit/static/static/js/{4297.3afbdd03.chunk.js.LICENSE.txt → 4133.5d5fe118.chunk.js.LICENSE.txt} +0 -0
- /streamlit/static/static/js/{4856.03868952.chunk.js.LICENSE.txt → 7612.3f409b56.chunk.js.LICENSE.txt} +0 -0
- /streamlit/static/static/js/{main.8c705f66.js.LICENSE.txt → main.754d974e.js.LICENSE.txt} +0 -0
- {streamlit_nightly-1.39.1.dev20241029.data → streamlit_nightly-1.39.1.dev20241030.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.39.1.dev20241029.dist-info → streamlit_nightly-1.39.1.dev20241030.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.39.1.dev20241029.dist-info → streamlit_nightly-1.39.1.dev20241030.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.39.1.dev20241029.dist-info → streamlit_nightly-1.39.1.dev20241030.dist-info}/top_level.txt +0 -0
@@ -154,6 +154,10 @@ class BaseConnection(ABC, Generic[RawConnectionT]):
|
|
154
154
|
reinitializing it. Note that some connection methods may already use ``reset()``
|
155
155
|
in their error handling code.
|
156
156
|
|
157
|
+
Returns
|
158
|
+
-------
|
159
|
+
None
|
160
|
+
|
157
161
|
Example
|
158
162
|
-------
|
159
163
|
>>> import streamlit as st
|
@@ -40,14 +40,159 @@ if TYPE_CHECKING:
|
|
40
40
|
|
41
41
|
|
42
42
|
class SnowflakeConnection(BaseConnection["InternalSnowflakeConnection"]):
|
43
|
-
"""A connection to Snowflake using the Snowflake
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
43
|
+
"""A connection to Snowflake using the Snowflake Connector for Python.
|
44
|
+
|
45
|
+
Initialize this connection object using ``st.connection("snowflake")`` or
|
46
|
+
``st.connection("<name>", type="snowflake")``. Connection parameters for a
|
47
|
+
SnowflakeConnection can be specified using ``secrets.toml`` and/or
|
48
|
+
``**kwargs``. Connection parameters are passed to
|
49
|
+
|snowflake.connector.connect()|.
|
50
|
+
|
51
|
+
When an app is running in Streamlit in Snowflake,
|
52
|
+
``st.connection("snowflake")`` connects automatically using the app owner's
|
53
|
+
role without further configuration. ``**kwargs`` will be ignored in this
|
54
|
+
case. Use ``secrets.toml`` and ``**kwargs`` to configure your connection
|
55
|
+
for local development.
|
56
|
+
|
57
|
+
SnowflakeConnection includes several convenience methods. For example, you
|
58
|
+
can directly execute a SQL query with ``.query()`` or access the underlying
|
59
|
+
Snowflake Connector object with ``.raw_connection``.
|
60
|
+
|
61
|
+
.. |snowflake.connector.connect()| replace:: ``snowflake.connector.connect()``
|
62
|
+
.. _snowflake.connector.connect(): https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-api#label-snowflake-connector-methods-connect
|
63
|
+
|
64
|
+
.. Tip::
|
65
|
+
`snowflake-snowpark-python <https://pypi.org/project/snowflake-snowpark-python/>`_
|
66
|
+
must be installed in your environment to use this connection. You can
|
67
|
+
install Snowflake extras along with Streamlit:
|
68
|
+
|
69
|
+
>>> pip install streamlit[snowflake]
|
70
|
+
|
71
|
+
.. Important::
|
72
|
+
Account identifiers must be of the form ``<orgname>-<account_name>``
|
73
|
+
where ``<orgname>`` is the name of your Snowflake organization and
|
74
|
+
``<account_name>`` is the unique name of your account within your
|
75
|
+
organization. This is dash-separated, not dot-separated like when used
|
76
|
+
in SQL queries. For more information, see `Account identifiers
|
77
|
+
<https://docs.snowflake.com/en/user-guide/admin-account-identifier>`_.
|
78
|
+
|
79
|
+
Examples
|
80
|
+
--------
|
81
|
+
|
82
|
+
**Example 1: Configuration with Streamlit secrets**
|
83
|
+
|
84
|
+
You can configure your Snowflake connection using Streamlit's
|
85
|
+
`Secrets management <https://docs.streamlit.io/develop/concepts/connections/secrets-management>`_.
|
86
|
+
For example, if you have MFA enabled on your account, you can connect using
|
87
|
+
`key-pair authentication <https://docs.snowflake.com/en/user-guide/key-pair-auth>`_.
|
88
|
+
|
89
|
+
``.streamlit/secrets.toml``:
|
90
|
+
|
91
|
+
>>> [connections.snowflake]
|
92
|
+
>>> account = "xxx-xxx"
|
93
|
+
>>> user = "xxx"
|
94
|
+
>>> private_key_file = "/xxx/xxx/xxx.p8"
|
95
|
+
>>> role = "xxx"
|
96
|
+
>>> warehouse = "xxx"
|
97
|
+
>>> database = "xxx"
|
98
|
+
>>> schema = "xxx"
|
99
|
+
|
100
|
+
Your app code:
|
101
|
+
|
102
|
+
>>> import streamlit as st
|
103
|
+
>>> conn = st.connection("snowflake")
|
104
|
+
>>> df = conn.query("SELECT * FROM my_table")
|
105
|
+
|
106
|
+
**Example 2: Configuration with keyword arguments and external authentication**
|
107
|
+
|
108
|
+
You can configure your Snowflake connection with keyword arguments (with or
|
109
|
+
without ``secrets.toml``). For example, if your Snowflake account supports
|
110
|
+
SSO, you can set up a quick local connection for development using `browser-based SSO
|
111
|
+
<https://docs.snowflake.com/en/user-guide/admin-security-fed-auth-use#how-browser-based-sso-works>`_.
|
112
|
+
|
113
|
+
>>> import streamlit as st
|
114
|
+
>>> conn = st.connection(
|
115
|
+
... "snowflake", account="xxx-xxx", user="xxx", authenticator="externalbrowser"
|
116
|
+
... )
|
117
|
+
>>> df = conn.query("SELECT * FROM my_table")
|
118
|
+
|
119
|
+
**Example 3: Named connection with Snowflake's connection configuration file**
|
120
|
+
|
121
|
+
Snowflake's Python Connector supports a `connection configuration file
|
122
|
+
<https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-connect#connecting-using-the-connections-toml-file>`_,
|
123
|
+
which is well integrated with Streamlit's ``SnowflakeConnection``. If you
|
124
|
+
already have one or more connections configured, all you need to do is pass
|
125
|
+
the name of the connection to use.
|
126
|
+
|
127
|
+
``~/.snowflake/connections.toml``:
|
128
|
+
|
129
|
+
>>> [my_connection]
|
130
|
+
>>> account = "xxx-xxx"
|
131
|
+
>>> user = "xxx"
|
132
|
+
>>> password = "xxx"
|
133
|
+
>>> warehouse = "xxx"
|
134
|
+
>>> database = "xxx"
|
135
|
+
>>> schema = "xxx"
|
136
|
+
|
137
|
+
Your app code:
|
138
|
+
|
139
|
+
>>> import streamlit as st
|
140
|
+
>>> conn = st.connection("my_connection", type="snowflake")
|
141
|
+
>>> df = conn.query("SELECT * FROM my_table")
|
142
|
+
|
143
|
+
**Example 4: Named connection with Streamlit secrets and Snowflake's connection configuration file**
|
144
|
+
|
145
|
+
If you have a Snowflake configuration file with a connection named
|
146
|
+
``my_connection`` as in Example 3, you can pass the connection name through
|
147
|
+
``secrets.toml``.
|
148
|
+
|
149
|
+
``.streamlit/secrets.toml``:
|
150
|
+
|
151
|
+
>>> [connections.snowflake]
|
152
|
+
>>> connection_name = "my_connection"
|
153
|
+
|
154
|
+
Your app code:
|
155
|
+
|
156
|
+
>>> import streamlit as st
|
157
|
+
>>> conn = st.connection("snowflake")
|
158
|
+
>>> df = conn.query("SELECT * FROM my_table")
|
159
|
+
|
160
|
+
**Example 5: Default connection with an environment variable**
|
161
|
+
|
162
|
+
If you have a Snowflake configuration file with a connection named
|
163
|
+
``my_connection`` as in Example 3, you can set an environment variable to
|
164
|
+
declare it as the default Snowflake connection.
|
165
|
+
|
166
|
+
>>> SNOWFLAKE_DEFAULT_CONNECTION_NAME = "my_connection"
|
167
|
+
|
168
|
+
Your app code:
|
169
|
+
|
170
|
+
>>> import streamlit as st
|
171
|
+
>>> conn = st.connection("snowflake")
|
172
|
+
>>> df = conn.query("SELECT * FROM my_table")
|
173
|
+
|
174
|
+
**Example 6: Default connection in Snowflake's connection configuration file**
|
175
|
+
|
176
|
+
If you have a Snowflake configuration file that defines your ``default``
|
177
|
+
connection, Streamlit will automatically use it if no other connection is
|
178
|
+
declared.
|
179
|
+
|
180
|
+
``~/.snowflake/connections.toml``:
|
181
|
+
|
182
|
+
>>> [default]
|
183
|
+
>>> account = "xxx-xxx"
|
184
|
+
>>> user = "xxx"
|
185
|
+
>>> password = "xxx"
|
186
|
+
>>> warehouse = "xxx"
|
187
|
+
>>> database = "xxx"
|
188
|
+
>>> schema = "xxx"
|
189
|
+
|
190
|
+
Your app code:
|
191
|
+
|
192
|
+
>>> import streamlit as st
|
193
|
+
>>> conn = st.connection("snowflake")
|
194
|
+
>>> df = conn.query("SELECT * FROM my_table")
|
195
|
+
|
51
196
|
"""
|
52
197
|
|
53
198
|
def _connect(self, **kwargs) -> InternalSnowflakeConnection:
|
@@ -129,29 +274,37 @@ class SnowflakeConnection(BaseConnection["InternalSnowflakeConnection"]):
|
|
129
274
|
) -> DataFrame:
|
130
275
|
"""Run a read-only SQL query.
|
131
276
|
|
132
|
-
This method implements
|
133
|
-
identical to that of using
|
277
|
+
This method implements query result caching and simple error
|
278
|
+
handling/retries. The caching behavior is identical to that of using
|
279
|
+
``@st.cache_data``.
|
134
280
|
|
135
281
|
.. note::
|
136
|
-
Queries that are run without a specified ttl are cached
|
282
|
+
Queries that are run without a specified ``ttl`` are cached
|
283
|
+
indefinitely.
|
137
284
|
|
138
285
|
Parameters
|
139
286
|
----------
|
140
287
|
sql : str
|
141
288
|
The read-only SQL query to execute.
|
142
289
|
ttl : float, int, timedelta or None
|
143
|
-
The maximum number of seconds to keep results in the cache
|
144
|
-
None
|
290
|
+
The maximum number of seconds to keep results in the cache. If this
|
291
|
+
is ``None`` (default), cached results do not expire with time.
|
145
292
|
show_spinner : boolean or string
|
146
|
-
|
147
|
-
|
148
|
-
|
293
|
+
Whether to enable the spinner. When a cached query is executed, no
|
294
|
+
spinner is displayed because the result is immediately available.
|
295
|
+
When a new query is executed, the default is to show a spinner with
|
296
|
+
the message "Running ``snowflake.query(...)``."
|
297
|
+
|
298
|
+
If this is ``False``, no spinner displays while executing the
|
299
|
+
query. If this is a string, the string will be used as the message
|
300
|
+
for the spinner.
|
149
301
|
params : list, tuple, dict or None
|
150
|
-
List of parameters to pass to the
|
151
|
-
|
152
|
-
|
302
|
+
List of parameters to pass to the Snowflake Connector for Python
|
303
|
+
``Cursor.execute()`` method. This connector supports binding data
|
304
|
+
to a SQL statement using qmark bindings. For more information and
|
305
|
+
examples, see the `Snowflake Connector for Python documentation
|
153
306
|
<https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-example#using-qmark-or-numeric-binding>`_.
|
154
|
-
|
307
|
+
This defaults to ``None``.
|
155
308
|
|
156
309
|
Returns
|
157
310
|
-------
|
@@ -160,11 +313,13 @@ class SnowflakeConnection(BaseConnection["InternalSnowflakeConnection"]):
|
|
160
313
|
|
161
314
|
Example
|
162
315
|
-------
|
316
|
+
|
163
317
|
>>> import streamlit as st
|
164
318
|
>>>
|
165
319
|
>>> conn = st.connection("snowflake")
|
166
|
-
>>> df = conn.query("
|
320
|
+
>>> df = conn.query("SELECT * FROM my_table")
|
167
321
|
>>> st.dataframe(df)
|
322
|
+
|
168
323
|
"""
|
169
324
|
from snowflake.connector.errors import ProgrammingError # type: ignore[import]
|
170
325
|
from snowflake.connector.network import ( # type: ignore[import]
|
@@ -232,20 +387,64 @@ class SnowflakeConnection(BaseConnection["InternalSnowflakeConnection"]):
|
|
232
387
|
chunk_size: int | None = None,
|
233
388
|
**kwargs,
|
234
389
|
) -> tuple[bool, int, int]:
|
235
|
-
"""
|
390
|
+
"""Write a ``pandas.DataFrame`` to a table in a Snowflake database.
|
236
391
|
|
237
|
-
This convenience method is
|
238
|
-
|
239
|
-
|
392
|
+
This convenience method is a thin wrapper around
|
393
|
+
``snowflake.connector.pandas_tools.write_pandas()`` using the
|
394
|
+
underlying connection. The ``conn`` parameter is passed automatically.
|
395
|
+
For more information and additional keyword arguments, see the
|
396
|
+
`Snowflake Connector for Python documentation
|
240
397
|
<https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-api#write_pandas>`_.
|
241
398
|
|
399
|
+
Parameters
|
400
|
+
----------
|
401
|
+
df: pandas.DataFrame
|
402
|
+
The ``pandas.DataFrame`` object containing the data to be copied
|
403
|
+
into the table.
|
404
|
+
table_name: str
|
405
|
+
Name of the table where the data should be copied to.
|
406
|
+
database: str
|
407
|
+
Name of the database containing the table. By default, the function
|
408
|
+
writes to the database that is currently in use in the session.
|
409
|
+
|
410
|
+
.. Note::
|
411
|
+
If you specify this parameter, you must also specify the schema
|
412
|
+
parameter.
|
413
|
+
|
414
|
+
schema: str
|
415
|
+
Name of the schema containing the table. By default, the function
|
416
|
+
writes to the table in the schema that is currently in use in the
|
417
|
+
session.
|
418
|
+
chunk_size: int
|
419
|
+
Number of elements to insert at a time. By default, the function
|
420
|
+
inserts all elements in one chunk.
|
421
|
+
**kwargs: Any
|
422
|
+
Additional keyword arguments for
|
423
|
+
``snowflake.connector.pandas_tools.write_pandas()``.
|
424
|
+
|
242
425
|
Returns
|
243
426
|
-------
|
244
427
|
tuple[bool, int, int]
|
245
428
|
A tuple containing three values:
|
246
|
-
|
247
|
-
|
248
|
-
|
429
|
+
|
430
|
+
1. A boolean value that is ``True`` if the write was successful.
|
431
|
+
2. An integer giving the number of chunks of data that were copied.
|
432
|
+
3. An integer giving the number of rows that were inserted.
|
433
|
+
|
434
|
+
Example
|
435
|
+
-------
|
436
|
+
The following example uses the database and schema currently in use in
|
437
|
+
the session and copies the data into a table named "my_table."
|
438
|
+
|
439
|
+
>>> import streamlit as st
|
440
|
+
>>> import pandas as pd
|
441
|
+
>>>
|
442
|
+
>>> df = pd.DataFrame(
|
443
|
+
... {"Name": ["Mary", "John", "Robert"], "Pet": ["dog", "cat", "bird"]}
|
444
|
+
... )
|
445
|
+
>>> conn = st.connection("snowflake")
|
446
|
+
>>> conn.write_pandas(df, "my_table")
|
447
|
+
|
249
448
|
"""
|
250
449
|
from snowflake.connector.pandas_tools import write_pandas # type:ignore[import]
|
251
450
|
|
@@ -262,27 +461,102 @@ class SnowflakeConnection(BaseConnection["InternalSnowflakeConnection"]):
|
|
262
461
|
return (success, nchunks, nrows)
|
263
462
|
|
264
463
|
def cursor(self) -> SnowflakeCursor:
|
265
|
-
"""
|
464
|
+
"""Create a new cursor object from this connection.
|
266
465
|
|
267
|
-
|
466
|
+
Snowflake Connector cursors implement the Python Database API v2.0
|
467
|
+
specification (PEP-249). For more information, see the
|
468
|
+
`Snowflake Connector for Python documentation
|
268
469
|
<https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-api#object-cursor>`_.
|
470
|
+
|
471
|
+
Returns
|
472
|
+
-------
|
473
|
+
snowflake.connector.cursor.SnowflakeCursor
|
474
|
+
A cursor object for the connection.
|
475
|
+
|
476
|
+
Example
|
477
|
+
-------
|
478
|
+
The following example uses a cursor to insert multiple rows into a
|
479
|
+
table. The ``qmark`` parameter style is specified as an optional
|
480
|
+
keyword argument. Alternatively, the parameter style can be declared in
|
481
|
+
your connection configuration file. For more information, see the
|
482
|
+
`Snowflake Connector for Python documentation
|
483
|
+
<https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-example#using-qmark-or-numeric-binding>`_.
|
484
|
+
|
485
|
+
>>> import streamlit as st
|
486
|
+
>>>
|
487
|
+
>>> conn = st.connection("snowflake", "paramstyle"="qmark")
|
488
|
+
>>> rows_to_insert = [("Mary", "dog"), ("John", "cat"), ("Robert", "bird")]
|
489
|
+
>>> conn.cursor().executemany(
|
490
|
+
... "INSERT INTO mytable (name, pet) VALUES (?, ?)", rows_to_insert
|
491
|
+
... )
|
492
|
+
|
269
493
|
"""
|
270
494
|
return self._instance.cursor()
|
271
495
|
|
272
496
|
@property
|
273
497
|
def raw_connection(self) -> InternalSnowflakeConnection:
|
274
|
-
"""Access the underlying
|
498
|
+
"""Access the underlying connection object from the Snowflake\
|
499
|
+
Connector for Python.
|
500
|
+
|
501
|
+
For information on how to use the Snowflake Connector for Python, see
|
502
|
+
the `Snowflake Connector for Python documentation
|
503
|
+
<https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-example>`_.
|
504
|
+
|
505
|
+
Returns
|
506
|
+
-------
|
507
|
+
snowflake.connector.connection.SnowflakeConnection
|
508
|
+
The connection object.
|
509
|
+
|
510
|
+
Example
|
511
|
+
-------
|
512
|
+
The following example uses a cursor to submit an asynchronous query,
|
513
|
+
saves the query ID, then periodically checks the query status through
|
514
|
+
the connection before retrieving the results.
|
515
|
+
|
516
|
+
>>> import streamlit as st
|
517
|
+
>>> import time
|
518
|
+
>>>
|
519
|
+
>>> conn = st.connection("snowflake")
|
520
|
+
>>> cur = conn.cursor()
|
521
|
+
>>> cur.execute_async("SELECT * FROM my_table")
|
522
|
+
>>> query_id = cur.sfqid
|
523
|
+
>>> while True:
|
524
|
+
... status = conn.raw_connection.get_query_status(query_id)
|
525
|
+
... if conn.raw_connection.is_still_running(status):
|
526
|
+
... time.sleep(1)
|
527
|
+
... else:
|
528
|
+
... break
|
529
|
+
>>> cur.get_results_from_sfqid(query_id)
|
530
|
+
>>> df = cur.fetchall()
|
275
531
|
|
276
|
-
Information on how to use the Snowflake Python Connector can be found in the
|
277
|
-
`Snowflake Python Connector documentation <https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-example>`_.
|
278
532
|
"""
|
279
533
|
return self._instance
|
280
534
|
|
281
535
|
def session(self) -> Session:
|
282
|
-
"""Create a new Snowpark
|
536
|
+
"""Create a new Snowpark session from this connection.
|
537
|
+
|
538
|
+
For information on how to use Snowpark sessions, see the
|
539
|
+
`Snowpark developer guide
|
540
|
+
<https://docs.snowflake.com/en/developer-guide/snowpark/python/working-with-dataframes>`_
|
541
|
+
and `Snowpark API Reference
|
542
|
+
<https://docs.snowflake.com/en/developer-guide/snowpark/reference/python/latest/snowpark/session>`_.
|
543
|
+
|
544
|
+
Returns
|
545
|
+
-------
|
546
|
+
snowflake.snowpark.Session
|
547
|
+
A new Snowpark session for this connection.
|
548
|
+
|
549
|
+
Example
|
550
|
+
-------
|
551
|
+
The following example creates a new Snowpark session and uses it to run
|
552
|
+
a query.
|
553
|
+
|
554
|
+
>>> import streamlit as st
|
555
|
+
>>>
|
556
|
+
>>> conn = st.connection("snowflake")
|
557
|
+
>>> session = conn.session()
|
558
|
+
>>> df = session.sql("SELECT * FROM my_table").collect()
|
283
559
|
|
284
|
-
Information on how to use Snowpark sessions can be found in the `Snowpark documentation
|
285
|
-
<https://docs.snowflake.com/en/developer-guide/snowpark/python/working-with-dataframes>`_.
|
286
560
|
"""
|
287
561
|
from snowflake.snowpark.context import get_active_session # type:ignore[import]
|
288
562
|
from snowflake.snowpark.session import Session # type:ignore[import]
|
@@ -123,7 +123,7 @@ class SnowparkConnection(BaseConnection["Session"]):
|
|
123
123
|
>>> import streamlit as st
|
124
124
|
>>>
|
125
125
|
>>> conn = st.connection("snowpark")
|
126
|
-
>>> df = conn.query("
|
126
|
+
>>> df = conn.query("SELECT * FROM pet_owners")
|
127
127
|
>>> st.dataframe(df)
|
128
128
|
"""
|
129
129
|
from snowflake.snowpark.exceptions import ( # type:ignore[import]
|
@@ -52,35 +52,129 @@ _REQUIRED_CONNECTION_PARAMS = {"dialect", "username", "host"}
|
|
52
52
|
|
53
53
|
|
54
54
|
class SQLConnection(BaseConnection["Engine"]):
|
55
|
-
"""A connection to a SQL database using a SQLAlchemy Engine.
|
55
|
+
"""A connection to a SQL database using a SQLAlchemy Engine.
|
56
|
+
|
57
|
+
Initialize this connection object using ``st.connection("sql")`` or
|
58
|
+
``st.connection("<name>", type="sql")``. Connection parameters for a
|
59
|
+
SQLConnection can be specified using ``secrets.toml`` and/or ``**kwargs``.
|
60
|
+
Possible connection parameters include:
|
61
|
+
|
62
|
+
- ``url`` or keyword arguments for |sqlalchemy.engine.URL.create()|_, except
|
63
|
+
``drivername``. Use ``dialect`` and ``driver`` instead of ``drivername``.
|
64
|
+
- Keyword arguments for |sqlalchemy.create_engine()|_, including custom
|
65
|
+
``connect()`` arguments used by your specific ``dialect`` or ``driver``.
|
66
|
+
- ``autocommit``. If this is ``False`` (default), the connection operates
|
67
|
+
in manual commit (transactional) mode. If this is ``True``, the
|
68
|
+
connection operates in autocommit (non-transactional) mode.
|
69
|
+
|
70
|
+
If ``url`` exists as a connection parameter, Streamlit will pass it to
|
71
|
+
``sqlalchemy.engine.make_url()``. Otherwise, Streamlit requires (at a
|
72
|
+
minimum) ``dialect``, ``username``, and ``host``. Streamlit will use
|
73
|
+
``dialect`` and ``driver`` (if defined) to derive ``drivername``, then pass
|
74
|
+
the relevant connection parameters to ``sqlalchemy.engine.URL.create()``.
|
75
|
+
|
76
|
+
In addition to the default keyword arguments for ``sqlalchemy.create_engine()``,
|
77
|
+
your dialect may accept additional keyword arguments. For example, if you
|
78
|
+
use ``dialect="snowflake"`` with `Snowflake SQLAlchemy
|
79
|
+
<https://github.com/snowflakedb/snowflake-sqlalchemy#key-pair-authentication-support>`_,
|
80
|
+
you can pass a value for ``private_key`` to use key-pair authentication. If
|
81
|
+
you use ``dialect="bigquery"`` with `Google BigQuery
|
82
|
+
<https://github.com/googleapis/python-bigquery-sqlalchemy#authentication>`_,
|
83
|
+
you can pass a value for ``location``.
|
84
|
+
|
85
|
+
SQLConnection provides the ``.query()`` convenience method, which can be
|
86
|
+
used to run simple, read-only queries with both caching and simple error
|
87
|
+
handling/retries. More complex database interactions can be performed by
|
88
|
+
using the ``.session`` property to receive a regular SQLAlchemy Session.
|
89
|
+
|
90
|
+
.. Important::
|
91
|
+
`SQLAlchemy <https://pypi.org/project/SQLAlchemy/>`_ must be installed
|
92
|
+
in your environment to use this connection. You must also install your
|
93
|
+
driver, such as ``pyodbc`` or ``psycopg2``.
|
94
|
+
|
95
|
+
.. |sqlalchemy.engine.URL.create()| replace:: ``sqlalchemy.engine.URL.create()``
|
96
|
+
.. _sqlalchemy.engine.URL.create(): https://docs.sqlalchemy.org/en/20/core/engines.html#sqlalchemy.engine.URL.create
|
97
|
+
.. |sqlalchemy.engine.make_url()| replace:: ``sqlalchemy.engine.make_url()``
|
98
|
+
.. _sqlalchemy.engine.make_url(): https://docs.sqlalchemy.org/en/20/core/engines.html#sqlalchemy.engine.make_url
|
99
|
+
.. |sqlalchemy.create_engine()| replace:: ``sqlalchemy.create_engine()``
|
100
|
+
.. _sqlalchemy.create_engine(): https://docs.sqlalchemy.org/en/20/core/engines.html#sqlalchemy.create_engine
|
101
|
+
|
102
|
+
Examples
|
103
|
+
--------
|
104
|
+
|
105
|
+
**Example 1: Configuration with URL**
|
106
|
+
|
107
|
+
You can configure your SQL connection using Streamlit's
|
108
|
+
`Secrets management <https://docs.streamlit.io/develop/concepts/connections/secrets-management>`_.
|
109
|
+
The following example specifies a SQL connection URL.
|
110
|
+
|
111
|
+
``.streamlit/secrets.toml``:
|
112
|
+
|
113
|
+
>>> [connections.sql]
|
114
|
+
>>> url = "xxx+xxx://xxx:xxx@xxx:xxx/xxx"
|
115
|
+
|
116
|
+
Your app code:
|
56
117
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
118
|
+
>>> import streamlit as st
|
119
|
+
>>>
|
120
|
+
>>> conn = st.connection("sql")
|
121
|
+
>>> df = conn.query("SELECT * FROM pet_owners")
|
122
|
+
>>> st.dataframe(df)
|
61
123
|
|
62
|
-
|
63
|
-
initialized directly. Connection parameters for a SQLConnection can be specified
|
64
|
-
using either ``st.secrets`` or ``**kwargs``. Some frequently used parameters include:
|
124
|
+
**Example 2: Configuration with dialect, host, and username**
|
65
125
|
|
66
|
-
|
67
|
-
|
68
|
-
|
126
|
+
If you do not specify ``url``, you must at least specify ``dialect``,
|
127
|
+
``host``, and ``username`` instead. The following example also includes
|
128
|
+
``password``.
|
69
129
|
|
70
|
-
|
71
|
-
`snowflake-sqlalchemy <https://github.com/snowflakedb/snowflake-sqlalchemy#key-pair-authentication-support>`_
|
72
|
-
or `Google BigQuery <https://github.com/googleapis/python-bigquery-sqlalchemy#authentication>`_.
|
73
|
-
These can also be passed directly as ``**kwargs`` to connection().
|
130
|
+
``.streamlit/secrets.toml``:
|
74
131
|
|
75
|
-
|
132
|
+
>>> [connections.sql]
|
133
|
+
>>> dialect = "xxx"
|
134
|
+
>>> host = "xxx"
|
135
|
+
>>> username = "xxx"
|
136
|
+
>>> password = "xxx"
|
137
|
+
|
138
|
+
Your app code:
|
76
139
|
|
77
|
-
Example
|
78
|
-
-------
|
79
140
|
>>> import streamlit as st
|
80
141
|
>>>
|
81
142
|
>>> conn = st.connection("sql")
|
82
|
-
>>> df = conn.query("
|
143
|
+
>>> df = conn.query("SELECT * FROM pet_owners")
|
144
|
+
>>> st.dataframe(df)
|
145
|
+
|
146
|
+
**Example 3: Configuration with keyword arguments**
|
147
|
+
|
148
|
+
You can configure your SQL connection with keyword arguments (with or
|
149
|
+
without ``secrets.toml``). For example, if you use Microsoft Entra ID with
|
150
|
+
a Microsoft Azure SQL server, you can quickly set up a local connection for
|
151
|
+
development using `interactive authentication
|
152
|
+
<https://learn.microsoft.com/en-us/sql/connect/odbc/using-azure-active-directory?view=sql-server-ver16#new-andor-modified-dsn-and-connection-string-keywords>`_.
|
153
|
+
|
154
|
+
This example requires the `Microsoft ODBC Driver for SQL Server
|
155
|
+
<https://learn.microsoft.com/en-us/sql/connect/odbc/microsoft-odbc-driver-for-sql-server?view=sql-server-ver16>`_
|
156
|
+
for *Windows* in addition to the ``sqlalchemy`` and ``pyodbc`` packages for
|
157
|
+
Python.
|
158
|
+
|
159
|
+
>>> import streamlit as st
|
160
|
+
>>>
|
161
|
+
>>> conn = st.connection(
|
162
|
+
... "sql",
|
163
|
+
... dialect="mssql",
|
164
|
+
... driver="pyodbc",
|
165
|
+
... host="xxx.database.windows.net",
|
166
|
+
... database="xxx",
|
167
|
+
... username="xxx",
|
168
|
+
... query={
|
169
|
+
... "driver": "ODBC Driver 18 for SQL Server",
|
170
|
+
... "authentication": "ActiveDirectoryInteractive",
|
171
|
+
... "encrypt": "yes",
|
172
|
+
... },
|
173
|
+
... )
|
174
|
+
>>>
|
175
|
+
>>> df = conn.query("SELECT * FROM pet_owners")
|
83
176
|
>>> st.dataframe(df)
|
177
|
+
|
84
178
|
"""
|
85
179
|
|
86
180
|
def _connect(self, autocommit: bool = False, **kwargs) -> Engine:
|
@@ -140,15 +234,15 @@ class SQLConnection(BaseConnection["Engine"]):
|
|
140
234
|
) -> DataFrame:
|
141
235
|
"""Run a read-only query.
|
142
236
|
|
143
|
-
This method implements
|
144
|
-
identical to that of using
|
237
|
+
This method implements query result caching and simple error
|
238
|
+
handling/retries. The caching behavior is identical to that of using
|
239
|
+
``@st.cache_data``.
|
145
240
|
|
146
241
|
.. note::
|
147
242
|
Queries that are run without a specified ttl are cached indefinitely.
|
148
243
|
|
149
|
-
|
150
|
-
|
151
|
-
and have the behavior described in the pandas documentation.
|
244
|
+
All keyword arguments passed to this function are passed down to
|
245
|
+
|pandas.read_sql|_, except ``ttl``.
|
152
246
|
|
153
247
|
.. |pandas.read_sql| replace:: ``pandas.read_sql``
|
154
248
|
.. _pandas.read_sql: https://pandas.pydata.org/docs/reference/api/pandas.read_sql.html
|
@@ -192,7 +286,7 @@ class SQLConnection(BaseConnection["Engine"]):
|
|
192
286
|
>>>
|
193
287
|
>>> conn = st.connection("sql")
|
194
288
|
>>> df = conn.query(
|
195
|
-
... "
|
289
|
+
... "SELECT * FROM pet_owners WHERE owner = :owner",
|
196
290
|
... ttl=3600,
|
197
291
|
... params={"owner": "barbara"},
|
198
292
|
... )
|
@@ -259,12 +353,17 @@ class SQLConnection(BaseConnection["Engine"]):
|
|
259
353
|
|
260
354
|
def connect(self) -> SQLAlchemyConnection:
|
261
355
|
"""Call ``.connect()`` on the underlying SQLAlchemy Engine, returning a new\
|
262
|
-
|
356
|
+
connection object.
|
263
357
|
|
264
358
|
Calling this method is equivalent to calling ``self._instance.connect()``.
|
265
359
|
|
266
360
|
NOTE: This method should not be confused with the internal ``_connect`` method used
|
267
361
|
to implement a Streamlit Connection.
|
362
|
+
|
363
|
+
Returns
|
364
|
+
-------
|
365
|
+
sqlalchemy.engine.Connection
|
366
|
+
A new SQLAlchemy connection object.
|
268
367
|
"""
|
269
368
|
return self._instance.connect()
|
270
369
|
|
@@ -273,6 +372,11 @@ class SQLConnection(BaseConnection["Engine"]):
|
|
273
372
|
"""The underlying SQLAlchemy Engine.
|
274
373
|
|
275
374
|
This is equivalent to accessing ``self._instance``.
|
375
|
+
|
376
|
+
Returns
|
377
|
+
-------
|
378
|
+
sqlalchemy.engine.base.Engine
|
379
|
+
The underlying SQLAlchemy Engine.
|
276
380
|
"""
|
277
381
|
return self._instance
|
278
382
|
|
@@ -281,6 +385,11 @@ class SQLConnection(BaseConnection["Engine"]):
|
|
281
385
|
"""The name of the driver used by the underlying SQLAlchemy Engine.
|
282
386
|
|
283
387
|
This is equivalent to accessing ``self._instance.driver``.
|
388
|
+
|
389
|
+
Returns
|
390
|
+
-------
|
391
|
+
str
|
392
|
+
The name of the driver. For example, ``"pyodbc"`` or ``"psycopg2"``.
|
284
393
|
"""
|
285
394
|
return cast(str, self._instance.driver)
|
286
395
|
|
@@ -296,6 +405,11 @@ class SQLConnection(BaseConnection["Engine"]):
|
|
296
405
|
<https://docs.sqlalchemy.org/en/20/orm/session_basics.html>`_ docs also contain
|
297
406
|
much more information on the usage of sessions.
|
298
407
|
|
408
|
+
Returns
|
409
|
+
-------
|
410
|
+
sqlalchemy.orm.Session
|
411
|
+
A SQLAlchemy Session.
|
412
|
+
|
299
413
|
Example
|
300
414
|
-------
|
301
415
|
>>> import streamlit as st
|