Skip to content

Commit

Permalink
v1.2.0 update (#7)
Browse files Browse the repository at this point in the history
- Add setup.py and editable install
- Update environment.yml to create the editable install
- Sproc now returns a table
- Set OpenSSL version to address this issue: wbond/oscrypto#75
- Consolidate test req's into requirements.txt
- Update README for the corresponding changes above
  • Loading branch information
sfc-gh-jfreeberg authored Aug 8, 2023
1 parent 8639aa6 commit 32d440f
Show file tree
Hide file tree
Showing 16 changed files with 131 additions and 123 deletions.
50 changes: 22 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,20 @@ Set the following environment variables with your Snowflake account information:

```bash
# Linux/MacOS
set SNOWSQL_ACCOUNT=<replace with your account identifer>
set SNOWSQL_USER=<replace with your username>
set SNOWSQL_PWD=<replace with your password>
set SNOWSQL_DATABASE=<replace with your database>
set SNOWSQL_SCHEMA=<replace with your schema>
set SNOWSQL_WAREHOUSE=<replace with your warehouse>
export SNOWSQL_ACCOUNT=<replace with your account identifer>
export SNOWSQL_USER=<replace with your username>
export SNOWSQL_ROLE=<replace with your role>
export SNOWSQL_PWD=<replace with your password>
export SNOWSQL_DATABASE=<replace with your database>
export SNOWSQL_SCHEMA=<replace with your schema>
export SNOWSQL_WAREHOUSE=<replace with your warehouse>
```

```powershell
# Windows/PowerShell
$env:SNOWSQL_ACCOUNT = "<replace with your account identifer>"
$env:SNOWSQL_USER = "<replace with your username>"
$env:SNOWSQL_ROLE = "<replace with your role>"
$env:SNOWSQL_PWD = "<replace with your password>"
$env:SNOWSQL_DATABASE = "<replace with your database>"
$env:SNOWSQL_SCHEMA = "<replace with your schema>"
Expand All @@ -31,38 +33,37 @@ using the System Properties menu (on Windows).

### Install dependencies

Set up a virtual environment using [Anaconda](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-with-commands) or [virtualenv](https://docs.python.org/3/library/venv.html).

#### Anaconda
Create and activate a conda environment using [Anaconda](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-with-commands):

```bash
conda env create -f environment.yml
conda env create --file environment.yml
conda activate snowpark
```

#### Virtualenv
### Configure IDE

```bash
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```
#### VS Code

Press `Ctrl`+`Shift`+`P` to open the command palette, then select **Python: Select Interpreter** and select the **snowpark** interpreter under the **Conda** list.

#### PyCharm

Go to **File** > **Settings** > **Project** > **Python Interpreter** and select the snowpark interpreter.

## Prereqs

To develop your applications locally, you will need

- A Snowflake account
- Python 3.8
- Python 3.8 or greater
- An IDE or code editor (VS Code, PyCharm, etc.)

## Usage

Once you've set your credentials and installed the packages, you can test your connection to Snowflake by executing the stored procedure in [`app.py`](src/procs/app.py):

```
cd src
python procs/app.py
```bash
python src/app.py
```

You should see the following output:
Expand All @@ -80,8 +81,7 @@ You should see the following output:

You can run the test suite locally from the project root:

```
pip install -r requirements-test.txt
```bash
python -m pytest
```

Expand All @@ -90,12 +90,6 @@ python -m pytest
The GitHub Actions [workflow file](.github/workflows/build-and-deploy.yml) allows you to continously deploy your objects to Snowflake. When you're ready,
create secrets in your GitHub repository with the same name and values as the environment variables you created earler (`SNOWSQL_PWD`, `SNOWSQL_ACCOUNT`, etc.). The workflow will create a stage, upload the Python source code, and create the stored procedure object. For more information, see [`resources.sql`](resources.sql).

## Project Structure

- [procs/](src/procs/): Directory for stored procedures
- [udf/](src/udf/): Directory for your user-defined functions
- [util/](src/util/): Directory for methods/classes shared between UDFs and procedures

## Docs

- [Snowpark Developer Guide for Python](https://docs.snowflake.com/en/developer-guide/snowpark/python/index)
Expand Down
1 change: 0 additions & 1 deletion app.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
snowsql_config_path = ""
snowsql_connection_name = ""

[dev]
database = ""
schema = ""
role = ""
Expand Down
9 changes: 4 additions & 5 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ name: snowpark
channels:
- snowflake
dependencies:
- python=3.8
- python=3.9
- openssl=3.0.9 # Addresses this issue with oscrypto: https://github.com/wbond/oscrypto/issues/75
- pip
- snowflake-snowpark-python
- toml
- tomli
- pip:
- "-r requirements-test.txt"
- "-r requirements.txt"
- "--editable ."
2 changes: 0 additions & 2 deletions requirements-test.txt

This file was deleted.

4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
snowflake-snowpark-python
snowflake-snowpark-python[pandas]
tomli
toml
pytest
snowflake-vcrpy @ git+https://github.com/Snowflake-Labs/[email protected]
6 changes: 3 additions & 3 deletions resources.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ CREATE STAGE IF NOT EXISTS artifacts;
PUT file://&artifact_name @artifacts AUTO_COMPRESS=FALSE OVERWRITE=TRUE;

CREATE OR REPLACE PROCEDURE HELLO_WORLD_PROC()
RETURNS integer
RETURNS TABLE()
LANGUAGE PYTHON
RUNTIME_VERSION = 3.8
IMPORTS = ('@artifacts/&artifact_name')
HANDLER = 'src.procs.app.run'
HANDLER = 'src.app.run'
PACKAGES = ('pytest','snowflake-snowpark-python','tomli','toml');

CREATE OR REPLACE FUNCTION COMBINE(a String, b String)
RETURNS String
LANGUAGE PYTHON
RUNTIME_VERSION = 3.8
IMPORTS = ('@artifacts/&artifact_name')
HANDLER = 'src.udf.functions.combine'
HANDLER = 'src.functions.combine'
PACKAGES = ('pytest','snowflake-snowpark-python','tomli','toml');
12 changes: 12 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""
Run `conda env create --file environment.yaml` to create an editable
install of this project
"""

from setuptools import setup, find_packages

setup(
name="Example Snowpark Python project",
version="0.1.0",
packages=find_packages()
)
File renamed without changes.
48 changes: 48 additions & 0 deletions src/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""
An example stored procedure. __main__ provides an entrypoint for local development
and testing.
"""

from snowflake.snowpark.session import Session
from snowflake.snowpark.dataframe import col, DataFrame
from snowflake.snowpark.functions import udf
from src import functions

def run(snowpark_session: Session) -> DataFrame:
"""
A sample stored procedure which creates a small DataFrame, prints it to the
console, and returns the number of rows in the table.
"""

combine_udf = udf(functions.combine)

schema = ["col_1", "col_2"]

data = [
("Welcome to ", "Snowflake!"),
("Learn more: ", "https://www.snowflake.com/snowpark/"),
]

df = snowpark_session.create_dataframe(data, schema)

df2 = df.select(combine_udf(col("col_1"), col("col_2")).as_("hello_world")).sort(
"hello_world", ascending=False
)

return df2


if __name__ == "__main__":
# This entrypoint is used for local development (`$ python src/procs/app.py`)

from src.util.local import get_env_var_config

print("Creating session...")
session = Session.builder.configs(get_env_var_config()).create()
session.add_import(functions.__file__, 'src.functions')

print("Running stored procedure...")
result = run(session)

print("Stored procedure complete:")
result.show()
2 changes: 1 addition & 1 deletion src/udf/functions.py → src/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
This module contains the UDFs for the project.
"""


def combine(string_a: str, string_b: str) -> str:
"""
A sample UDF implementation
"""

return string_a + string_b
57 changes: 0 additions & 57 deletions src/procs/app.py

This file was deleted.

Empty file removed src/udf/__init__.py
Empty file.
16 changes: 16 additions & 0 deletions test/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
Fixtures and configurations for the PyTest suite
"""

import pytest
from snowflake.snowpark.session import Session
from src.util.local import get_env_var_config

@pytest.fixture
def session(scope='module'):
# pylint: disable=unused-argument
"""
Creates a Session object for tests
"""

return Session.builder.configs(get_env_var_config()).create()
24 changes: 0 additions & 24 deletions test/procs/test_app.py

This file was deleted.

17 changes: 17 additions & 0 deletions test/test_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""
Tests for the procedure module.
"""

from snowflake.snowpark.session import Session
from src import functions
from src.app import run

def test_app_dim(session: Session):
session.add_import(functions.__file__, 'src.functions')
expected = session.create_dataframe(
[["Welcome to Snowflake!"], ["Learn more: https://www.snowflake.com/snowpark/"]],
["hello_world"])

actual = run(session)

assert expected.collect() == actual.collect()
6 changes: 5 additions & 1 deletion test/udf/test_functions.py → test/test_functions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from src.udf.functions import combine
"""
Tests for the functions module.
"""

from src.functions import combine

def test_combine():
expected = "hello world"
actual = combine("hello ", "world")

assert expected == actual

0 comments on commit 32d440f

Please sign in to comment.