-
Notifications
You must be signed in to change notification settings - Fork 285
Update deploy example to use snowcli 2.0 #58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
sfc-gh-zblackwood
wants to merge
5
commits into
Snowflake-Labs:main
Choose a base branch
from
sfc-gh-zblackwood:snowcli-2-update
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
186b3bb
Update deploy example to use snowcli 2.0
sfc-gh-zblackwood d9b38e4
Fix type hint
sfc-gh-zblackwood 5b06450
Update environment.yml
sfc-gh-zblackwood f5c778a
Fix version syntax
sfc-gh-zblackwood c75172e
Fix version
sfc-gh-zblackwood File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -109,5 +109,7 @@ geospatial/streamlit-apps/.streamlit/.DS_Store | |
| .DS_Store | ||
| *.toml | ||
|
|
||
| *.pyc | ||
|
|
||
| .envrc | ||
| .direnv | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,11 +5,44 @@ Often when developing SiS apps, you might want to graduate from the Snowsight UI | |
| - Install the right dependencies | ||
| - Test and deploy your SiS apps from the command line | ||
|
|
||
| If you have issues with this example, feel free to open an issue, talk to your SE, or email me at [email protected]. You can find full documentation for the snowcli [here](https://github.com/Snowflake-Labs/snowcli) and specific documentation for the snowcli and SiS [here](https://docs.snowflake.com/LIMITEDACCESS/snowcli/streamlit-apps/overview). | ||
| If you have issues with this example, feel free to open an issue, talk to your SE, or email me at [email protected] or [email protected]. You can find full documentation for the snowcli [here](https://github.com/Snowflake-Labs/snowcli) and specific documentation for the snowcli and SiS [here](https://docs.snowflake.com/LIMITEDACCESS/snowcli-v2/streamlit-apps/). | ||
|
|
||
| # Install snowcli | ||
|
|
||
| ```sh | ||
| pip install snowflake-cli-labs==2.0.0 | ||
| ``` | ||
|
|
||
| # Download this folder | ||
|
|
||
| You can either download the files individually, clone this repo in git, or download the whole folder | ||
| by pasting this page's url in https://download-directory.github.io | ||
|
|
||
| NOTE: you can get a similar setup by simply doing | ||
| ``` | ||
| snow streamlit create my_app_name | ||
| ``` | ||
|
|
||
| Here's a brief summary of the files in the repo | ||
|
|
||
| ├── .streamlit | ||
| │ └── secrets.toml # This is where your credentials go for testing your app locally | ||
| ├── common | ||
| │ ├── get_data.py # Some functions for loading the sample data from Snowflake | ||
| │ └── utils.py # Some general utilty methods | ||
| ├── environment.yml # Defines the python packages your app will use | ||
| ├── event_data.csv # Some sample data | ||
| ├── pages | ||
| │ └── users.py # An example page | ||
| ├── snowflake.yml # Specifies your app's name and files for snowcli | ||
| └── streamlit_app.py # An example home page | ||
|
|
||
| Once you've downloaded the folder, unzip it if necessary and go into it. | ||
|
|
||
| # Secrets | ||
|
|
||
| Create your Streamlit secrets file (.streamlit/secrets.toml) and fill it out with the information below. | ||
| Edit the file called `.streamlit/secrets.toml` information below ( | ||
| everything in <BRACKETS> should be filled in with your specific info): | ||
|
|
||
| ```toml | ||
| [connections.snowflake] | ||
|
|
@@ -22,10 +55,16 @@ schema = "<SCHEMA>" | |
| warehouse = "<WAREHOUSE>" | ||
| ``` | ||
|
|
||
| Edit your global Snowflake config file (~/.snowflake/config.toml) with the information below. | ||
| Now add the same info to the global Snowflake config file (~/.snowflake/config.toml) by running | ||
| ```sh | ||
| snow connection add --connection-name default | ||
| ``` | ||
| and putting in the same account, username, etc. as you put in your secrets.toml. | ||
|
|
||
| You can look at `~/.snowflake/config.toml` and you should see an entry that looks like this. | ||
|
|
||
| ```toml | ||
| [connections.dev] | ||
| [connections.default] | ||
| account = "<ACCOUNT>" | ||
| user = "<USERNAME>" | ||
| authenticator = "externalbrowser" | ||
|
|
@@ -37,28 +76,68 @@ warehouse = "<WAREHOUSE>" | |
|
|
||
| # Set up local environment | ||
|
|
||
| Because streamlit-in-snowflake uses conda to install and packages, it's best to install | ||
| conda locally and use that. These are defined in environment.yml | ||
|
|
||
| ```yml | ||
| name: sf_env | ||
| channels: | ||
| - snowflake | ||
| dependencies: | ||
| - python=3.8.12 # The latest python available in snowflake as of 2024-02-12 | ||
| - streamlit=1.26.0 # The latest streamlit available in snowflake as of 2024-02-12 | ||
| - snowflake-snowpark-python | ||
| - plotly | ||
| ``` | ||
|
|
||
| If you want to use other packages, just check that they're available on the Snowflake | ||
| anaconda channel https://repo.anaconda.com/pkgs/snowflake/, and if they're on there, | ||
| they should work fine. | ||
|
|
||
| You can then install conda locally and create a conda environment from this file | ||
|
|
||
| ```sh | ||
| pip install snowflake-cli-labs==1.2.1 | ||
| brew install miniconda | ||
| conda env update | ||
| conda activate sis-deploy | ||
| conda activate sf_env | ||
| ``` | ||
|
|
||
| # Generate data | ||
| # Update files | ||
|
|
||
| `python generate_data.py` | ||
| Update `snowflake.yml` to have the name and warehouse you want to use | ||
|
|
||
| You need to upload this data to a table in Snowflake, feel free to upload in the Snowsight UI [here](https://docs.snowflake.com/en/user-guide/data-load-web-ui). | ||
| ```yml | ||
| definition_version: 1 | ||
| streamlit: | ||
| name: streamlit_app | ||
| query_warehouse: my_streamlit_warehouse # Note that an XS warehouse is recommended | ||
| main_file: streamlit_app.py | ||
| env_file: environment.yml | ||
| pages_dir: pages/ | ||
| additional_source_files: | ||
| - common/*.py | ||
| ``` | ||
|
|
||
| # Upload data | ||
|
|
||
| There is a file called `event_data.csv`, which you can download and then upload into a table in Snowflake. | ||
| You can do this by by uploading it through the Snowsight UI [here](https://docs.snowflake.com/en/user-guide/data-load-web-ui). | ||
|
|
||
| Once you have uploaded the file, update `TABLE_NAME` in `common/get_data.py` to the | ||
| full location of the table. | ||
|
|
||
| # Test locally | ||
|
|
||
| To test and debug the app locally, run: | ||
|
|
||
| ```sh | ||
| streamlit run app.py | ||
| streamlit run streamlit_app.py | ||
| ``` | ||
|
|
||
| # Deployment | ||
|
|
||
| To deploy the app to Snowflake, run: | ||
|
|
||
| ```sh | ||
| snow streamlit deploy MY_APP --replace --query-warehouse=MY_WAREHOUSE | ||
| snow stage put "*.py" DATABASE.SCHEMA.streamlit/MY_APP --overwrite | ||
| snow streamlit deploy --open | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,6 @@ | |
| import re | ||
| import time | ||
| from contextlib import contextmanager | ||
| from datetime import date | ||
| from functools import reduce | ||
| from typing import Mapping, cast | ||
|
|
||
|
|
@@ -242,76 +241,6 @@ def format_sql_from_df(df: DataFrame, use_header: bool = True) -> str: | |
| return header + format_sql(str(df._plan.queries[0].sql)) | ||
|
|
||
|
|
||
| @st.cache_data | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like this way better without |
||
| def get_download_link(_session: Session, df: pd.DataFrame, filename: str) -> str: | ||
| """ | ||
| Get download link for a dataframe. | ||
| Before this works, you need to create a stage using this command: | ||
| ``` | ||
| CREATE OR REPLACE STAGE {temp_stage} | ||
| ENCRYPTION = (TYPE = 'SNOWFLAKE_SSE') | ||
| FILE_FORMAT = (TYPE = CSV, COMPRESSION = NONE) | ||
| ``` | ||
| """ | ||
| temp_stage = "TEMP_STAGE_DOWNLOAD" | ||
|
|
||
| db = _session.get_current_database() | ||
| schema = _session.get_current_schema() | ||
| full_temp_stage = f"@{db}.{schema}.{temp_stage}" | ||
| snowpark_df = _session.create_dataframe(df) | ||
|
|
||
| snowpark_df.write.copy_into_location( | ||
| f"{full_temp_stage}/{filename}", | ||
| header=True, | ||
| overwrite=True, | ||
| single=True, | ||
| ) | ||
|
|
||
| res = _session.sql( | ||
| f"select get_presigned_url({full_temp_stage}, '{filename}', 3600) as url" | ||
| ).collect() | ||
| url = res[0]["URL"] | ||
|
|
||
| return f"[Download data 📥]({url})" | ||
|
|
||
|
|
||
| def sis_download_button( | ||
| data: pd.DataFrame, filename: str | None = None, key: str | None = None | ||
| ) -> None: | ||
| """ | ||
| Adds a button to download a dataframe as a CSV file. | ||
| This is a workaround for st.download_button while it is not supported in SiS. | ||
| It uses Snowpark's get_presigned_url function to generate a link! | ||
| Args: | ||
| data (pd.DataFrame): Data to be downloaded | ||
| filename (str, optional): Filename. Defaults to None. | ||
| key (str, optional): Key of the streamlit button. Defaults to None. | ||
| """ | ||
|
|
||
| data_hash = hashlib.sha256(pd.util.hash_pandas_object(data).values).hexdigest() | ||
|
|
||
| if filename is None: | ||
| filename = f"{data_hash}_{date.today()}.csv" | ||
|
|
||
| if key is None: | ||
| key = f"{data_hash}_{filename}" | ||
|
|
||
| if st.button("Get link to download CSV", key=key): | ||
| if data.empty: | ||
| st.error("No data") | ||
| else: | ||
| st.info( | ||
| """ | ||
| Right click on the link below and select 'open in new tab' to download the | ||
| data. | ||
| """ | ||
| ) | ||
| session = SnowparkConnection().connect() | ||
| st.write(get_download_link(session, data, filename)) | ||
|
|
||
|
|
||
| @contextmanager | ||
| def tile_ctx( | ||
| df: sp.DataFrame | pd.DataFrame, | ||
|
|
@@ -380,9 +309,12 @@ def tile_ctx( | |
| pd.util.hash_pandas_object(data).values | ||
| ).hexdigest() | ||
|
|
||
| sis_download_button( | ||
| data=data, | ||
| key=f"{description}_{data_hash}", | ||
| st.download_button( | ||
| "Download data as csv", | ||
| data.to_csv(index=False), | ||
| "data.csv", | ||
| mime="text/csv", | ||
| key=data_hash, | ||
| ) | ||
|
|
||
| # When dataframe is a Snowpark dataframe, the SQL query is not explicitly passed | ||
|
|
@@ -407,7 +339,7 @@ def tile_ctx( | |
| def tile( | ||
| df: sp.DataFrame | pd.DataFrame, | ||
| description: str, | ||
| chart: alt.Chart | Figure | alt.LayerChart | None = None, | ||
| chart: alt.Chart | alt.LayerChart | Figure | None = None, | ||
| sql: str | None = None, | ||
| skip_chart: bool = False, | ||
| ) -> None: | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,8 @@ | ||
| name: sis-deploy | ||
| name: sf_env | ||
| channels: | ||
| - snowflake | ||
| - snowflake | ||
| dependencies: | ||
| - python=3.8.12 | ||
| - streamlit=1.22.0 | ||
| - snowflake-snowpark-python | ||
| - plotly=5.9.0 | ||
| - sqlparse | ||
| - python=3.8.12 | ||
| - streamlit=1.26.0 | ||
| - snowflake-snowpark-python | ||
| - plotly |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so streamlit is 1.22 in SiS for most customers right now, we should be going into a public preview next week so I think this is fine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, good catch. Should I update the comment to reflect the date, or is this fine as-is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nah it is fine as is I think