fullscript.spellbook 2.1.2__tar.gz → 2.1.4__tar.gz
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.
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/.gitlab-ci.yml +2 -6
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/PKG-INFO +11 -2
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/README.md +9 -0
- fullscript_spellbook-2.1.4/documentation/db_magic.md +98 -0
- fullscript_spellbook-2.1.4/documentation/drive_magic.md +77 -0
- fullscript_spellbook-2.1.4/documentation/sheet_magic.md +138 -0
- fullscript_spellbook-2.1.4/documentation/snowflake_key_pair_setup.md +35 -0
- fullscript_spellbook-2.1.4/documentation/stats_magic.md +154 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/fullscript.spellbook.egg-info/PKG-INFO +11 -2
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/fullscript.spellbook.egg-info/SOURCES.txt +6 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/pyproject.toml +1 -1
- fullscript_spellbook-2.1.4/requirements.txt +252 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/db_magic.py +29 -9
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/utils.py +31 -1
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/.DS_Store +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/.gitignore +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/.python-version +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/LICENSE +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/MANIFEST.in +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/fullscript.spellbook.egg-info/dependency_links.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/fullscript.spellbook.egg-info/requires.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/fullscript.spellbook.egg-info/top_level.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/setup.cfg +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/.DS_Store +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/__init__.py +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/drive_magic.py +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/sheet_magic.py +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/stats_magic.py +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/__init__.py +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/wizard1.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/wizard10.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/wizard11.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/wizard12.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/wizard2.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/wizard3.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/wizard4.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/wizard5.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/wizard6.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/wizard7.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/wizard8.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook/wizards/wizard9.txt +0 -0
- {fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/spellbook_config.yaml +0 -0
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
include:
|
|
2
2
|
- component: $CI_SERVER_FQDN/devops/ci-cd/build-python/template@0.0.2
|
|
3
|
-
- component: $CI_SERVER_FQDN/devops/ci-cd/publish-python-package/template@
|
|
3
|
+
- component: $CI_SERVER_FQDN/devops/ci-cd/publish-python-package/template@0.1.1
|
|
4
4
|
inputs:
|
|
5
|
-
public_python_package_image_tag: 87fa387a0fe221b8a630f7c0e78fbbaf6c23e9a1
|
|
6
5
|
artifacts_job_name: build_spellbook
|
|
7
|
-
- component: $CI_SERVER_FQDN/devops/ci-cd/publish-python-package/template@
|
|
6
|
+
- component: $CI_SERVER_FQDN/devops/ci-cd/publish-python-package/template@0.1.1
|
|
8
7
|
inputs:
|
|
9
|
-
public_python_package_image_tag: 87fa387a0fe221b8a630f7c0e78fbbaf6c23e9a1
|
|
10
8
|
upload_target: pypi
|
|
11
|
-
pypi_rules_config:
|
|
12
|
-
- when: always
|
|
13
9
|
artifacts_job_name: build_spellbook
|
|
14
10
|
- project: devops/ci-cd/workflow-skip-duplicate-pipelines
|
|
15
11
|
file: template.yaml
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: fullscript.spellbook
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.4
|
|
4
4
|
Summary: A simple package to make your life easier.
|
|
5
5
|
Author-email: Thomas Edwards <thomas.edwards@fullscript.com>, Gui Chagas <gui.chagas@fullscript.com>, David King <david.king@fullscript.com>, Meinhard Mare <meinhard.mare@fullscript.com>, Karsten Melchers <karsten.melchers@fullscript.com>
|
|
6
6
|
License: MIT
|
|
7
|
-
Project-URL: homepage, https://
|
|
7
|
+
Project-URL: homepage, https://github.com/Fullscript/spellbook
|
|
8
8
|
Requires-Python: <3.12,>=3.10
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
@@ -136,6 +136,7 @@ Spellbook is built to simplify your workflows and supercharge your data explorat
|
|
|
136
136
|
- [Features](#features)
|
|
137
137
|
- [Installation](#installation)
|
|
138
138
|
- [Configuration](#configuration)
|
|
139
|
+
- [Documentation](#documentation)
|
|
139
140
|
- [Contributing](#contributing)
|
|
140
141
|
- [License](#license)
|
|
141
142
|
|
|
@@ -190,6 +191,14 @@ google_accounts:
|
|
|
190
191
|
service_account: "your_base64_encoded_service_account_credentials_here" # Add your Base64-encoded service account JSON here
|
|
191
192
|
```
|
|
192
193
|
|
|
194
|
+
## Documentation
|
|
195
|
+
For detailed documentation on how to use Spellbook, please refer to the [Documentation](documentation) folder in the repository.
|
|
196
|
+
**Functionality:**
|
|
197
|
+
- [Database Magic](documentation/db_magic.md)
|
|
198
|
+
- [Drive Magic](documentation/drive_magic.md)
|
|
199
|
+
- [Sheet Magic](documentation/sheet_magic.md)
|
|
200
|
+
- [Stat Magic](documentation/stat_magic.md)
|
|
201
|
+
|
|
193
202
|
## Contributing
|
|
194
203
|
|
|
195
204
|
We welcome contributions! Please follow these steps:
|
|
@@ -17,6 +17,7 @@ Spellbook is built to simplify your workflows and supercharge your data explorat
|
|
|
17
17
|
- [Features](#features)
|
|
18
18
|
- [Installation](#installation)
|
|
19
19
|
- [Configuration](#configuration)
|
|
20
|
+
- [Documentation](#documentation)
|
|
20
21
|
- [Contributing](#contributing)
|
|
21
22
|
- [License](#license)
|
|
22
23
|
|
|
@@ -71,6 +72,14 @@ google_accounts:
|
|
|
71
72
|
service_account: "your_base64_encoded_service_account_credentials_here" # Add your Base64-encoded service account JSON here
|
|
72
73
|
```
|
|
73
74
|
|
|
75
|
+
## Documentation
|
|
76
|
+
For detailed documentation on how to use Spellbook, please refer to the [Documentation](documentation) folder in the repository.
|
|
77
|
+
**Functionality:**
|
|
78
|
+
- [Database Magic](documentation/db_magic.md)
|
|
79
|
+
- [Drive Magic](documentation/drive_magic.md)
|
|
80
|
+
- [Sheet Magic](documentation/sheet_magic.md)
|
|
81
|
+
- [Stat Magic](documentation/stat_magic.md)
|
|
82
|
+
|
|
74
83
|
## Contributing
|
|
75
84
|
|
|
76
85
|
We welcome contributions! Please follow these steps:
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
A magical wrapper to perform work with databases.
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
##### Key Features
|
|
5
|
+
* **Unified Interface**: Abstracts the complexities of connecting and interacting with Snowflake and MySQL databases.
|
|
6
|
+
* **Seamless Data Handling**: Fetch, manipulate, and write data with Pandas DataFrames.
|
|
7
|
+
* **Flexibility**: Supports secure credentials management via configuration files and environment variables.
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from spellbook import db_magic
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Methods Overview
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
##### get_data(db_name, query)
|
|
17
|
+
|
|
18
|
+
Fetches data from a specified database and returns it as a Pandas DataFrame. This method abstracts the connection and retrieval process for both Snowflake and MySQL databases, allowing you to focus on the SQL query.
|
|
19
|
+
|
|
20
|
+
Parameters:
|
|
21
|
+
* `db_name` (str): The database name defined in the configuration file.
|
|
22
|
+
* `query` (str): The SQL query to execute.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
* A Pandas DataFrame containing the result of the query.
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
# Fetch data from Snowflake
|
|
29
|
+
# Option 1:
|
|
30
|
+
query = "SELECT * FROM my_table LIMIT 10;"
|
|
31
|
+
df = db_magic.get_data("snowflake_db", query)
|
|
32
|
+
|
|
33
|
+
# Option 2:
|
|
34
|
+
df = db_magic.get_data("snowflake_db", 'my_sql_query.sql')
|
|
35
|
+
|
|
36
|
+
# Option 3:
|
|
37
|
+
df = db_magic.get_data("snowflake_db", 'user/project/my_query.sql')
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# Fetch data from MySQL
|
|
41
|
+
query = "SELECT * FROM users WHERE is_active = 1;"
|
|
42
|
+
df = db_magic.get_data("mysql_db", query)
|
|
43
|
+
|
|
44
|
+
# Display results
|
|
45
|
+
print(df.head())
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
##### write_data(db_name, schema, df, table_name, overwrite=True, chunk_size=1000, **kwargs)
|
|
49
|
+
|
|
50
|
+
Writes a Pandas DataFrame to a table in Snowflake. It supports creating tables automatically and overwriting existing tables.
|
|
51
|
+
|
|
52
|
+
Parameters:
|
|
53
|
+
* `db_name` (str): The database name defined in the configuration file.
|
|
54
|
+
* `schema` (str): The schema where the table is located.
|
|
55
|
+
* `df` (Pandas DataFrame): The data to write.
|
|
56
|
+
* `table_name` (str): The name of the destination table.
|
|
57
|
+
* `overwrite` (bool): Whether to overwrite the table if it exists (default: True).
|
|
58
|
+
* `chunk_size` (int): Number of rows to write per chunk (default: 1000).
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import pandas as pd
|
|
62
|
+
|
|
63
|
+
# Create a sample DataFrame
|
|
64
|
+
data = {"id": [1, 2, 3], "name": ["Alice", "Bob", "Charlie"]}
|
|
65
|
+
df = pd.DataFrame(data)
|
|
66
|
+
|
|
67
|
+
# Write data to Snowflake
|
|
68
|
+
db_magic.write_data("snowflake_db", "my_schema", df, "my_table", overwrite=True)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
##### run_sql(db_name, query)
|
|
72
|
+
|
|
73
|
+
Executes a SQL query directly on a specified database without returning results. Ideal for operations like creating tables, updating rows, or running stored procedures.
|
|
74
|
+
|
|
75
|
+
Parameters:
|
|
76
|
+
* `db_name` (str): The database name defined in the configuration file.
|
|
77
|
+
* `query` (str): The SQL query to execute.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
* `None`
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
|
|
84
|
+
# Execute SQL in Snowflake
|
|
85
|
+
create_table_query = """
|
|
86
|
+
CREATE TABLE my_table (
|
|
87
|
+
id INT,
|
|
88
|
+
name STRING
|
|
89
|
+
);
|
|
90
|
+
"""
|
|
91
|
+
db_magic.run_sql("snowflake_db", create_table_query)
|
|
92
|
+
|
|
93
|
+
# Execute SQL in MySQL
|
|
94
|
+
update_query = "UPDATE users SET is_active = 1 WHERE last_login > '2024-01-01';"
|
|
95
|
+
db_magic.run_sql("mysql_db", update_query)
|
|
96
|
+
|
|
97
|
+
print("SQL executed successfully!")
|
|
98
|
+
```
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
## Different Authentication Methods
|
|
2
|
+
|
|
3
|
+
This package can use 2 different authentication methods:
|
|
4
|
+
|
|
5
|
+
- Service Account: The same method we currently use in `sheet_magic`
|
|
6
|
+
- OAuth: Method where the user has to allow the script to use their credentials
|
|
7
|
+
|
|
8
|
+
Both methods have their pros and cons:
|
|
9
|
+
|
|
10
|
+
- Service Account:
|
|
11
|
+
- It's the easiest to use as one probably already has the setup ready.
|
|
12
|
+
- It can only access folders shared with the service account email (similarly as it can only access sheets we share with it)
|
|
13
|
+
- Because we're not managers of the data team's shared folders, we cannot share those folders with this account. This is a road block for now.
|
|
14
|
+
- OAuth:
|
|
15
|
+
- The user has to grant access constantly (every time the scope changes or the authentication token expires)
|
|
16
|
+
- This method can access any folder shared with you as the script will be using your identity (this includes shared folders where you're not the owner)
|
|
17
|
+
|
|
18
|
+
## OAuth Setup
|
|
19
|
+
|
|
20
|
+
Step-by-step:
|
|
21
|
+
|
|
22
|
+
1 - Access this link and follow the [OAuth client ID credentials](https://developers.google.com/workspace/guides/create-credentials#oauth-client-id) process
|
|
23
|
+
|
|
24
|
+
2 - Probably you'll be asked to setup the OAuth Consent Screen. At the second page of this part ("Scopes"), be sure to add all Google Drive API scopes.
|
|
25
|
+
|
|
26
|
+
3 - In the "Client ID for Web Application" page, add `http://localhost:3000/` as an "Authorized redirect URIs"
|
|
27
|
+
|
|
28
|
+
4 - From the same page, download the client secret as a JSON file.
|
|
29
|
+
|
|
30
|
+
5 - Now the process is similar to what is done for `'GS_SERVICE_ACCOUNT'`. Copy the contents of the JSON file.
|
|
31
|
+
|
|
32
|
+
6 - Go to the terminal and use `pbpaste | base64 | pbcopy` to paste, encode, and copy the contents again.
|
|
33
|
+
|
|
34
|
+
7 - Store the encoded contents as an envvar called `'GS_CLIENT_SECRETS'`
|
|
35
|
+
|
|
36
|
+
## Initiate
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from spellbook import drive_magic as dm
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Usage examples
|
|
43
|
+
|
|
44
|
+
##### Getting service
|
|
45
|
+
```python
|
|
46
|
+
scopes = ['https://www.googleapis.com/auth/drive.metadata.readonly',
|
|
47
|
+
'https://www.googleapis.com/auth/drive.file',
|
|
48
|
+
'https://www.googleapis.com/auth/drive.readonly',
|
|
49
|
+
'https://www.googleapis.com/auth/drive',
|
|
50
|
+
'https://www.googleapis.com/auth/drive.file',
|
|
51
|
+
'https://www.googleapis.com/auth/drive.appdata']
|
|
52
|
+
|
|
53
|
+
# service = dm.get_service(scopes=scopes, auth_type='service_account')
|
|
54
|
+
service = dm.get_service(scopes=scopes, auth_type='oauth')
|
|
55
|
+
del scopes
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
##### Listing contents of a folder
|
|
59
|
+
```python
|
|
60
|
+
folder_url = 'https://drive.google.com/drive/u/0/folders/1zgsK7EkEcYsvmiQ0InT04Bg5yBdG6b-D'
|
|
61
|
+
df_files = dm.list_folder_contents(service, folder_url)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
##### Uploading a file
|
|
65
|
+
```python
|
|
66
|
+
dm.upload_file(service, folder_url, 'samples/01_sample_pdf.pdf')
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
##### Downloading a file
|
|
70
|
+
```python
|
|
71
|
+
temp_file_id = '1JAYgOUztUNYrx5qJispiEM-B2oXdLQzO'
|
|
72
|
+
dm.download_file(service, temp_file_id, '02_sample_picture_v2.jpeg')
|
|
73
|
+
```
|
|
74
|
+
##### Deleting / thrashing a file
|
|
75
|
+
```python
|
|
76
|
+
dm.delete_file(service, temp_file_id)
|
|
77
|
+
```
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
### Key Features
|
|
2
|
+
|
|
3
|
+
1. **Sheet Management**:
|
|
4
|
+
* Create, delete, or clear sheets with ease.
|
|
5
|
+
* Access sheets by name or index.
|
|
6
|
+
2. **Data Handling**:
|
|
7
|
+
* Read and write Pandas DataFrames.
|
|
8
|
+
* Target specific ranges or clear entire sheets.
|
|
9
|
+
3. **Flexibility**:
|
|
10
|
+
* Automatically create sheets if they don’t exist.
|
|
11
|
+
* Handle trailing empty cells in row counting.
|
|
12
|
+
4. **Seamless Google Sheets Integration**:
|
|
13
|
+
* Authenticate with Google Service Account credentials.
|
|
14
|
+
* Perform operations with minimal setup.
|
|
15
|
+
|
|
16
|
+
# Setup
|
|
17
|
+
|
|
18
|
+
## Create a Google Service account
|
|
19
|
+
To use this feature, you must create a Google service account. Instructions on how to do this are available on the Google [IAM documentation](https://cloud.google.com/iam/docs/service-accounts-create#iam-service-accounts-create-console)
|
|
20
|
+
|
|
21
|
+
## Saving Your `GS_SERVICE_ACCOUNT` Environment Variable
|
|
22
|
+
How to save your 'GS_SERVICE_ACCOUNT' env-var to use this code
|
|
23
|
+
|
|
24
|
+
To use Google Service Account functionality with this code, you need to save your Google Service Account JSON as an encrypted string in an environment variable. Follow these steps:
|
|
25
|
+
1.Convert the JSON File Content to a Base64-Encoded String
|
|
26
|
+
* Copy the content of your service account JSON file to your clipboard.
|
|
27
|
+
* Open your terminal and run the following command to encode it:
|
|
28
|
+
```bash
|
|
29
|
+
pbpaste | base64 | pbcopy
|
|
30
|
+
```
|
|
31
|
+
* This command encrypts the JSON content using Base64 and places the encoded string back into your clipboard.
|
|
32
|
+
|
|
33
|
+
2.Save the Encoded String as an Environment Variable
|
|
34
|
+
* Add the encoded string as an environment variable.
|
|
35
|
+
* Use a name like GS_SERVICE_ACCOUNT for consistency.
|
|
36
|
+
|
|
37
|
+
For example, add the following line to your environment file (e.g., .env):
|
|
38
|
+
```bash
|
|
39
|
+
GS_SERVICE_ACCOUNT=your_base64_encoded_string
|
|
40
|
+
```
|
|
41
|
+
3.Why Base64 Encoding?
|
|
42
|
+
* Base64 ensures the JSON content is securely represented as a single string, making it compatible with environment variables.
|
|
43
|
+
|
|
44
|
+
Once set up, your code will securely retrieve the service account details directly from the environment variable.
|
|
45
|
+
|
|
46
|
+
## Initialize
|
|
47
|
+
|
|
48
|
+
To begin using sheet_magic, initialize the handler with the URL of the Google Sheet you want to work with.
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from spellbook import sheet_magic
|
|
52
|
+
|
|
53
|
+
# Replace with your actual Google Sheet URL
|
|
54
|
+
sheet_url = 'https://docs.google.com/spreadsheets/d/your_sheet_id/edit'
|
|
55
|
+
working_sheet = sheet_magic.GSheetsHandler(gsheet_url=sheet_url, service_account_name='my_google_service_account')
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
<div style="border-left: 6px solid #f39c12; padding: 10px; background-color: #fcf8e3;">
|
|
59
|
+
|
|
60
|
+
⚠️ **Important Notice:** In order to use sheet_magic, you need to add the Google service account to the sheet you are working on
|
|
61
|
+
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
### Usage Examples
|
|
65
|
+
|
|
66
|
+
1. Create a New Sheet
|
|
67
|
+
|
|
68
|
+
Add a new sheet to your Google Sheets document.
|
|
69
|
+
```python
|
|
70
|
+
# Create a new sheet named 'test_sheet'
|
|
71
|
+
working_sheet.create_sheet(worksheet='test_sheet')
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
2. Delete an Existing Sheet
|
|
75
|
+
|
|
76
|
+
Delete a sheet by its name or index.
|
|
77
|
+
```python
|
|
78
|
+
# Delete a sheet by its name
|
|
79
|
+
working_sheet.delete_sheet(worksheet='test_sheet')
|
|
80
|
+
|
|
81
|
+
# Delete a sheet by its index
|
|
82
|
+
working_sheet.delete_sheet(worksheet=1)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
3. Write Data to a Sheet
|
|
86
|
+
|
|
87
|
+
Write a Pandas DataFrame to a specified sheet. You can specify a starting position, and the sheet will be resized or extended as needed.
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import pandas as pd
|
|
91
|
+
|
|
92
|
+
# Sample DataFrame
|
|
93
|
+
data = {'Name': ['Alice', 'Bob'], 'Age': [25, 30]}
|
|
94
|
+
df_test = pd.DataFrame(data)
|
|
95
|
+
|
|
96
|
+
# Write DataFrame to a sheet by name
|
|
97
|
+
working_sheet.write_to_sheet(input_dataframe=df_test, worksheet='data_sheet')
|
|
98
|
+
|
|
99
|
+
# Write DataFrame to a sheet by index
|
|
100
|
+
working_sheet.write_to_sheet(input_dataframe=df_test, worksheet=2)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
4. Count Rows in a Sheet
|
|
104
|
+
|
|
105
|
+
Count the number of rows in a specified column, with an option to include trailing empty cells.
|
|
106
|
+
```python
|
|
107
|
+
# Count rows in column 1 of the sheet 'data_sheet'
|
|
108
|
+
row_count = working_sheet.count_rows(worksheet='data_sheet')
|
|
109
|
+
|
|
110
|
+
# Count rows, including empty trailing cells
|
|
111
|
+
row_count_with_empty = working_sheet.count_rows(worksheet='data_sheet', include_tailing_empty=True)
|
|
112
|
+
|
|
113
|
+
print(f"Rows in column 1: {row_count}")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
5. Clear a Range
|
|
117
|
+
|
|
118
|
+
Clear the contents of a specific range or the entire sheet.
|
|
119
|
+
```python
|
|
120
|
+
# Clear the entire sheet
|
|
121
|
+
working_sheet.clear_range(worksheet='data_sheet')
|
|
122
|
+
|
|
123
|
+
# Clear a specific range (e.g., B2:D4)
|
|
124
|
+
working_sheet.clear_range(worksheet='data_sheet', clear_range_str='B2:D4')
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
6. Read Data from a Sheet
|
|
128
|
+
|
|
129
|
+
Read data from a sheet into a Pandas DataFrame. Optionally, specify a target range.
|
|
130
|
+
```python
|
|
131
|
+
# Read all data from the sheet 'data_sheet'
|
|
132
|
+
df_read = working_sheet.read_sheet(worksheet='data_sheet')
|
|
133
|
+
|
|
134
|
+
# Read a specific range (e.g., B1:C4) from the sheet
|
|
135
|
+
df_read_partial = working_sheet.read_sheet(worksheet='data_sheet', target_range_str='B1:C4')
|
|
136
|
+
|
|
137
|
+
print(df_read.head())
|
|
138
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
A step-by-step guide to establishing a connection to Snowflake using Snowpark for Python with key-pair authentication.
|
|
2
|
+
|
|
3
|
+
### 1. Generate Key Pair:
|
|
4
|
+
* **Private Key**: Create an unencrypted private key using OpenSSL:
|
|
5
|
+
```bash
|
|
6
|
+
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt
|
|
7
|
+
```
|
|
8
|
+
> Note: If you want a passphrase for additional security, remove the `-nocrypt` flag.
|
|
9
|
+
|
|
10
|
+
* **Public Key**: Derive the public key from the private key:
|
|
11
|
+
```bash
|
|
12
|
+
openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### 2. Assign Public Key to Snowflake User (will require admin access):
|
|
16
|
+
* In Snowflake, associate the generated public key with your user account:
|
|
17
|
+
```sql
|
|
18
|
+
ALTER USER <username> SET rsa_public_key='<contents_of_rsa_key.pub>';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
* Replace `<username>` with your actual Snowflake username and `<contents_of_rsa_key.pub>` with the content of your public key file.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### 3. Base64 Encode the Private Key:
|
|
25
|
+
Since private keys are typically multi-line strings, encoding them in Base64 ensures they can be stored as single-line environment variables.
|
|
26
|
+
```bash
|
|
27
|
+
openssl base64 -in rsa_key.p8 -out rsa_key_base64.txt
|
|
28
|
+
```
|
|
29
|
+
This command reads your rsa_key.p8 file and outputs a Base64-encoded version to rsa_key_base64.txt.
|
|
30
|
+
|
|
31
|
+
### 4. Set the Environment Variable:
|
|
32
|
+
Once you have the Base64-encoded key, set it as an environment variable.
|
|
33
|
+
```bash
|
|
34
|
+
export PRIVATE_KEY_BASE64='your_base64_encoded_key_here'
|
|
35
|
+
```
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
The stats_magic module provides a suite of statistical tests and tools for analyzing datasets. It simplifies the process of conducting normality tests, variance analysis, ANOVA, and various other statistical methods. The module supports multi-group comparisons as well as two-group analyses, making it ideal for exploratory data analysis and hypothesis testing.
|
|
2
|
+
|
|
3
|
+
### Key Features
|
|
4
|
+
|
|
5
|
+
1. **Comprehensive Statistical Tests:**
|
|
6
|
+
* Covers normality, variance, mean, and median comparisons.
|
|
7
|
+
* Includes both parametric and non-parametric methods.
|
|
8
|
+
2. **Multi-Group Analysis:**
|
|
9
|
+
* Tools like ANOVA, Tukey’s, and Dunn’s tests for multi-level datasets.
|
|
10
|
+
3. **Two-Group Analysis:**
|
|
11
|
+
* Student’s t-test, Welch’s t-test, and Mann-Whitney U test for pairwise comparisons.
|
|
12
|
+
4. **Detailed Outputs:**
|
|
13
|
+
* Returns results as Pandas DataFrames for easy analysis.
|
|
14
|
+
* Supports verbose mode for detailed explanations of results.
|
|
15
|
+
|
|
16
|
+
# Setup
|
|
17
|
+
|
|
18
|
+
## Import the Module
|
|
19
|
+
To begin using stats_magic, import it into your Python environment.
|
|
20
|
+
```python
|
|
21
|
+
from spellbook import stats_magic
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Multi-Level Tests
|
|
25
|
+
|
|
26
|
+
These tests are designed for datasets with more than two groups, allowing comparisons across multiple categories.
|
|
27
|
+
|
|
28
|
+
1. **Shapiro-Wilk Normality Test**
|
|
29
|
+
|
|
30
|
+
Tests if the data in each group follows a normal distribution.
|
|
31
|
+
```python
|
|
32
|
+
shapiro_df = stats_magic.shapiro_wilk_normality_test(
|
|
33
|
+
df=df_penguins,
|
|
34
|
+
group_column='species',
|
|
35
|
+
values_column='flipper_length_mm',
|
|
36
|
+
alpha_level=0.05,
|
|
37
|
+
verbose=True
|
|
38
|
+
)
|
|
39
|
+
```
|
|
40
|
+
Key Parameters:
|
|
41
|
+
* `group_column`: The column defining groups (e.g., species).
|
|
42
|
+
* `values_column`: The column containing numeric values to test.
|
|
43
|
+
* `alpha_level`: Significance level (default 0.05).
|
|
44
|
+
* `verbose`: Print detailed output (default False).
|
|
45
|
+
|
|
46
|
+
2. **Levene’s Variance Test**
|
|
47
|
+
|
|
48
|
+
Tests if the variances across groups are equal.
|
|
49
|
+
```python
|
|
50
|
+
levene_df = stats_magic.levene_variance_test(
|
|
51
|
+
df=df_penguins,
|
|
52
|
+
group_column='species',
|
|
53
|
+
values_column='flipper_length_mm',
|
|
54
|
+
alpha_level=0.05,
|
|
55
|
+
center_method='mean',
|
|
56
|
+
verbose=True
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
Key Parameters:
|
|
60
|
+
* `center_method`: Method to calculate central tendency (mean, median, or trimmed).
|
|
61
|
+
|
|
62
|
+
3. **ANOVA**
|
|
63
|
+
|
|
64
|
+
Performs an analysis of variance to test if means across groups are significantly different.
|
|
65
|
+
```python
|
|
66
|
+
anova_df = stats_magic.anova(
|
|
67
|
+
df=df_penguins,
|
|
68
|
+
group_column='species',
|
|
69
|
+
values_column='flipper_length_mm',
|
|
70
|
+
alpha_level=0.05,
|
|
71
|
+
verbose=True
|
|
72
|
+
)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
4. **Tukey’s Test**
|
|
76
|
+
|
|
77
|
+
Conducts pairwise comparisons between group means.
|
|
78
|
+
```python
|
|
79
|
+
tukey_test_df = stats_magic.tukey_test(
|
|
80
|
+
df=df_penguins,
|
|
81
|
+
group_column='species',
|
|
82
|
+
values_column='flipper_length_mm',
|
|
83
|
+
alpha_level=0.05,
|
|
84
|
+
verbose=True
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
5. **Mood’s Median Test**
|
|
89
|
+
|
|
90
|
+
Tests if the medians across groups are significantly different.
|
|
91
|
+
```python
|
|
92
|
+
mood_median_test_df = stats_magic.mood_median_test(
|
|
93
|
+
df=df_penguins,
|
|
94
|
+
group_column='species',
|
|
95
|
+
values_column='flipper_length_mm',
|
|
96
|
+
alpha_level=0.05,
|
|
97
|
+
verbose=True
|
|
98
|
+
)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
6. **Dunn’s Test**
|
|
102
|
+
|
|
103
|
+
Performs pairwise comparisons between groups, adjusting p-values to account for multiple tests.
|
|
104
|
+
```python
|
|
105
|
+
dunn_test_df = stats_magic.dunn_test(
|
|
106
|
+
df=df_penguins,
|
|
107
|
+
group_column='species',
|
|
108
|
+
values_column='flipper_length_mm',
|
|
109
|
+
alpha_level=0.05,
|
|
110
|
+
verbose=True
|
|
111
|
+
)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Two-Level Tests
|
|
115
|
+
|
|
116
|
+
These tests are designed for datasets with exactly two groups, allowing direct comparisons between them.
|
|
117
|
+
|
|
118
|
+
**Setup: Create a Two-Group Dataset**
|
|
119
|
+
Filter the dataset to include only two groups.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
two_group_df = df_penguins[
|
|
123
|
+
(df_penguins['species'] == 'Adelie') | (df_penguins['species'] == 'Gentoo')
|
|
124
|
+
]
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
1. **Student’s t-test / Welch’s t-test**
|
|
128
|
+
|
|
129
|
+
Tests if the means of two groups are significantly different.
|
|
130
|
+
```python
|
|
131
|
+
t_welch_test_df = stats_magic.t_welch_test(
|
|
132
|
+
df=two_group_df,
|
|
133
|
+
group_column='species',
|
|
134
|
+
values_column='flipper_length_mm',
|
|
135
|
+
equal_variances=True,
|
|
136
|
+
alpha_level=0.05,
|
|
137
|
+
verbose=True
|
|
138
|
+
)
|
|
139
|
+
```
|
|
140
|
+
Key Parameters:
|
|
141
|
+
* `equal_variances`: Set to False to use Welch’s t-test for unequal variances.
|
|
142
|
+
|
|
143
|
+
2. **Mann-Whitney U Test**
|
|
144
|
+
|
|
145
|
+
Tests if the distributions of two groups are significantly different.
|
|
146
|
+
```python
|
|
147
|
+
mann_whitney_u_test_df = stats_magic.mann_whitney_u_test(
|
|
148
|
+
df=two_group_df,
|
|
149
|
+
group_column='species',
|
|
150
|
+
values_column='flipper_length_mm',
|
|
151
|
+
alpha_level=0.05,
|
|
152
|
+
verbose=True
|
|
153
|
+
)
|
|
154
|
+
```
|
{fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/fullscript.spellbook.egg-info/PKG-INFO
RENAMED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: fullscript.spellbook
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.4
|
|
4
4
|
Summary: A simple package to make your life easier.
|
|
5
5
|
Author-email: Thomas Edwards <thomas.edwards@fullscript.com>, Gui Chagas <gui.chagas@fullscript.com>, David King <david.king@fullscript.com>, Meinhard Mare <meinhard.mare@fullscript.com>, Karsten Melchers <karsten.melchers@fullscript.com>
|
|
6
6
|
License: MIT
|
|
7
|
-
Project-URL: homepage, https://
|
|
7
|
+
Project-URL: homepage, https://github.com/Fullscript/spellbook
|
|
8
8
|
Requires-Python: <3.12,>=3.10
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
@@ -136,6 +136,7 @@ Spellbook is built to simplify your workflows and supercharge your data explorat
|
|
|
136
136
|
- [Features](#features)
|
|
137
137
|
- [Installation](#installation)
|
|
138
138
|
- [Configuration](#configuration)
|
|
139
|
+
- [Documentation](#documentation)
|
|
139
140
|
- [Contributing](#contributing)
|
|
140
141
|
- [License](#license)
|
|
141
142
|
|
|
@@ -190,6 +191,14 @@ google_accounts:
|
|
|
190
191
|
service_account: "your_base64_encoded_service_account_credentials_here" # Add your Base64-encoded service account JSON here
|
|
191
192
|
```
|
|
192
193
|
|
|
194
|
+
## Documentation
|
|
195
|
+
For detailed documentation on how to use Spellbook, please refer to the [Documentation](documentation) folder in the repository.
|
|
196
|
+
**Functionality:**
|
|
197
|
+
- [Database Magic](documentation/db_magic.md)
|
|
198
|
+
- [Drive Magic](documentation/drive_magic.md)
|
|
199
|
+
- [Sheet Magic](documentation/sheet_magic.md)
|
|
200
|
+
- [Stat Magic](documentation/stat_magic.md)
|
|
201
|
+
|
|
193
202
|
## Contributing
|
|
194
203
|
|
|
195
204
|
We welcome contributions! Please follow these steps:
|
{fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/fullscript.spellbook.egg-info/SOURCES.txt
RENAMED
|
@@ -6,7 +6,13 @@ LICENSE
|
|
|
6
6
|
MANIFEST.in
|
|
7
7
|
README.md
|
|
8
8
|
pyproject.toml
|
|
9
|
+
requirements.txt
|
|
9
10
|
spellbook_config.yaml
|
|
11
|
+
documentation/db_magic.md
|
|
12
|
+
documentation/drive_magic.md
|
|
13
|
+
documentation/sheet_magic.md
|
|
14
|
+
documentation/snowflake_key_pair_setup.md
|
|
15
|
+
documentation/stats_magic.md
|
|
10
16
|
fullscript.spellbook.egg-info/PKG-INFO
|
|
11
17
|
fullscript.spellbook.egg-info/SOURCES.txt
|
|
12
18
|
fullscript.spellbook.egg-info/dependency_links.txt
|
|
@@ -16,7 +16,7 @@ authors = [
|
|
|
16
16
|
{name = "Meinhard Mare", email = "meinhard.mare@fullscript.com"},
|
|
17
17
|
{name = "Karsten Melchers", email = "karsten.melchers@fullscript.com"}
|
|
18
18
|
]
|
|
19
|
-
urls = {homepage = "https://
|
|
19
|
+
urls = {homepage = "https://github.com/Fullscript/spellbook"}
|
|
20
20
|
dependencies = [
|
|
21
21
|
"appnope==0.1.4",
|
|
22
22
|
"asn1crypto==1.5.1",
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This file is autogenerated by pip-compile with Python 3.11
|
|
3
|
+
# by the following command:
|
|
4
|
+
#
|
|
5
|
+
# pip-compile
|
|
6
|
+
#
|
|
7
|
+
appnope==0.1.4
|
|
8
|
+
# via
|
|
9
|
+
# fullscript.spellbook (pyproject.toml)
|
|
10
|
+
# ipykernel
|
|
11
|
+
asn1crypto==1.5.1
|
|
12
|
+
# via
|
|
13
|
+
# fullscript.spellbook (pyproject.toml)
|
|
14
|
+
# snowflake-connector-python
|
|
15
|
+
asttokens==2.4.1
|
|
16
|
+
# via
|
|
17
|
+
# fullscript.spellbook (pyproject.toml)
|
|
18
|
+
# stack-data
|
|
19
|
+
certifi==2024.8.30
|
|
20
|
+
# via
|
|
21
|
+
# fullscript.spellbook (pyproject.toml)
|
|
22
|
+
# requests
|
|
23
|
+
# snowflake-connector-python
|
|
24
|
+
cffi==1.17.1
|
|
25
|
+
# via
|
|
26
|
+
# cryptography
|
|
27
|
+
# fullscript.spellbook (pyproject.toml)
|
|
28
|
+
# snowflake-connector-python
|
|
29
|
+
charset-normalizer==3.4.0
|
|
30
|
+
# via
|
|
31
|
+
# fullscript.spellbook (pyproject.toml)
|
|
32
|
+
# requests
|
|
33
|
+
# snowflake-connector-python
|
|
34
|
+
cloudpickle==2.2.1
|
|
35
|
+
# via
|
|
36
|
+
# fullscript.spellbook (pyproject.toml)
|
|
37
|
+
# snowflake-snowpark-python
|
|
38
|
+
comm==0.2.2
|
|
39
|
+
# via
|
|
40
|
+
# fullscript.spellbook (pyproject.toml)
|
|
41
|
+
# ipykernel
|
|
42
|
+
cryptography==43.0.3
|
|
43
|
+
# via
|
|
44
|
+
# fullscript.spellbook (pyproject.toml)
|
|
45
|
+
# pyopenssl
|
|
46
|
+
# snowflake-connector-python
|
|
47
|
+
debugpy==1.8.8
|
|
48
|
+
# via
|
|
49
|
+
# fullscript.spellbook (pyproject.toml)
|
|
50
|
+
# ipykernel
|
|
51
|
+
decorator==5.1.1
|
|
52
|
+
# via
|
|
53
|
+
# fullscript.spellbook (pyproject.toml)
|
|
54
|
+
# ipython
|
|
55
|
+
executing==2.1.0
|
|
56
|
+
# via
|
|
57
|
+
# fullscript.spellbook (pyproject.toml)
|
|
58
|
+
# stack-data
|
|
59
|
+
filelock==3.16.1
|
|
60
|
+
# via
|
|
61
|
+
# fullscript.spellbook (pyproject.toml)
|
|
62
|
+
# snowflake-connector-python
|
|
63
|
+
idna==3.10
|
|
64
|
+
# via
|
|
65
|
+
# fullscript.spellbook (pyproject.toml)
|
|
66
|
+
# requests
|
|
67
|
+
# snowflake-connector-python
|
|
68
|
+
ipykernel==6.29.5
|
|
69
|
+
# via fullscript.spellbook (pyproject.toml)
|
|
70
|
+
ipython==8.29.0
|
|
71
|
+
# via
|
|
72
|
+
# fullscript.spellbook (pyproject.toml)
|
|
73
|
+
# ipykernel
|
|
74
|
+
jedi==0.19.2
|
|
75
|
+
# via
|
|
76
|
+
# fullscript.spellbook (pyproject.toml)
|
|
77
|
+
# ipython
|
|
78
|
+
jupyter-client==8.6.3
|
|
79
|
+
# via
|
|
80
|
+
# fullscript.spellbook (pyproject.toml)
|
|
81
|
+
# ipykernel
|
|
82
|
+
jupyter-core==5.7.2
|
|
83
|
+
# via
|
|
84
|
+
# fullscript.spellbook (pyproject.toml)
|
|
85
|
+
# ipykernel
|
|
86
|
+
# jupyter-client
|
|
87
|
+
matplotlib-inline==0.1.7
|
|
88
|
+
# via
|
|
89
|
+
# fullscript.spellbook (pyproject.toml)
|
|
90
|
+
# ipykernel
|
|
91
|
+
# ipython
|
|
92
|
+
nest-asyncio==1.6.0
|
|
93
|
+
# via
|
|
94
|
+
# fullscript.spellbook (pyproject.toml)
|
|
95
|
+
# ipykernel
|
|
96
|
+
numpy==2.1.3
|
|
97
|
+
# via
|
|
98
|
+
# fullscript.spellbook (pyproject.toml)
|
|
99
|
+
# pandas
|
|
100
|
+
packaging==24.2
|
|
101
|
+
# via
|
|
102
|
+
# fullscript.spellbook (pyproject.toml)
|
|
103
|
+
# ipykernel
|
|
104
|
+
# snowflake-connector-python
|
|
105
|
+
pandas==2.2.3
|
|
106
|
+
# via fullscript.spellbook (pyproject.toml)
|
|
107
|
+
parso==0.8.4
|
|
108
|
+
# via
|
|
109
|
+
# fullscript.spellbook (pyproject.toml)
|
|
110
|
+
# jedi
|
|
111
|
+
pexpect==4.9.0
|
|
112
|
+
# via
|
|
113
|
+
# fullscript.spellbook (pyproject.toml)
|
|
114
|
+
# ipython
|
|
115
|
+
platformdirs==4.3.6
|
|
116
|
+
# via
|
|
117
|
+
# fullscript.spellbook (pyproject.toml)
|
|
118
|
+
# jupyter-core
|
|
119
|
+
# snowflake-connector-python
|
|
120
|
+
prompt-toolkit==3.0.48
|
|
121
|
+
# via
|
|
122
|
+
# fullscript.spellbook (pyproject.toml)
|
|
123
|
+
# ipython
|
|
124
|
+
protobuf==5.28.3
|
|
125
|
+
# via
|
|
126
|
+
# fullscript.spellbook (pyproject.toml)
|
|
127
|
+
# snowflake-snowpark-python
|
|
128
|
+
psutil==6.1.0
|
|
129
|
+
# via
|
|
130
|
+
# fullscript.spellbook (pyproject.toml)
|
|
131
|
+
# ipykernel
|
|
132
|
+
ptyprocess==0.7.0
|
|
133
|
+
# via
|
|
134
|
+
# fullscript.spellbook (pyproject.toml)
|
|
135
|
+
# pexpect
|
|
136
|
+
pure-eval==0.2.3
|
|
137
|
+
# via
|
|
138
|
+
# fullscript.spellbook (pyproject.toml)
|
|
139
|
+
# stack-data
|
|
140
|
+
pyarrow==18.0.0
|
|
141
|
+
# via fullscript.spellbook (pyproject.toml)
|
|
142
|
+
pycparser==2.22
|
|
143
|
+
# via
|
|
144
|
+
# cffi
|
|
145
|
+
# fullscript.spellbook (pyproject.toml)
|
|
146
|
+
pygments==2.18.0
|
|
147
|
+
# via
|
|
148
|
+
# fullscript.spellbook (pyproject.toml)
|
|
149
|
+
# ipython
|
|
150
|
+
pyjwt==2.9.0
|
|
151
|
+
# via
|
|
152
|
+
# fullscript.spellbook (pyproject.toml)
|
|
153
|
+
# snowflake-connector-python
|
|
154
|
+
pyopenssl==24.2.1
|
|
155
|
+
# via
|
|
156
|
+
# fullscript.spellbook (pyproject.toml)
|
|
157
|
+
# snowflake-connector-python
|
|
158
|
+
python-dateutil==2.9.0.post0
|
|
159
|
+
# via
|
|
160
|
+
# fullscript.spellbook (pyproject.toml)
|
|
161
|
+
# jupyter-client
|
|
162
|
+
# pandas
|
|
163
|
+
pytz==2024.2
|
|
164
|
+
# via
|
|
165
|
+
# fullscript.spellbook (pyproject.toml)
|
|
166
|
+
# pandas
|
|
167
|
+
# snowflake-connector-python
|
|
168
|
+
pyyaml==6.0.2
|
|
169
|
+
# via
|
|
170
|
+
# fullscript.spellbook (pyproject.toml)
|
|
171
|
+
# snowflake-snowpark-python
|
|
172
|
+
pyzmq==26.2.0
|
|
173
|
+
# via
|
|
174
|
+
# fullscript.spellbook (pyproject.toml)
|
|
175
|
+
# ipykernel
|
|
176
|
+
# jupyter-client
|
|
177
|
+
requests==2.32.3
|
|
178
|
+
# via
|
|
179
|
+
# fullscript.spellbook (pyproject.toml)
|
|
180
|
+
# snowflake-connector-python
|
|
181
|
+
six==1.16.0
|
|
182
|
+
# via
|
|
183
|
+
# asttokens
|
|
184
|
+
# fullscript.spellbook (pyproject.toml)
|
|
185
|
+
# python-dateutil
|
|
186
|
+
snowflake-connector-python==3.12.3
|
|
187
|
+
# via
|
|
188
|
+
# fullscript.spellbook (pyproject.toml)
|
|
189
|
+
# snowflake-snowpark-python
|
|
190
|
+
# snowflake-sqlalchemy
|
|
191
|
+
snowflake-snowpark-python==1.25.0
|
|
192
|
+
# via fullscript.spellbook (pyproject.toml)
|
|
193
|
+
snowflake-sqlalchemy==1.7.0
|
|
194
|
+
# via fullscript.spellbook (pyproject.toml)
|
|
195
|
+
sortedcontainers==2.4.0
|
|
196
|
+
# via
|
|
197
|
+
# fullscript.spellbook (pyproject.toml)
|
|
198
|
+
# snowflake-connector-python
|
|
199
|
+
sqlalchemy==2.0.36
|
|
200
|
+
# via
|
|
201
|
+
# fullscript.spellbook (pyproject.toml)
|
|
202
|
+
# snowflake-sqlalchemy
|
|
203
|
+
stack-data==0.6.3
|
|
204
|
+
# via
|
|
205
|
+
# fullscript.spellbook (pyproject.toml)
|
|
206
|
+
# ipython
|
|
207
|
+
tomlkit==0.13.2
|
|
208
|
+
# via
|
|
209
|
+
# fullscript.spellbook (pyproject.toml)
|
|
210
|
+
# snowflake-connector-python
|
|
211
|
+
tornado==6.4.1
|
|
212
|
+
# via
|
|
213
|
+
# fullscript.spellbook (pyproject.toml)
|
|
214
|
+
# ipykernel
|
|
215
|
+
# jupyter-client
|
|
216
|
+
traitlets==5.14.3
|
|
217
|
+
# via
|
|
218
|
+
# comm
|
|
219
|
+
# fullscript.spellbook (pyproject.toml)
|
|
220
|
+
# ipykernel
|
|
221
|
+
# ipython
|
|
222
|
+
# jupyter-client
|
|
223
|
+
# jupyter-core
|
|
224
|
+
# matplotlib-inline
|
|
225
|
+
typing-extensions==4.12.2
|
|
226
|
+
# via
|
|
227
|
+
# fullscript.spellbook (pyproject.toml)
|
|
228
|
+
# ipython
|
|
229
|
+
# snowflake-connector-python
|
|
230
|
+
# snowflake-snowpark-python
|
|
231
|
+
# sqlalchemy
|
|
232
|
+
tzdata==2024.2
|
|
233
|
+
# via
|
|
234
|
+
# fullscript.spellbook (pyproject.toml)
|
|
235
|
+
# pandas
|
|
236
|
+
tzlocal==5.2
|
|
237
|
+
# via
|
|
238
|
+
# fullscript.spellbook (pyproject.toml)
|
|
239
|
+
# snowflake-snowpark-python
|
|
240
|
+
urllib3==2.2.3
|
|
241
|
+
# via
|
|
242
|
+
# fullscript.spellbook (pyproject.toml)
|
|
243
|
+
# requests
|
|
244
|
+
wcwidth==0.2.13
|
|
245
|
+
# via
|
|
246
|
+
# fullscript.spellbook (pyproject.toml)
|
|
247
|
+
# prompt-toolkit
|
|
248
|
+
wheel==0.45.1
|
|
249
|
+
# via snowflake-snowpark-python
|
|
250
|
+
|
|
251
|
+
# The following packages are considered to be unsafe in a requirements file:
|
|
252
|
+
# setuptools
|
|
@@ -5,7 +5,7 @@ import pandas as pd
|
|
|
5
5
|
from cryptography.hazmat.backends import default_backend
|
|
6
6
|
from cryptography.hazmat.primitives import serialization
|
|
7
7
|
import base64
|
|
8
|
-
from spellbook.utils import load_and_parse_config, get_wizard
|
|
8
|
+
from spellbook.utils import load_and_parse_config, get_wizard, load_sql_file
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
# Needs a very specific pip install
|
|
@@ -108,7 +108,9 @@ def read_mysql(db_name, query):
|
|
|
108
108
|
if con is None:
|
|
109
109
|
return pd.DataFrame()
|
|
110
110
|
try:
|
|
111
|
-
df = pd.read_sql(
|
|
111
|
+
df = pd.read_sql(
|
|
112
|
+
load_sql_file(query),
|
|
113
|
+
con)
|
|
112
114
|
df.columns = df.columns.str.lower()
|
|
113
115
|
return df
|
|
114
116
|
except Exception as e:
|
|
@@ -129,7 +131,9 @@ def execute_mysql(query, dbname):
|
|
|
129
131
|
# Establish a connection and run the query
|
|
130
132
|
con = mysql_connect(dbname)
|
|
131
133
|
mycursor = con.connection.cursor()
|
|
132
|
-
mycursor.execute(
|
|
134
|
+
mycursor.execute(
|
|
135
|
+
load_sql_file(query)
|
|
136
|
+
)
|
|
133
137
|
except Exception as e:
|
|
134
138
|
# Handle errors
|
|
135
139
|
print('An error was encountered executing mysql, ', e)
|
|
@@ -151,7 +155,9 @@ def execute_snowflake(db_name, query):
|
|
|
151
155
|
return
|
|
152
156
|
|
|
153
157
|
# Execute query
|
|
154
|
-
session.sql(
|
|
158
|
+
session.sql(
|
|
159
|
+
load_sql_file(query)
|
|
160
|
+
).collect()
|
|
155
161
|
print("Query executed successfully.")
|
|
156
162
|
|
|
157
163
|
except Exception as e:
|
|
@@ -177,7 +183,9 @@ def read_snowflake(db_name, query):
|
|
|
177
183
|
return pd.DataFrame()
|
|
178
184
|
|
|
179
185
|
# Execute query and fetch data
|
|
180
|
-
df = session.sql(
|
|
186
|
+
df = (session.sql(
|
|
187
|
+
load_sql_file(query)
|
|
188
|
+
).to_pandas())
|
|
181
189
|
df.columns = df.columns.str.lower() # Normalize column names
|
|
182
190
|
return df
|
|
183
191
|
|
|
@@ -238,10 +246,16 @@ def get_data(db_name, query, **kwargs):
|
|
|
238
246
|
# Call the correct database read function
|
|
239
247
|
if db_config['type'] == 'snowflake':
|
|
240
248
|
print(get_wizard())
|
|
241
|
-
df = read_snowflake(
|
|
249
|
+
df = read_snowflake(
|
|
250
|
+
db_name,
|
|
251
|
+
load_sql_file(query)
|
|
252
|
+
)
|
|
242
253
|
elif db_config['type'] == 'mysql':
|
|
243
254
|
print(get_wizard())
|
|
244
|
-
df = read_mysql(
|
|
255
|
+
df = read_mysql(
|
|
256
|
+
db_name,
|
|
257
|
+
load_sql_file(query)
|
|
258
|
+
)
|
|
245
259
|
else:
|
|
246
260
|
print('Valid database types are, snowflake and mysql')
|
|
247
261
|
return df
|
|
@@ -258,9 +272,15 @@ def run_sql(db_name, query, **kwargs):
|
|
|
258
272
|
# Call the correct database run function
|
|
259
273
|
if db_config['type'] == 'snowflake':
|
|
260
274
|
print(get_wizard())
|
|
261
|
-
execute_snowflake(
|
|
275
|
+
execute_snowflake(
|
|
276
|
+
db_name,
|
|
277
|
+
load_sql_file(query)
|
|
278
|
+
)
|
|
262
279
|
elif db_config['type'] == 'mysql':
|
|
263
280
|
print(get_wizard())
|
|
264
|
-
execute_mysql(
|
|
281
|
+
execute_mysql(
|
|
282
|
+
db_name,
|
|
283
|
+
load_sql_file(query)
|
|
284
|
+
)
|
|
265
285
|
else:
|
|
266
286
|
print('Valid database types are, snowflake and mysql')
|
|
@@ -90,4 +90,34 @@ def get_wizard():
|
|
|
90
90
|
print('An error was encountered loading the wizard:', e)
|
|
91
91
|
wizard = None
|
|
92
92
|
|
|
93
|
-
return wizard
|
|
93
|
+
return wizard
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def load_sql_file(query_file):
|
|
97
|
+
"""
|
|
98
|
+
Load the contents of a SQL file or return the SQL string directly.
|
|
99
|
+
|
|
100
|
+
:param query_file: str, path to the SQL file or raw SQL query string
|
|
101
|
+
:return: str, SQL query
|
|
102
|
+
:raises ValueError: if the file path is invalid or not a .sql file
|
|
103
|
+
"""
|
|
104
|
+
if isinstance(query_file, str) and os.path.exists(query_file):
|
|
105
|
+
# Ensure it's a .sql file
|
|
106
|
+
if not query_file.lower().endswith('.sql'):
|
|
107
|
+
raise ValueError(f"The file {query_file} is not a valid SQL file.")
|
|
108
|
+
|
|
109
|
+
# Use a context manager to read the file safely
|
|
110
|
+
try:
|
|
111
|
+
with open(query_file, 'r', encoding='utf-8') as file:
|
|
112
|
+
query_str = file.read()
|
|
113
|
+
except Exception as e:
|
|
114
|
+
raise ValueError(f"Error reading the file {query_file}: {e}")
|
|
115
|
+
else:
|
|
116
|
+
# Assume it's a raw SQL query string
|
|
117
|
+
query_str = query_file
|
|
118
|
+
|
|
119
|
+
# Check for empty SQL content
|
|
120
|
+
if not query_str.strip():
|
|
121
|
+
raise ValueError("The SQL query is empty. Please provide valid SQL content.")
|
|
122
|
+
|
|
123
|
+
return query_str
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fullscript_spellbook-2.1.2 → fullscript_spellbook-2.1.4}/fullscript.spellbook.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|