fullscript.spellbook 2.1__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Fullscript
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.2
2
+ Name: fullscript.spellbook
3
+ Version: 2.1
4
+ Summary: A simple package to make your life easier.
5
+ Author: Gui Chagas, David King, Meinhard Mare, Karsten Melchers
6
+ Author-email: Thomas Edwards <thomas.edwards@fullscript.com>
7
+ License: MIT
8
+ Project-URL: homepage, https://git.fullscript.io/data/spellbook
9
+ Requires-Python: <3.12,>=3.10
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: appnope==0.1.4
13
+ Requires-Dist: asn1crypto==1.5.1
14
+ Requires-Dist: asttokens==2.4.1
15
+ Requires-Dist: snowflake-sqlalchemy==1.7.0
16
+ Requires-Dist: certifi==2024.8.30
17
+ Requires-Dist: cffi==1.17.1
18
+ Requires-Dist: charset-normalizer==3.4.0
19
+ Requires-Dist: cloudpickle==2.2.1
20
+ Requires-Dist: comm==0.2.2
21
+ Requires-Dist: cryptography==43.0.3
22
+ Requires-Dist: debugpy==1.8.8
23
+ Requires-Dist: decorator==5.1.1
24
+ Requires-Dist: executing==2.1.0
25
+ Requires-Dist: filelock==3.16.1
26
+ Requires-Dist: idna==3.10
27
+ Requires-Dist: ipykernel==6.29.5
28
+ Requires-Dist: ipython==8.29.0
29
+ Requires-Dist: jedi==0.19.2
30
+ Requires-Dist: jupyter_client==8.6.3
31
+ Requires-Dist: jupyter_core==5.7.2
32
+ Requires-Dist: matplotlib-inline==0.1.7
33
+ Requires-Dist: nest-asyncio==1.6.0
34
+ Requires-Dist: numpy==2.1.3
35
+ Requires-Dist: packaging==24.2
36
+ Requires-Dist: pandas==2.2.3
37
+ Requires-Dist: parso==0.8.4
38
+ Requires-Dist: pexpect==4.9.0
39
+ Requires-Dist: platformdirs==4.3.6
40
+ Requires-Dist: prompt_toolkit==3.0.48
41
+ Requires-Dist: protobuf==5.28.3
42
+ Requires-Dist: psutil==6.1.0
43
+ Requires-Dist: ptyprocess==0.7.0
44
+ Requires-Dist: pure_eval==0.2.3
45
+ Requires-Dist: pyarrow==18.0.0
46
+ Requires-Dist: pycparser==2.22
47
+ Requires-Dist: Pygments==2.18.0
48
+ Requires-Dist: PyJWT==2.9.0
49
+ Requires-Dist: pyOpenSSL==24.2.1
50
+ Requires-Dist: python-dateutil==2.9.0.post0
51
+ Requires-Dist: pytz==2024.2
52
+ Requires-Dist: PyYAML==6.0.2
53
+ Requires-Dist: pyzmq==26.2.0
54
+ Requires-Dist: requests==2.32.3
55
+ Requires-Dist: six==1.16.0
56
+ Requires-Dist: snowflake-connector-python==3.12.3
57
+ Requires-Dist: snowflake-snowpark-python==1.25.0
58
+ Requires-Dist: sortedcontainers==2.4.0
59
+ Requires-Dist: SQLAlchemy==2.0.36
60
+ Requires-Dist: stack-data==0.6.3
61
+ Requires-Dist: tomlkit==0.13.2
62
+ Requires-Dist: tornado==6.4.1
63
+ Requires-Dist: traitlets==5.14.3
64
+ Requires-Dist: typing_extensions==4.12.2
65
+ Requires-Dist: tzdata==2024.2
66
+ Requires-Dist: tzlocal==5.2
67
+ Requires-Dist: urllib3==2.2.3
68
+ Requires-Dist: wcwidth==0.2.13
69
+ Provides-Extra: drivemagic
70
+ Requires-Dist: cachetools==5.5.0; extra == "drivemagic"
71
+ Requires-Dist: google-api-core==2.23.0; extra == "drivemagic"
72
+ Requires-Dist: google-api-python-client==2.153.0; extra == "drivemagic"
73
+ Requires-Dist: google-auth==2.36.0; extra == "drivemagic"
74
+ Requires-Dist: google-auth-httplib2==0.2.0; extra == "drivemagic"
75
+ Requires-Dist: google-auth-oauthlib==1.2.1; extra == "drivemagic"
76
+ Requires-Dist: googleapis-common-protos==1.66.0; extra == "drivemagic"
77
+ Requires-Dist: httplib2==0.22.0; extra == "drivemagic"
78
+ Requires-Dist: oauthlib==3.2.2; extra == "drivemagic"
79
+ Requires-Dist: proto-plus==1.25.0; extra == "drivemagic"
80
+ Requires-Dist: pyasn1==0.6.1; extra == "drivemagic"
81
+ Requires-Dist: pyasn1_modules==0.4.1; extra == "drivemagic"
82
+ Requires-Dist: pyparsing==3.2.0; extra == "drivemagic"
83
+ Requires-Dist: requests-oauthlib==2.0.0; extra == "drivemagic"
84
+ Requires-Dist: rsa==4.9; extra == "drivemagic"
85
+ Requires-Dist: uritemplate==4.1.1; extra == "drivemagic"
86
+ Provides-Extra: sheetmagic
87
+ Requires-Dist: cachetools==5.5.0; extra == "sheetmagic"
88
+ Requires-Dist: google-api-core==2.23.0; extra == "sheetmagic"
89
+ Requires-Dist: google-api-python-client==2.153.0; extra == "sheetmagic"
90
+ Requires-Dist: google-auth==2.36.0; extra == "sheetmagic"
91
+ Requires-Dist: google-auth-httplib2==0.2.0; extra == "sheetmagic"
92
+ Requires-Dist: google-auth-oauthlib==1.2.1; extra == "sheetmagic"
93
+ Requires-Dist: googleapis-common-protos==1.66.0; extra == "sheetmagic"
94
+ Requires-Dist: httplib2==0.22.0; extra == "sheetmagic"
95
+ Requires-Dist: oauthlib==3.2.2; extra == "sheetmagic"
96
+ Requires-Dist: pyasn1==0.6.1; extra == "sheetmagic"
97
+ Requires-Dist: pyasn1_modules==0.4.1; extra == "sheetmagic"
98
+ Requires-Dist: Pygments==2.18.0; extra == "sheetmagic"
99
+ Requires-Dist: pygsheets==2.0.6; extra == "sheetmagic"
100
+ Requires-Dist: pyparsing==3.2.0; extra == "sheetmagic"
101
+ Requires-Dist: requests-oauthlib==2.0.0; extra == "sheetmagic"
102
+ Requires-Dist: rsa==4.9; extra == "sheetmagic"
103
+ Requires-Dist: uritemplate==4.1.1; extra == "sheetmagic"
104
+ Provides-Extra: statsmagic
105
+ Requires-Dist: contourpy==1.3.1; extra == "statsmagic"
106
+ Requires-Dist: cycler==0.12.1; extra == "statsmagic"
107
+ Requires-Dist: fonttools==4.55.0; extra == "statsmagic"
108
+ Requires-Dist: kiwisolver==1.4.7; extra == "statsmagic"
109
+ Requires-Dist: matplotlib==3.9.2; extra == "statsmagic"
110
+ Requires-Dist: patsy==1.0.1; extra == "statsmagic"
111
+ Requires-Dist: pillow==11.0.0; extra == "statsmagic"
112
+ Requires-Dist: pyparsing==3.2.0; extra == "statsmagic"
113
+ Requires-Dist: python-dateutil==2.9.0.post0; extra == "statsmagic"
114
+ Requires-Dist: pytz==2024.2; extra == "statsmagic"
115
+ Requires-Dist: scikit-posthocs==0.10.0; extra == "statsmagic"
116
+ Requires-Dist: scipy==1.14.1; extra == "statsmagic"
117
+ Requires-Dist: seaborn==0.13.2; extra == "statsmagic"
118
+ Requires-Dist: six==1.16.0; extra == "statsmagic"
119
+ Requires-Dist: statsmodels==0.14.4; extra == "statsmagic"
120
+
121
+ # Spellbook
122
+
123
+ Helping data scientists and engineers save time by making it simple to connect to databases, work with spreadsheets,
124
+ manage files, and run analyses. With Spellbook, they can focus on finding insights and solving problems instead of
125
+ dealing with complicated tools.
126
+
127
+ With Spellbook, you can:
128
+ * Seamlessly connect to Snowflake and MySQL databases, for secure querying and effortless data retrieval.
129
+ * Work with Google Sheets, making it easy to read, write, and update spreadsheets.
130
+ * Manage Google Drive, creating folders and saving files with ease.
131
+ * Perform statistical analyses, helping you run A/B tests and extract actionable insights.
132
+
133
+ Spellbook is built to simplify your workflows and supercharge your data exploration, so you can focus on turning insights into action!
134
+
135
+ ## Table of Contents
136
+
137
+ - [Features](#features)
138
+ - [Installation](#installation)
139
+ - [Configuration](#configuration)
140
+ - [Contributing](#contributing)
141
+ - [License](#license)
142
+
143
+ ## Features
144
+
145
+ - Effortless Database Connections and query execution
146
+ - Read/ Write to Google worksheets
147
+ - Manage Google Drive
148
+ - Perform statistical analyses
149
+
150
+ For feature methods and examples, please refer to the [Wiki Page](https://git.fullscript.io/data/spellbook/-/wikis/home).
151
+
152
+
153
+ ## Installation
154
+
155
+ Spellbook requires Python 3.11 or higher. Use the following steps to install:
156
+ > Note: At the time relase, Snowpark does not support versions of Python higher than 3.11
157
+
158
+ 1. Pip install:
159
+
160
+ ```bash
161
+ pip install git+https://git.fullscript.io/data/spellbook.git
162
+ ```
163
+
164
+ ## Configuration
165
+ Effortlessly and securely manage your connections and configurations! Simply add database types and connection
166
+ credentials to your [spellbook_config.yaml](spellbook_config.yaml) file, or include your Google service account details for seamless access to
167
+ Google services. For added security, Spellbook supports storing credentials in environment variables
168
+ or in a configuration file that references those variables, keeping your sensitive information safe and sound.
169
+
170
+ You must have a `spellbook_config.yaml` file in your root directory or in your project directory.
171
+ An example of the `spellbook_config.yaml` file is shown below:
172
+
173
+ ```yaml
174
+ databases:
175
+ # Snowflake Database Connection
176
+ - name: alias_of_your_connection
177
+ type: snowflake
178
+ account: your_account
179
+ user: snowflake_user_name # Optional for private key auth
180
+ password: snowflake_password # Optional, used if private key is not present
181
+ private_key: snowflake_pk # Base64-encoded private key
182
+ private_key_passphrase: snowflake_pk_phrase # Optional
183
+ role: snowflake_role
184
+ warehouse: snowflake_warehouse
185
+ database: snowflake_database
186
+ schema: snowflake_schema
187
+
188
+ google_accounts:
189
+ # Google Sheets Service Account 1
190
+ - name: google_sheets_service_account_1
191
+ service_account: "your_base64_encoded_service_account_credentials_here" # Add your Base64-encoded service account JSON here
192
+ ```
193
+
194
+ ## Contributing
195
+
196
+ We welcome contributions! Please follow these steps:
197
+
198
+ 1. Fork this repository.
199
+ 2. Create a new branch: `git checkout -b feature-name`.
200
+ 3. Commit your changes: `git commit -m 'Add some feature'`.
201
+ 4. Push to the branch: `git push origin feature-name`.
202
+ 5. Open a pull request.
203
+
204
+ ## License
205
+
206
+ Spellbook is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
207
+
208
+ ---
@@ -0,0 +1,23 @@
1
+ spellbook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ spellbook/db_magic.py,sha256=rRQm6EL7vRvO7rR9snF0_RlJTRfmFq9gvWvh7L9BYbM,8579
3
+ spellbook/drive_magic.py,sha256=uZH-nAOgBXO_NHm4OJ3xX3jPAS11jTj0bkfNd8pBLis,9594
4
+ spellbook/sheet_magic.py,sha256=a8ZQE3ifFJpsptfHyj4ku-hrbeBM8qL3zW5Sy-HjL_c,8186
5
+ spellbook/stats_magic.py,sha256=8uwq-n4NWDYzUUFZAX17Ls1jWcFj17l-BFqeF8VrTPQ,7655
6
+ spellbook/utils.py,sha256=DQ1R3dZxhnEvUMixvy28oyCuJw63MudwJLnCs_yIyQ8,3306
7
+ spellbook/wizards/wizard1.txt,sha256=6F-jH4EJ5birPbFrD4HhxIUBLtP2wTlUZcJjNV5upAg,285
8
+ spellbook/wizards/wizard10.txt,sha256=NjT8pIZs60nahK-7Z6mkIdUgoUNeaBj0qU4NdWrM7aM,798
9
+ spellbook/wizards/wizard11.txt,sha256=ioKNImgjRTQNQdmeSagmeMAnDNhldCbcLHHy9EuPG0Y,565
10
+ spellbook/wizards/wizard12.txt,sha256=78fVVYHbSqf5AqI7xgSZNvznpdKtKXOhzvPBaJO5Dic,462
11
+ spellbook/wizards/wizard2.txt,sha256=8zgsC2-msh4QGez3Ivv1VuurQBGyeFiyuVNs9VfWkA8,57
12
+ spellbook/wizards/wizard3.txt,sha256=QO8cQa9HsqtTaUMNDqvic8ySRBx6O1QYst2plGaqjFE,61
13
+ spellbook/wizards/wizard4.txt,sha256=eLBEHHiX2aCADRmlXUg5PiovZKHnbF4Uz9uM5PsasKo,146
14
+ spellbook/wizards/wizard5.txt,sha256=3Vm-KdTUnq34IGxd_kMeWY5j_LHlzYPvAkRtkqq1i3w,129
15
+ spellbook/wizards/wizard6.txt,sha256=mQ0FNaRrh-q5B6MiJZ1MO4XCdqsPvj_tGOhIZJDfHis,115
16
+ spellbook/wizards/wizard7.txt,sha256=ssaQtCSfUaLOgq7-gu0Ao74GFa7FkN8lCjOMIiGL4Ak,86
17
+ spellbook/wizards/wizard8.txt,sha256=ZVgn0KzC0g71_lnzvYf8XbSbrGEqFHS_n3JjRFEvrOg,684
18
+ spellbook/wizards/wizard9.txt,sha256=ROHeUtq9k66goCVsLctpPgx3U_UxAJzBtSVyWhFfho0,1435
19
+ fullscript.spellbook-2.1.dist-info/LICENSE,sha256=RG9zQfX4eYYNV_n6_zvsKucXCgPqSAXBUQkkPEJJUQg,1066
20
+ fullscript.spellbook-2.1.dist-info/METADATA,sha256=QOFJ_R6PcEPoqjJCptiK5scoqzOLl__Y3TDnjF7L2_Y,8465
21
+ fullscript.spellbook-2.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
22
+ fullscript.spellbook-2.1.dist-info/top_level.txt,sha256=mL7M9kCzo_sE_bt4FPXIdHtCV8YiDCAH8kkdOSI3yqw,10
23
+ fullscript.spellbook-2.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.8.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ spellbook
spellbook/__init__.py ADDED
File without changes
spellbook/db_magic.py ADDED
@@ -0,0 +1,266 @@
1
+ import os
2
+ from snowflake.snowpark import Session
3
+ from sqlalchemy import create_engine
4
+ import pandas as pd
5
+ from cryptography.hazmat.backends import default_backend
6
+ from cryptography.hazmat.primitives import serialization
7
+ import base64
8
+ from spellbook.utils import load_and_parse_config, get_wizard
9
+
10
+
11
+ # Needs a very specific pip install
12
+ # pip install "snowflake-connector-python[pandas]"
13
+
14
+
15
+ def get_db_config(db_name):
16
+ # load the configuration
17
+ try:
18
+ config = load_and_parse_config(configurations='databases')
19
+ except FileNotFoundError:
20
+ print("Config file not found. Please ensure 'spellbook_config.yaml' exists.")
21
+ config = None
22
+
23
+ for db in config['databases']:
24
+ if db['name'] == db_name:
25
+ return db
26
+ raise ValueError(f"Database configuration for '{db_name}' not found.")
27
+
28
+
29
+ def snowflake_connect(db_name, **kwargs):
30
+ """
31
+ Create a Snowflake connection using credentials from the config file or environment variables.
32
+ :param db_name: The name of the database as defined in the config file.
33
+ :return: Snowpark session object.
34
+ """
35
+ db_config = get_db_config(db_name, **kwargs) # Fetch database config from the config file
36
+
37
+ # Determine authentication method
38
+ use_private_key = db_config.get('private_key') or os.getenv('SNOW_PK')
39
+
40
+ try:
41
+ if use_private_key:
42
+ # Private key authentication
43
+ private_key = db_config.get('private_key')
44
+ passphrase = db_config.get('private_key_passphrase')
45
+
46
+ # Decode and load the private key
47
+ p_key = serialization.load_pem_private_key(
48
+ base64.b64decode(private_key),
49
+ password=passphrase.encode('ascii') if passphrase else None,
50
+ backend=default_backend()
51
+ )
52
+ pkb = p_key.private_bytes(
53
+ encoding=serialization.Encoding.DER,
54
+ format=serialization.PrivateFormat.PKCS8,
55
+ encryption_algorithm=serialization.NoEncryption()
56
+ )
57
+
58
+ session = Session.builder.configs({
59
+ 'account': db_config['account'],
60
+ 'user': db_config['user'],
61
+ 'private_key': pkb,
62
+ 'role': db_config['role'],
63
+ 'warehouse': db_config['warehouse'],
64
+ 'database': db_config['database'],
65
+ 'schema': db_config.get('schema', 'public')
66
+ }).create()
67
+ else:
68
+ # Username/password authentication
69
+ session = Session.builder.configs({
70
+ 'account': db_config['account'],
71
+ 'user': db_config['user'],
72
+ 'password': db_config.get('password'),
73
+ 'role': db_config['role'],
74
+ 'warehouse': db_config['warehouse'],
75
+ 'database': db_config['database'],
76
+ 'schema': db_config.get('schema', 'public')
77
+ }).create()
78
+
79
+ return session
80
+ except Exception as e:
81
+ print(f"An error occurred creating the Snowflake session: {e}")
82
+ return None
83
+
84
+
85
+ def mysql_connect(db_name, **kwargs):
86
+ db_config = get_db_config(db_name, **kwargs)
87
+ try:
88
+ connection_string = (
89
+ f"mysql+mysqlconnector://{db_config['user']}:{db_config['password']}"
90
+ f"@{db_config['host']}:{db_config.get('port', 3306)}/{db_config['database']}"
91
+ )
92
+ engine = create_engine(connection_string)
93
+ con = engine.connect()
94
+ return con
95
+ except Exception as e:
96
+ print(f"An error occurred creating the MySQL connection: {e}")
97
+ return None
98
+
99
+
100
+ def read_mysql(db_name, query):
101
+ """
102
+ Read data from a MySQL database into a Pandas DataFrame.
103
+ :param db_name: Name of the database as defined in the config file.
104
+ :param query: SQL query to execute.
105
+ :return:
106
+ """
107
+ con = mysql_connect(db_name)
108
+ if con is None:
109
+ return pd.DataFrame()
110
+ try:
111
+ df = pd.read_sql(query, con)
112
+ df.columns = df.columns.str.lower()
113
+ return df
114
+ except Exception as e:
115
+ print(f"An error occurred reading from MySQL: {e}")
116
+ return pd.DataFrame()
117
+ finally:
118
+ con.close()
119
+
120
+
121
+ def execute_mysql(query, dbname):
122
+ """
123
+ Execute a query on a MySQL database.
124
+ :param query: SQL query to execute.
125
+ :param dbname: Database name as defined in the config file.
126
+ :return:
127
+ """
128
+ try:
129
+ # Establish a connection and run the query
130
+ con = mysql_connect(dbname)
131
+ mycursor = con.connection.cursor()
132
+ mycursor.execute(query)
133
+ except Exception as e:
134
+ # Handle errors
135
+ print('An error was encountered executing mysql, ', e)
136
+ finally:
137
+ con.close()
138
+
139
+
140
+ def execute_snowflake(db_name, query):
141
+ """
142
+ Execute a query on Snowflake using Snowpark.
143
+ :param query: SQL query to execute.
144
+ :param db_name: Database name as defined in the config file.
145
+ """
146
+ try:
147
+ # Establish session
148
+ session = snowflake_connect(db_name)
149
+ if not session:
150
+ print("Failed to connect to Snowflake.")
151
+ return
152
+
153
+ # Execute query
154
+ session.sql(query).collect()
155
+ print("Query executed successfully.")
156
+
157
+ except Exception as e:
158
+ print(f"An error occurred executing in Snowflake: {e}")
159
+
160
+ finally:
161
+ if session:
162
+ session.close()
163
+
164
+
165
+ def read_snowflake(db_name, query):
166
+ """
167
+ Fetch data from Snowflake into a Pandas DataFrame using Snowpark.
168
+ :param db_name: Database name as defined in the config file.
169
+ :param query: SQL query to fetch data.
170
+ :return: Pandas DataFrame.
171
+ """
172
+ try:
173
+ # Establish session
174
+ session = snowflake_connect(db_name)
175
+ if not session:
176
+ print("Failed to connect to Snowflake.")
177
+ return pd.DataFrame()
178
+
179
+ # Execute query and fetch data
180
+ df = session.sql(query).to_pandas()
181
+ df.columns = df.columns.str.lower() # Normalize column names
182
+ return df
183
+
184
+ except Exception as e:
185
+ print(f"An error occurred reading from Snowflake: {e}")
186
+ return pd.DataFrame()
187
+
188
+ finally:
189
+ if session:
190
+ session.close()
191
+
192
+
193
+ def write_data(db_name, schema, df, table_name, overwrite=True, chunk_size=1000, **kwargs):
194
+ """
195
+ Write a Pandas DataFrame to a Snowflake table using Snowpark.
196
+ :param db_name: Database name as defined in the config file.
197
+ :param schema: Schema where the table exists.
198
+ :param df: Pandas DataFrame to write.
199
+ :param table_name: Table name to write to.
200
+ :param overwrite: Whether to overwrite the table if it exists.
201
+ """
202
+ try:
203
+ # Establish session
204
+ session = snowflake_connect(db_name)
205
+ if not session:
206
+ print("Failed to connect to Snowflake.")
207
+ return
208
+
209
+ # Write DataFrame to Snowflake
210
+ session.write_pandas(
211
+ df=df,
212
+ schema=schema,
213
+ table_name=table_name,
214
+ auto_create_table=True,
215
+ overwrite=overwrite,
216
+ quote_identifiers=False,
217
+ chunk_size=chunk_size,
218
+ **kwargs
219
+ )
220
+ print(f"Data written successfully to {schema}.{table_name}.")
221
+
222
+ except Exception as e:
223
+ print(f"An error occurred writing to Snowflake: {e}")
224
+
225
+ finally:
226
+ if session:
227
+ session.close()
228
+
229
+
230
+ def get_data(db_name, query, **kwargs):
231
+ """
232
+ Get data from a database
233
+ :param db_name: The name of the database as defined in the config file.
234
+ :param query: SQL query to execute.
235
+ :return: Returns a pandas dataframe
236
+ """
237
+ db_config = get_db_config(db_name, **kwargs)
238
+ # Call the correct database read function
239
+ if db_config['type'] == 'snowflake':
240
+ print(get_wizard())
241
+ df = read_snowflake(db_name, query)
242
+ elif db_config['type'] == 'mysql':
243
+ print(get_wizard())
244
+ df = read_mysql(db_name, query)
245
+ else:
246
+ print('Valid database types are, snowflake and mysql')
247
+ return df
248
+
249
+
250
+ def run_sql(db_name, query, **kwargs):
251
+ """
252
+ Run a SQL query on a database
253
+ :param db_name: The name of the database as defined in the config file.
254
+ :param query: SQL query to execute.
255
+ :return: None
256
+ """
257
+ db_config = get_db_config(db_name, **kwargs)
258
+ # Call the correct database run function
259
+ if db_config['type'] == 'snowflake':
260
+ print(get_wizard())
261
+ execute_snowflake(db_name, query)
262
+ elif db_config['type'] == 'mysql':
263
+ print(get_wizard())
264
+ execute_mysql(db_name, query)
265
+ else:
266
+ print('Valid database types are, snowflake and mysql')