snowflake-sqlalchemy 1.5.3__tar.gz → 1.7.0__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.
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/.pre-commit-config.yaml +8 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/DESCRIPTION.md +26 -2
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/PKG-INFO +26 -15
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/README.md +22 -11
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/ci/build.sh +7 -5
- snowflake_sqlalchemy-1.7.0/ci/test_linux.sh +25 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/pyproject.toml +23 -3
- snowflake_sqlalchemy-1.7.0/snyk/requirements.txt +2 -0
- snowflake_sqlalchemy-1.7.0/snyk/requiremtnts.txt +2 -0
- snowflake_sqlalchemy-1.7.0/snyk/update_requirements.py +17 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/src/snowflake/sqlalchemy/__init__.py +52 -6
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/src/snowflake/sqlalchemy/_constants.py +2 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/src/snowflake/sqlalchemy/base.py +82 -30
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/compat.py +36 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/src/snowflake/sqlalchemy/custom_commands.py +2 -1
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/src/snowflake/sqlalchemy/custom_types.py +20 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/exc.py +82 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/functions.py +16 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/parser/custom_type_parser.py +190 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/src/snowflake/sqlalchemy/requirements.py +16 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/src/snowflake/sqlalchemy/snowdialect.py +249 -172
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/__init__.py +9 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/clustered_table.py +37 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/custom_table_base.py +127 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/custom_table_prefix.py +13 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/dynamic_table.py +117 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/hybrid_table.py +62 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/iceberg_table.py +102 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/options/__init__.py +33 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/options/as_query_option.py +63 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/options/cluster_by_option.py +58 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/options/identifier_option.py +63 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/options/invalid_table_option.py +25 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/options/keyword_option.py +65 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/options/keywords.py +14 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/options/literal_option.py +67 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/options/table_option.py +84 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/options/target_lag_option.py +94 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/snowflake_table.py +70 -0
- snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql/custom_schema/table_from_query.py +54 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/src/snowflake/sqlalchemy/util.py +10 -2
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/src/snowflake/sqlalchemy/version.py +1 -1
- snowflake_sqlalchemy-1.7.0/tests/__snapshots__/test_compile_dynamic_table.ambr +13 -0
- snowflake_sqlalchemy-1.7.0/tests/__snapshots__/test_core.ambr +4 -0
- snowflake_sqlalchemy-1.7.0/tests/__snapshots__/test_orm.ambr +4 -0
- snowflake_sqlalchemy-1.7.0/tests/__snapshots__/test_reflect_dynamic_table.ambr +4 -0
- snowflake_sqlalchemy-1.7.0/tests/__snapshots__/test_structured_datatypes.ambr +90 -0
- snowflake_sqlalchemy-1.7.0/tests/__snapshots__/test_unit_structured_types.ambr +4 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/conftest.py +39 -23
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/__init__.py +2 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/__snapshots__/test_compile_dynamic_table.ambr +40 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/__snapshots__/test_compile_hybrid_table.ambr +7 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/__snapshots__/test_compile_iceberg_table.ambr +19 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/__snapshots__/test_compile_snowflake_table.ambr +35 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/__snapshots__/test_create_dynamic_table.ambr +7 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/__snapshots__/test_create_hybrid_table.ambr +7 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/__snapshots__/test_create_iceberg_table.ambr +14 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/__snapshots__/test_create_snowflake_table.ambr +4 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/__snapshots__/test_generic_options.ambr +13 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/__snapshots__/test_reflect_hybrid_table.ambr +4 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/__snapshots__/test_reflect_snowflake_table.ambr +29 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/test_compile_dynamic_table.py +271 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/test_compile_hybrid_table.py +52 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/test_compile_iceberg_table.py +116 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/test_compile_snowflake_table.py +180 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/test_create_dynamic_table.py +124 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/test_create_hybrid_table.py +95 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/test_create_iceberg_table.py +43 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/test_create_snowflake_table.py +66 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/test_generic_options.py +83 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/test_reflect_dynamic_table.py +88 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/test_reflect_hybrid_table.py +65 -0
- snowflake_sqlalchemy-1.7.0/tests/custom_tables/test_reflect_snowflake_table.py +92 -0
- snowflake_sqlalchemy-1.7.0/tests/sqlalchemy_test_suite/__init__.py +3 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/sqlalchemy_test_suite/conftest.py +7 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/sqlalchemy_test_suite/test_suite.py +4 -0
- snowflake_sqlalchemy-1.7.0/tests/sqlalchemy_test_suite/test_suite_20.py +205 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_compiler.py +1 -1
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_core.py +114 -135
- snowflake_sqlalchemy-1.7.0/tests/test_custom_functions.py +25 -0
- snowflake_sqlalchemy-1.7.0/tests/test_custom_types.py +67 -0
- snowflake_sqlalchemy-1.7.0/tests/test_index_reflection.py +34 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_orm.py +199 -28
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_pandas.py +7 -6
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_qmark.py +2 -2
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_sequence.py +26 -0
- snowflake_sqlalchemy-1.7.0/tests/test_structured_datatypes.py +271 -0
- snowflake_sqlalchemy-1.7.0/tests/test_unit_structured_types.py +73 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/util.py +2 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tox.ini +4 -8
- snowflake_sqlalchemy-1.5.3/ci/test_linux.sh +0 -25
- snowflake_sqlalchemy-1.5.3/tests/test_custom_types.py +0 -36
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/.gitignore +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/.gitmodules +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/LICENSE.txt +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/MANIFEST.in +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/ci/build_docker.sh +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/ci/docker/sqlalchemy_build/Dockerfile +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/ci/docker/sqlalchemy_build/scripts/entrypoint.sh +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/ci/set_base_image.sh +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/ci/test.sh +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/ci/test_docker.sh +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/license_header.txt +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/setup.cfg +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/src/snowflake/sqlalchemy/provision.py +0 -0
- {snowflake_sqlalchemy-1.5.3/tests → snowflake_sqlalchemy-1.7.0/src/snowflake/sqlalchemy/sql}/__init__.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tested_requirements/requirements_310.reqs +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tested_requirements/requirements_37.reqs +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tested_requirements/requirements_38.reqs +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tested_requirements/requirements_39.reqs +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/README.rst +0 -0
- {snowflake_sqlalchemy-1.5.3/tests/sqlalchemy_test_suite → snowflake_sqlalchemy-1.7.0/tests}/__init__.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/data/users.txt +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/sqlalchemy_test_suite/README.md +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_copy.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_create.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_geography.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_geometry.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_multivalues_insert.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_quote.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_semi_structured_datatypes.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_timestamp.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_unit_core.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_unit_cte.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_unit_types.py +0 -0
- {snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/tests/test_unit_url.py +0 -0
|
@@ -4,6 +4,7 @@ repos:
|
|
|
4
4
|
rev: v4.5.0
|
|
5
5
|
hooks:
|
|
6
6
|
- id: trailing-whitespace
|
|
7
|
+
exclude: '\.ambr$'
|
|
7
8
|
- id: end-of-file-fixer
|
|
8
9
|
- id: check-yaml
|
|
9
10
|
exclude: .github/repo_meta.yaml
|
|
@@ -44,3 +45,10 @@ repos:
|
|
|
44
45
|
- id: flake8
|
|
45
46
|
additional_dependencies:
|
|
46
47
|
- flake8-bugbear
|
|
48
|
+
- repo: local
|
|
49
|
+
hooks:
|
|
50
|
+
- id: requirements-update
|
|
51
|
+
name: "Update dependencies from pyproject.toml to snyk/requirements.txt"
|
|
52
|
+
language: system
|
|
53
|
+
entry: python snyk/update_requirements.py
|
|
54
|
+
files: ^pyproject.toml$
|
|
@@ -9,7 +9,31 @@ Source code is also available at:
|
|
|
9
9
|
|
|
10
10
|
# Release Notes
|
|
11
11
|
|
|
12
|
-
- v1.
|
|
12
|
+
- v1.7.0(November 22, 2024)
|
|
13
|
+
|
|
14
|
+
- Add support for dynamic tables and required options
|
|
15
|
+
- Add support for hybrid tables
|
|
16
|
+
- Fixed SAWarning when registering functions with existing name in default namespace
|
|
17
|
+
- Update options to be defined in key arguments instead of arguments.
|
|
18
|
+
- Add support for refresh_mode option in DynamicTable
|
|
19
|
+
- Add support for iceberg table with Snowflake Catalog
|
|
20
|
+
- Fix cluster by option to support explicit expressions
|
|
21
|
+
- Add support for MAP datatype
|
|
22
|
+
|
|
23
|
+
- v1.6.1(July 9, 2024)
|
|
24
|
+
|
|
25
|
+
- Update internal project workflow with pypi publishing
|
|
26
|
+
|
|
27
|
+
- v1.6.0(July 8, 2024)
|
|
28
|
+
|
|
29
|
+
- support for installing with SQLAlchemy 2.0.x
|
|
30
|
+
- use `hatch` & `uv` for managing project virtual environments
|
|
31
|
+
|
|
32
|
+
- v1.5.4
|
|
33
|
+
|
|
34
|
+
- Add ability to set ORDER / NOORDER sequence on columns with IDENTITY
|
|
35
|
+
|
|
36
|
+
- v1.5.3(April 16, 2024)
|
|
13
37
|
|
|
14
38
|
- Limit SQLAlchemy to < 2.0.0 before releasing version compatible with 2.0
|
|
15
39
|
|
|
@@ -20,7 +44,7 @@ Source code is also available at:
|
|
|
20
44
|
|
|
21
45
|
- v1.5.1(November 03, 2023)
|
|
22
46
|
|
|
23
|
-
- Fixed a compatibility issue with Snowflake Behavioral Change 1057 on outer lateral join, for more details check https://docs.snowflake.com/en/release-notes/bcr-bundles/2023_04/bcr-1057
|
|
47
|
+
- Fixed a compatibility issue with Snowflake Behavioral Change 1057 on outer lateral join, for more details check <https://docs.snowflake.com/en/release-notes/bcr-bundles/2023_04/bcr-1057>.
|
|
24
48
|
- Fixed credentials with `externalbrowser` authentication not caching due to incorrect parsing of boolean query parameters.
|
|
25
49
|
- This fixes other boolean parameter passing to driver as well.
|
|
26
50
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: snowflake-sqlalchemy
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.0
|
|
4
4
|
Summary: Snowflake SQLAlchemy Dialect
|
|
5
5
|
Project-URL: Changelog, https://github.com/snowflakedb/snowflake-sqlalchemy/blob/main/DESCRIPTION.md
|
|
6
6
|
Project-URL: Documentation, https://docs.snowflake.com/en/user-guide/sqlalchemy.html
|
|
@@ -8,8 +8,7 @@ Project-URL: Homepage, https://www.snowflake.com/
|
|
|
8
8
|
Project-URL: Issues, https://github.com/snowflakedb/snowflake-sqlalchemy/issues
|
|
9
9
|
Project-URL: Source, https://github.com/snowflakedb/snowflake-sqlalchemy
|
|
10
10
|
Author-email: "Snowflake Inc." <triage-snowpark-python-api-dl@snowflake.com>
|
|
11
|
-
License
|
|
12
|
-
License-File: LICENSE.txt
|
|
11
|
+
License: Apache-2.0
|
|
13
12
|
Keywords: Snowflake,analytics,cloud,database,db,warehouse
|
|
14
13
|
Classifier: Development Status :: 5 - Production/Stable
|
|
15
14
|
Classifier: Environment :: Console
|
|
@@ -36,7 +35,7 @@ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
|
36
35
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
37
36
|
Requires-Python: >=3.8
|
|
38
37
|
Requires-Dist: snowflake-connector-python<4.0.0
|
|
39
|
-
Requires-Dist: sqlalchemy
|
|
38
|
+
Requires-Dist: sqlalchemy>=1.4.19
|
|
40
39
|
Provides-Extra: development
|
|
41
40
|
Requires-Dist: mock; extra == 'development'
|
|
42
41
|
Requires-Dist: numpy; extra == 'development'
|
|
@@ -46,6 +45,7 @@ Requires-Dist: pytest-cov; extra == 'development'
|
|
|
46
45
|
Requires-Dist: pytest-rerunfailures; extra == 'development'
|
|
47
46
|
Requires-Dist: pytest-timeout; extra == 'development'
|
|
48
47
|
Requires-Dist: pytz; extra == 'development'
|
|
48
|
+
Requires-Dist: syrupy==4.6.1; extra == 'development'
|
|
49
49
|
Provides-Extra: pandas
|
|
50
50
|
Requires-Dist: snowflake-connector-python[pandas]; extra == 'pandas'
|
|
51
51
|
Description-Content-Type: text/markdown
|
|
@@ -153,6 +153,7 @@ containing special characters need to be URL encoded to be parsed correctly. Thi
|
|
|
153
153
|
characters could lead to authentication failure.
|
|
154
154
|
|
|
155
155
|
The encoding for the password can be generated using `urllib.parse`:
|
|
156
|
+
|
|
156
157
|
```python
|
|
157
158
|
import urllib.parse
|
|
158
159
|
urllib.parse.quote("kx@% jj5/g")
|
|
@@ -163,6 +164,7 @@ urllib.parse.quote("kx@% jj5/g")
|
|
|
163
164
|
|
|
164
165
|
To create an engine with the proper encodings, either manually constructing the url string by formatting
|
|
165
166
|
or taking advantage of the `snowflake.sqlalchemy.URL` helper method:
|
|
167
|
+
|
|
166
168
|
```python
|
|
167
169
|
import urllib.parse
|
|
168
170
|
from snowflake.sqlalchemy import URL
|
|
@@ -243,14 +245,23 @@ engine = create_engine(...)
|
|
|
243
245
|
engine.execute(<SQL>)
|
|
244
246
|
engine.dispose()
|
|
245
247
|
|
|
246
|
-
#
|
|
248
|
+
# Better.
|
|
247
249
|
engine = create_engine(...)
|
|
248
250
|
connection = engine.connect()
|
|
249
251
|
try:
|
|
250
|
-
|
|
252
|
+
connection.execute(text(<SQL>))
|
|
251
253
|
finally:
|
|
252
254
|
connection.close()
|
|
253
255
|
engine.dispose()
|
|
256
|
+
|
|
257
|
+
# Best
|
|
258
|
+
try:
|
|
259
|
+
with engine.connext() as connection:
|
|
260
|
+
connection.execute(text(<SQL>))
|
|
261
|
+
# or
|
|
262
|
+
connection.exec_driver_sql(<SQL>)
|
|
263
|
+
finally:
|
|
264
|
+
engine.dispose()
|
|
254
265
|
```
|
|
255
266
|
|
|
256
267
|
### Auto-increment Behavior
|
|
@@ -294,14 +305,14 @@ engine = create_engine(URL(
|
|
|
294
305
|
|
|
295
306
|
specific_date = np.datetime64('2016-03-04T12:03:05.123456789Z')
|
|
296
307
|
|
|
297
|
-
|
|
298
|
-
connection.
|
|
299
|
-
|
|
300
|
-
connection.
|
|
301
|
-
|
|
302
|
-
)
|
|
303
|
-
df = pd.read_sql_query("SELECT * FROM ts_tbl",
|
|
304
|
-
assert df.c1.values[0] == specific_date
|
|
308
|
+
with engine.connect() as connection:
|
|
309
|
+
connection.exec_driver_sql(
|
|
310
|
+
"CREATE OR REPLACE TABLE ts_tbl(c1 TIMESTAMP_NTZ)")
|
|
311
|
+
connection.exec_driver_sql(
|
|
312
|
+
"INSERT INTO ts_tbl(c1) values(%s)", (specific_date,)
|
|
313
|
+
)
|
|
314
|
+
df = pd.read_sql_query("SELECT * FROM ts_tbl", connection)
|
|
315
|
+
assert df.c1.values[0] == specific_date
|
|
305
316
|
```
|
|
306
317
|
|
|
307
318
|
The following `NumPy` data types are supported:
|
|
@@ -381,7 +392,7 @@ This example shows how to create a table with two columns, `id` and `name`, as t
|
|
|
381
392
|
t = Table('myuser', metadata,
|
|
382
393
|
Column('id', Integer, primary_key=True),
|
|
383
394
|
Column('name', String),
|
|
384
|
-
snowflake_clusterby=['id', 'name'], ...
|
|
395
|
+
snowflake_clusterby=['id', 'name', text('id > 5')], ...
|
|
385
396
|
)
|
|
386
397
|
metadata.create_all(engine)
|
|
387
398
|
```
|
|
@@ -101,6 +101,7 @@ containing special characters need to be URL encoded to be parsed correctly. Thi
|
|
|
101
101
|
characters could lead to authentication failure.
|
|
102
102
|
|
|
103
103
|
The encoding for the password can be generated using `urllib.parse`:
|
|
104
|
+
|
|
104
105
|
```python
|
|
105
106
|
import urllib.parse
|
|
106
107
|
urllib.parse.quote("kx@% jj5/g")
|
|
@@ -111,6 +112,7 @@ urllib.parse.quote("kx@% jj5/g")
|
|
|
111
112
|
|
|
112
113
|
To create an engine with the proper encodings, either manually constructing the url string by formatting
|
|
113
114
|
or taking advantage of the `snowflake.sqlalchemy.URL` helper method:
|
|
115
|
+
|
|
114
116
|
```python
|
|
115
117
|
import urllib.parse
|
|
116
118
|
from snowflake.sqlalchemy import URL
|
|
@@ -191,14 +193,23 @@ engine = create_engine(...)
|
|
|
191
193
|
engine.execute(<SQL>)
|
|
192
194
|
engine.dispose()
|
|
193
195
|
|
|
194
|
-
#
|
|
196
|
+
# Better.
|
|
195
197
|
engine = create_engine(...)
|
|
196
198
|
connection = engine.connect()
|
|
197
199
|
try:
|
|
198
|
-
|
|
200
|
+
connection.execute(text(<SQL>))
|
|
199
201
|
finally:
|
|
200
202
|
connection.close()
|
|
201
203
|
engine.dispose()
|
|
204
|
+
|
|
205
|
+
# Best
|
|
206
|
+
try:
|
|
207
|
+
with engine.connext() as connection:
|
|
208
|
+
connection.execute(text(<SQL>))
|
|
209
|
+
# or
|
|
210
|
+
connection.exec_driver_sql(<SQL>)
|
|
211
|
+
finally:
|
|
212
|
+
engine.dispose()
|
|
202
213
|
```
|
|
203
214
|
|
|
204
215
|
### Auto-increment Behavior
|
|
@@ -242,14 +253,14 @@ engine = create_engine(URL(
|
|
|
242
253
|
|
|
243
254
|
specific_date = np.datetime64('2016-03-04T12:03:05.123456789Z')
|
|
244
255
|
|
|
245
|
-
|
|
246
|
-
connection.
|
|
247
|
-
|
|
248
|
-
connection.
|
|
249
|
-
|
|
250
|
-
)
|
|
251
|
-
df = pd.read_sql_query("SELECT * FROM ts_tbl",
|
|
252
|
-
assert df.c1.values[0] == specific_date
|
|
256
|
+
with engine.connect() as connection:
|
|
257
|
+
connection.exec_driver_sql(
|
|
258
|
+
"CREATE OR REPLACE TABLE ts_tbl(c1 TIMESTAMP_NTZ)")
|
|
259
|
+
connection.exec_driver_sql(
|
|
260
|
+
"INSERT INTO ts_tbl(c1) values(%s)", (specific_date,)
|
|
261
|
+
)
|
|
262
|
+
df = pd.read_sql_query("SELECT * FROM ts_tbl", connection)
|
|
263
|
+
assert df.c1.values[0] == specific_date
|
|
253
264
|
```
|
|
254
265
|
|
|
255
266
|
The following `NumPy` data types are supported:
|
|
@@ -329,7 +340,7 @@ This example shows how to create a table with two columns, `id` and `name`, as t
|
|
|
329
340
|
t = Table('myuser', metadata,
|
|
330
341
|
Column('id', Integer, primary_key=True),
|
|
331
342
|
Column('name', String),
|
|
332
|
-
snowflake_clusterby=['id', 'name'], ...
|
|
343
|
+
snowflake_clusterby=['id', 'name', text('id > 5')], ...
|
|
333
344
|
)
|
|
334
345
|
metadata.create_all(engine)
|
|
335
346
|
```
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Build snowflake-sqlalchemy
|
|
4
4
|
set -o pipefail
|
|
5
5
|
|
|
6
|
-
PYTHON="python3.
|
|
6
|
+
PYTHON="python3.8"
|
|
7
7
|
THIS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
8
|
SQLALCHEMY_DIR="$(dirname "${THIS_DIR}")"
|
|
9
9
|
DIST_DIR="${SQLALCHEMY_DIR}/dist"
|
|
@@ -11,14 +11,16 @@ DIST_DIR="${SQLALCHEMY_DIR}/dist"
|
|
|
11
11
|
cd "$SQLALCHEMY_DIR"
|
|
12
12
|
# Clean up previously built DIST_DIR
|
|
13
13
|
if [ -d "${DIST_DIR}" ]; then
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
echo "[WARN] ${DIST_DIR} already existing, deleting it..."
|
|
15
|
+
rm -rf "${DIST_DIR}"
|
|
16
16
|
fi
|
|
17
17
|
|
|
18
18
|
# Constants and setup
|
|
19
|
+
export PATH=$PATH:$HOME/.local/bin
|
|
19
20
|
|
|
20
21
|
echo "[Info] Building snowflake-sqlalchemy with $PYTHON"
|
|
21
22
|
# Clean up possible build artifacts
|
|
22
23
|
rm -rf build generated_version.py
|
|
23
|
-
|
|
24
|
-
${PYTHON} -m
|
|
24
|
+
export UV_NO_CACHE=true
|
|
25
|
+
${PYTHON} -m pip install uv hatch
|
|
26
|
+
${PYTHON} -m hatch build
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/bin/bash -e
|
|
2
|
+
#
|
|
3
|
+
# Test Snowflake SQLAlchemy in Linux
|
|
4
|
+
# NOTES:
|
|
5
|
+
# - Versions to be tested should be passed in as the first argument, e.g: "3.7 3.8". If omitted 3.7-3.11 will be assumed.
|
|
6
|
+
# - This script assumes that ../dist/repaired_wheels has the wheel(s) built for all versions to be tested
|
|
7
|
+
# - This is the script that test_docker.sh runs inside of the docker container
|
|
8
|
+
|
|
9
|
+
PYTHON_VERSIONS="${1:-3.8 3.9 3.10 3.11}"
|
|
10
|
+
THIS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
|
+
SQLALCHEMY_DIR="$(dirname "${THIS_DIR}")"
|
|
12
|
+
|
|
13
|
+
# Install one copy of tox
|
|
14
|
+
python3 -m pip install -U tox
|
|
15
|
+
|
|
16
|
+
# Run tests
|
|
17
|
+
cd $SQLALCHEMY_DIR
|
|
18
|
+
for PYTHON_VERSION in ${PYTHON_VERSIONS}; do
|
|
19
|
+
echo "[Info] Testing with ${PYTHON_VERSION}"
|
|
20
|
+
SHORT_VERSION=$(python3 -c "print('${PYTHON_VERSION}'.replace('.', ''))")
|
|
21
|
+
SQLALCHEMY_WHL=$(ls $SQLALCHEMY_DIR/dist/snowflake_sqlalchemy-*-py3-none-any.whl | sort -r | head -n 1)
|
|
22
|
+
TEST_ENVLIST=fix_lint,py${SHORT_VERSION}-ci,py${SHORT_VERSION}-coverage
|
|
23
|
+
echo "[Info] Running tox for ${TEST_ENVLIST}"
|
|
24
|
+
python3 -m tox -e ${TEST_ENVLIST} --installpkg ${SQLALCHEMY_WHL}
|
|
25
|
+
done
|
|
@@ -38,7 +38,7 @@ classifiers = [
|
|
|
38
38
|
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
39
39
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
40
40
|
]
|
|
41
|
-
dependencies = ["snowflake-connector-python<4.0.0"
|
|
41
|
+
dependencies = ["SQLAlchemy>=1.4.19", "snowflake-connector-python<4.0.0"]
|
|
42
42
|
|
|
43
43
|
[tool.hatch.version]
|
|
44
44
|
path = "src/snowflake/sqlalchemy/version.py"
|
|
@@ -53,6 +53,7 @@ development = [
|
|
|
53
53
|
"pytz",
|
|
54
54
|
"numpy",
|
|
55
55
|
"mock",
|
|
56
|
+
"syrupy==4.6.1",
|
|
56
57
|
]
|
|
57
58
|
pandas = ["snowflake-connector-python[pandas]"]
|
|
58
59
|
|
|
@@ -73,6 +74,13 @@ exclude = ["/.github"]
|
|
|
73
74
|
packages = ["src/snowflake"]
|
|
74
75
|
|
|
75
76
|
[tool.hatch.envs.default]
|
|
77
|
+
extra-dependencies = ["SQLAlchemy>=1.4.19,<2.1.0"]
|
|
78
|
+
features = ["development", "pandas"]
|
|
79
|
+
python = "3.8"
|
|
80
|
+
installer = "uv"
|
|
81
|
+
|
|
82
|
+
[tool.hatch.envs.sa14]
|
|
83
|
+
extra-dependencies = ["SQLAlchemy>=1.4.19,<2.0.0"]
|
|
76
84
|
features = ["development", "pandas"]
|
|
77
85
|
python = "3.8"
|
|
78
86
|
|
|
@@ -82,10 +90,19 @@ SQLACHEMY_WARN_20 = "1"
|
|
|
82
90
|
|
|
83
91
|
[tool.hatch.envs.default.scripts]
|
|
84
92
|
check = "pre-commit run --all-files"
|
|
85
|
-
test-dialect = "pytest -ra -vvv --tb=short --cov snowflake.sqlalchemy --cov-append --junitxml ./junit.xml --ignore=tests/sqlalchemy_test_suite"
|
|
93
|
+
test-dialect = "pytest -ra -vvv --tb=short --cov snowflake.sqlalchemy --cov-append --junitxml ./junit.xml --ignore=tests/sqlalchemy_test_suite tests/"
|
|
86
94
|
test-dialect-compatibility = "pytest -ra -vvv --tb=short --cov snowflake.sqlalchemy --cov-append --junitxml ./junit.xml tests/sqlalchemy_test_suite"
|
|
87
|
-
test-
|
|
95
|
+
test-dialect-aws = "pytest -m \"aws\" -ra -vvv --tb=short --cov snowflake.sqlalchemy --cov-append --junitxml ./junit.xml --ignore=tests/sqlalchemy_test_suite tests/"
|
|
88
96
|
gh-cache-sum = "python -VV | sha256sum | cut -d' ' -f1"
|
|
97
|
+
check-import = "python -c 'import snowflake.sqlalchemy; print(snowflake.sqlalchemy.__version__)'"
|
|
98
|
+
|
|
99
|
+
[[tool.hatch.envs.release.matrix]]
|
|
100
|
+
python = ["3.8", "3.9", "3.10", "3.11", "3.12"]
|
|
101
|
+
features = ["development", "pandas"]
|
|
102
|
+
|
|
103
|
+
[tool.hatch.envs.release.scripts]
|
|
104
|
+
test-dialect = "pytest -ra -vvv --tb=short --ignore=tests/sqlalchemy_test_suite tests/"
|
|
105
|
+
test-compatibility = "pytest -ra -vvv --tb=short tests/sqlalchemy_test_suite tests/"
|
|
89
106
|
|
|
90
107
|
[tool.ruff]
|
|
91
108
|
line-length = 88
|
|
@@ -94,6 +111,7 @@ line-length = 88
|
|
|
94
111
|
line-length = 88
|
|
95
112
|
|
|
96
113
|
[tool.pytest.ini_options]
|
|
114
|
+
addopts = "-m 'not feature_max_lob_size and not aws and not requires_external_volume'"
|
|
97
115
|
markers = [
|
|
98
116
|
# Optional dependency groups markers
|
|
99
117
|
"lambda: AWS lambda tests",
|
|
@@ -110,5 +128,7 @@ markers = [
|
|
|
110
128
|
# Other markers
|
|
111
129
|
"timeout: tests that need a timeout time",
|
|
112
130
|
"internal: tests that could but should only run on our internal CI",
|
|
131
|
+
"requires_external_volume: tests that needs a external volume to be executed",
|
|
113
132
|
"external: tests that could but should only run on our external CI",
|
|
133
|
+
"feature_max_lob_size: tests that could but should only run on our external CI",
|
|
114
134
|
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import tomlkit
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def sync():
|
|
7
|
+
pyproject = tomlkit.loads(Path("pyproject.toml").read_text())
|
|
8
|
+
snyk_reqiurements = Path("snyk/requirements.txt")
|
|
9
|
+
dependencies = pyproject.get("project", {}).get("dependencies", [])
|
|
10
|
+
|
|
11
|
+
with snyk_reqiurements.open("w") as fh:
|
|
12
|
+
fh.write("\n".join(dependencies))
|
|
13
|
+
fh.write("\n")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
if __name__ == "__main__":
|
|
17
|
+
sync()
|
{snowflake_sqlalchemy-1.5.3 → snowflake_sqlalchemy-1.7.0}/src/snowflake/sqlalchemy/__init__.py
RENAMED
|
@@ -9,7 +9,7 @@ if sys.version_info < (3, 8):
|
|
|
9
9
|
else:
|
|
10
10
|
import importlib.metadata as importlib_metadata
|
|
11
11
|
|
|
12
|
-
from sqlalchemy.types import (
|
|
12
|
+
from sqlalchemy.types import ( # noqa
|
|
13
13
|
BIGINT,
|
|
14
14
|
BINARY,
|
|
15
15
|
BOOLEAN,
|
|
@@ -27,8 +27,8 @@ from sqlalchemy.types import (
|
|
|
27
27
|
VARCHAR,
|
|
28
28
|
)
|
|
29
29
|
|
|
30
|
-
from . import base, snowdialect
|
|
31
|
-
from .custom_commands import (
|
|
30
|
+
from . import base, snowdialect # noqa
|
|
31
|
+
from .custom_commands import ( # noqa
|
|
32
32
|
AWSBucket,
|
|
33
33
|
AzureContainer,
|
|
34
34
|
CopyFormatter,
|
|
@@ -41,7 +41,7 @@ from .custom_commands import (
|
|
|
41
41
|
MergeInto,
|
|
42
42
|
PARQUETFormatter,
|
|
43
43
|
)
|
|
44
|
-
from .custom_types import (
|
|
44
|
+
from .custom_types import ( # noqa
|
|
45
45
|
ARRAY,
|
|
46
46
|
BYTEINT,
|
|
47
47
|
CHARACTER,
|
|
@@ -50,6 +50,7 @@ from .custom_types import (
|
|
|
50
50
|
FIXED,
|
|
51
51
|
GEOGRAPHY,
|
|
52
52
|
GEOMETRY,
|
|
53
|
+
MAP,
|
|
53
54
|
NUMBER,
|
|
54
55
|
OBJECT,
|
|
55
56
|
STRING,
|
|
@@ -61,13 +62,30 @@ from .custom_types import (
|
|
|
61
62
|
VARBINARY,
|
|
62
63
|
VARIANT,
|
|
63
64
|
)
|
|
64
|
-
from .
|
|
65
|
+
from .sql.custom_schema import ( # noqa
|
|
66
|
+
DynamicTable,
|
|
67
|
+
HybridTable,
|
|
68
|
+
IcebergTable,
|
|
69
|
+
SnowflakeTable,
|
|
70
|
+
)
|
|
71
|
+
from .sql.custom_schema.options import ( # noqa
|
|
72
|
+
AsQueryOption,
|
|
73
|
+
ClusterByOption,
|
|
74
|
+
IdentifierOption,
|
|
75
|
+
KeywordOption,
|
|
76
|
+
LiteralOption,
|
|
77
|
+
SnowflakeKeyword,
|
|
78
|
+
TableOptionKey,
|
|
79
|
+
TargetLagOption,
|
|
80
|
+
TimeUnit,
|
|
81
|
+
)
|
|
82
|
+
from .util import _url as URL # noqa
|
|
65
83
|
|
|
66
84
|
base.dialect = dialect = snowdialect.dialect
|
|
67
85
|
|
|
68
86
|
__version__ = importlib_metadata.version("snowflake-sqlalchemy")
|
|
69
87
|
|
|
70
|
-
|
|
88
|
+
_custom_types = (
|
|
71
89
|
"BIGINT",
|
|
72
90
|
"BINARY",
|
|
73
91
|
"BOOLEAN",
|
|
@@ -102,6 +120,10 @@ __all__ = (
|
|
|
102
120
|
"TINYINT",
|
|
103
121
|
"VARBINARY",
|
|
104
122
|
"VARIANT",
|
|
123
|
+
"MAP",
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
_custom_commands = (
|
|
105
127
|
"MergeInto",
|
|
106
128
|
"CSVFormatter",
|
|
107
129
|
"JSONFormatter",
|
|
@@ -114,3 +136,27 @@ __all__ = (
|
|
|
114
136
|
"CreateStage",
|
|
115
137
|
"CreateFileFormat",
|
|
116
138
|
)
|
|
139
|
+
|
|
140
|
+
_custom_tables = ("HybridTable", "DynamicTable", "IcebergTable", "SnowflakeTable")
|
|
141
|
+
|
|
142
|
+
_custom_table_options = (
|
|
143
|
+
"AsQueryOption",
|
|
144
|
+
"TargetLagOption",
|
|
145
|
+
"LiteralOption",
|
|
146
|
+
"IdentifierOption",
|
|
147
|
+
"KeywordOption",
|
|
148
|
+
"ClusterByOption",
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
_enums = (
|
|
152
|
+
"TimeUnit",
|
|
153
|
+
"TableOptionKey",
|
|
154
|
+
"SnowflakeKeyword",
|
|
155
|
+
)
|
|
156
|
+
__all__ = (
|
|
157
|
+
*_custom_types,
|
|
158
|
+
*_custom_commands,
|
|
159
|
+
*_custom_tables,
|
|
160
|
+
*_custom_table_options,
|
|
161
|
+
*_enums,
|
|
162
|
+
)
|