snowflake-sqlalchemy 1.8.2__tar.gz → 1.10.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.8.2 → snowflake_sqlalchemy-1.10.0}/DESCRIPTION.md +50 -0
- snowflake_sqlalchemy-1.10.0/PKG-INFO +1593 -0
- snowflake_sqlalchemy-1.10.0/README.md +1537 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/ci/build.sh +2 -2
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/ci/test_linux.sh +9 -2
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/pyproject.toml +8 -2
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/__init__.py +31 -0
- snowflake_sqlalchemy-1.10.0/src/snowflake/sqlalchemy/alembic_util.py +140 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/base.py +150 -55
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/compat.py +1 -1
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/custom_commands.py +56 -2
- snowflake_sqlalchemy-1.10.0/src/snowflake/sqlalchemy/custom_types.py +295 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/exc.py +9 -0
- snowflake_sqlalchemy-1.10.0/src/snowflake/sqlalchemy/name_utils.py +63 -0
- snowflake_sqlalchemy-1.10.0/src/snowflake/sqlalchemy/orm.py +232 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/parser/custom_type_parser.py +33 -1
- snowflake_sqlalchemy-1.10.0/src/snowflake/sqlalchemy/provision.py +37 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/requirements.py +7 -3
- snowflake_sqlalchemy-1.10.0/src/snowflake/sqlalchemy/snowdialect.py +1807 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/structured_type_info_manager.py +61 -12
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/util.py +114 -140
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/version.py +1 -1
- snowflake_sqlalchemy-1.10.0/tests/README.rst +99 -0
- snowflake_sqlalchemy-1.10.0/tests/alembic_integration/README.md +41 -0
- snowflake_sqlalchemy-1.10.0/tests/alembic_integration/conftest.py +14 -0
- snowflake_sqlalchemy-1.10.0/tests/alembic_integration/test_multi_schema_fk.py +247 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/conftest.py +52 -3
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/__snapshots__/test_reflect_snowflake_table.ambr +3 -3
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/test_create_dynamic_table.py +6 -9
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/test_reflect_dynamic_table.py +8 -6
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/test_reflect_snowflake_table.py +3 -3
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/sqlalchemy_test_suite/test_suite.py +0 -15
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/sqlalchemy_test_suite/test_suite_20.py +0 -15
- snowflake_sqlalchemy-1.10.0/tests/test_compat.py +39 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_compiler.py +109 -4
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_copy.py +74 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_core.py +557 -34
- snowflake_sqlalchemy-1.10.0/tests/test_cross_database_reflection.py +446 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_custom_types.py +11 -2
- snowflake_sqlalchemy-1.10.0/tests/test_decfloat.py +366 -0
- snowflake_sqlalchemy-1.10.0/tests/test_dialect_connect.py +258 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_index_reflection.py +23 -15
- snowflake_sqlalchemy-1.10.0/tests/test_keys.py +171 -0
- snowflake_sqlalchemy-1.10.0/tests/test_loader_criteria_regression.py +104 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_pandas.py +38 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_sequence.py +34 -1
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_structured_datatypes.py +4 -4
- snowflake_sqlalchemy-1.10.0/tests/test_timestamp.py +298 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_transactions.py +5 -3
- snowflake_sqlalchemy-1.10.0/tests/test_unit_case_sensitivity.py +1112 -0
- snowflake_sqlalchemy-1.10.0/tests/test_unit_core.py +364 -0
- snowflake_sqlalchemy-1.10.0/tests/test_unit_orm.py +421 -0
- snowflake_sqlalchemy-1.10.0/tests/test_unit_structured_types.py +162 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_unit_types.py +8 -2
- snowflake_sqlalchemy-1.10.0/tests/test_vector.py +198 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/util.py +18 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tox.ini +21 -13
- snowflake_sqlalchemy-1.8.2/PKG-INFO +0 -758
- snowflake_sqlalchemy-1.8.2/README.md +0 -702
- snowflake_sqlalchemy-1.8.2/src/snowflake/sqlalchemy/custom_types.py +0 -155
- snowflake_sqlalchemy-1.8.2/src/snowflake/sqlalchemy/name_utils.py +0 -36
- snowflake_sqlalchemy-1.8.2/src/snowflake/sqlalchemy/provision.py +0 -12
- snowflake_sqlalchemy-1.8.2/src/snowflake/sqlalchemy/snowdialect.py +0 -969
- snowflake_sqlalchemy-1.8.2/tests/README.rst +0 -51
- snowflake_sqlalchemy-1.8.2/tests/test_dialect_connect.py +0 -124
- snowflake_sqlalchemy-1.8.2/tests/test_timestamp.py +0 -83
- snowflake_sqlalchemy-1.8.2/tests/test_unit_core.py +0 -169
- snowflake_sqlalchemy-1.8.2/tests/test_unit_structured_types.py +0 -81
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/.gitignore +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/.gitmodules +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/.pre-commit-config.yaml +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/LICENSE.txt +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/MANIFEST.in +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/ci/build_docker.sh +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/ci/docker/sqlalchemy_build/Dockerfile +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/ci/docker/sqlalchemy_build/scripts/entrypoint.sh +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/ci/set_base_image.sh +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/ci/test.sh +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/ci/test_docker.sh +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/license_header.txt +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/setup.cfg +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/snyk/requirements.txt +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/snyk/requiremtnts.txt +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/snyk/update_requirements.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/_constants.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/functions.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/__init__.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/__init__.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/clustered_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/custom_table_base.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/custom_table_prefix.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/dynamic_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/hybrid_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/iceberg_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/options/__init__.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/options/as_query_option.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/options/cluster_by_option.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/options/identifier_option.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/options/invalid_table_option.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/options/keyword_option.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/options/keywords.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/options/literal_option.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/options/table_option.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/options/target_lag_option.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/snowflake_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/src/snowflake/sqlalchemy/sql/custom_schema/table_from_query.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tested_requirements/requirements_310.reqs +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tested_requirements/requirements_37.reqs +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tested_requirements/requirements_38.reqs +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tested_requirements/requirements_39.reqs +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/__init__.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/__snapshots__/test_compile_dynamic_table.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/__snapshots__/test_core.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/__snapshots__/test_orm.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/__snapshots__/test_reflect_dynamic_table.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/__snapshots__/test_structured_datatypes.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/__snapshots__/test_unit_structured_types.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/__init__.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/__snapshots__/test_compile_dynamic_table.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/__snapshots__/test_compile_hybrid_table.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/__snapshots__/test_compile_iceberg_table.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/__snapshots__/test_compile_snowflake_table.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/__snapshots__/test_create_dynamic_table.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/__snapshots__/test_create_hybrid_table.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/__snapshots__/test_create_iceberg_table.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/__snapshots__/test_create_snowflake_table.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/__snapshots__/test_generic_options.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/__snapshots__/test_reflect_hybrid_table.ambr +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/test_compile_dynamic_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/test_compile_hybrid_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/test_compile_iceberg_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/test_compile_snowflake_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/test_create_hybrid_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/test_create_iceberg_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/test_create_snowflake_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/test_generic_options.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/custom_tables/test_reflect_hybrid_table.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/data/users.txt +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/sqlalchemy_test_suite/README.md +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/sqlalchemy_test_suite/__init__.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/sqlalchemy_test_suite/conftest.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_create.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_custom_functions.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_geography.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_geometry.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_imports.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_multivalues_insert.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_orm.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_qmark.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_quote.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_quote_identifiers.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_semi_structured_datatypes.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_unit_cte.py +0 -0
- {snowflake_sqlalchemy-1.8.2 → snowflake_sqlalchemy-1.10.0}/tests/test_unit_url.py +0 -0
|
@@ -11,6 +11,56 @@ Source code is also available at:
|
|
|
11
11
|
|
|
12
12
|
# Release Notes
|
|
13
13
|
|
|
14
|
+
- v1.10.0 (May 20, 2026)
|
|
15
|
+
- Fix `with_loader_criteria` silently dropping filters on non-Snowflake dialects ([#676](https://github.com/snowflakedb/snowflake-sqlalchemy/issues/676)). Importing `snowflake-sqlalchemy` previously altered SQLAlchemy's ORM compilation for every dialect in the process, causing loader-criteria filters to be omitted inside sealed subqueries when using PostgreSQL, MySQL, SQLite, etc. Snowflake dialect behavior is unchanged; the BCR-1057 lateral-join workaround is now scoped to Snowflake connections only.
|
|
16
|
+
- Map Snowflake `UUID` column type to `sqlalchemy.sql.sqltypes.UUID` for reflection on SQLAlchemy 2.x ([#681](https://github.com/snowflakedb/snowflake-sqlalchemy/issues/681)). Previously reflected as `NullType`. Values are returned as plain strings (`as_uuid=False`) rather than `uuid.UUID` instances. No change on SQLAlchemy 1.4 where the generic `UUID` type does not exist.
|
|
17
|
+
- Add GCS bucket support for `CopyIntoStorage` (SNOW-721174, [#368](https://github.com/snowflakedb/snowflake-sqlalchemy/issues/368)).
|
|
18
|
+
- Scope `referred_schema=None` normalization in foreign key reflection to the default schema only ([#610](https://github.com/snowflakedb/snowflake-sqlalchemy/issues/610), SNOW-2313675):
|
|
19
|
+
- When reflecting the default schema, same-schema FKs (default → default) keep the established SQLAlchemy convention of `referred_schema=None`, preserving compatibility with the upstream reflection test suite and with applications that do not qualify default-schema FK targets.
|
|
20
|
+
- When reflecting a non-default schema every FK keeps its actual `referred_schema`, which prevents SQLAlchemy's `_reflect_fk` from autoloading a non-default-schema target from the wrong place (the bug behind #610) and avoids the Alembic autogenerate mismatch that previously occurred when user metadata explicitly qualified a cross-schema FK that happened to target the default schema.
|
|
21
|
+
- Add `SnowflakeBase`, `snowflake_declarative_base()`, and `SnowflakeSession` to enable efficient bulk inserts for ORM models with nullable optional columns (SNOW-893080, [#441](https://github.com/snowflakedb/snowflake-sqlalchemy/issues/441)). When `session.bulk_save_objects()` is used with models that have randomly populated nullable columns, SQLAlchemy normally groups objects by their set of non-None column keys, producing O(N) separate INSERT statements. `SnowflakeBase` / `snowflake_declarative_base()` pre-populate all plain-nullable columns at construction time, and `SnowflakeSession` passes `render_nulls=True` so all objects share the same parameter-key set and are batched into a single `executemany` INSERT.
|
|
22
|
+
- Fix case-sensitive identifier handling (SNOW-1232488). Always-active bug fixes with no behavioural change for default users:
|
|
23
|
+
- `_split_schema_by_dot` now correctly parses SQL-escaped double-quotes (`""`) inside quoted schema/database identifiers (e.g. `"my""schema"` → `my"schema`), preventing silent truncation of identifiers containing literal quote characters.
|
|
24
|
+
- `denormalize_column_name` now correctly double-quotes `quoted_name("mycol", True)` columns in `CLUSTER BY` clauses instead of silently dropping the case-sensitivity signal. The caller has already opted into case-sensitive semantics by constructing a `quoted_name(..., True)`, so this is honoured independently of the dialect flag.
|
|
25
|
+
- `_has_object` (used by `has_table` / `has_sequence`) now applies `denormalize_name` to both the schema and object name before building the `DESC` SQL, making it consistent with all other reflection methods.
|
|
26
|
+
- Atomic `_NameUtils` swap in `create_connect_args` — when the URL's `case_sensitive_identifiers` value differs from the current dialect state, the `name_utils` instance is replaced rather than mutated in place, so concurrent readers on other threads observe either the old or the new instance but never a torn update.
|
|
27
|
+
- Add `case_sensitive_identifiers` opt-in engine flag (kwarg or `?case_sensitive_identifiers=True` URL param) governing three related behaviours. The default is `False`; existing applications are unaffected unless they explicitly opt in:
|
|
28
|
+
- ALL-UPPERCASE reserved-word identifiers (e.g. `TABLE`) are normalised to `quoted_name("table", True)` instead of returning unchanged, preventing key-lookup mismatches between creation and reflection.
|
|
29
|
+
- Mixed-case reflected identifiers (e.g. `MyCol` from a quoted Snowflake column) are returned as `quoted_name("MyCol", True)` instead of a plain `str`. Emitted SQL is identical in both modes (`_requires_quotes` force-quotes any name containing uppercase chars); the difference is only observable via `isinstance(..., quoted_name)` and `.quote`.
|
|
30
|
+
- Schema strings with inner double-quotes — e.g. `'"myschema"'` or `'"mydb"."myschema"'` — have their extracted parts marked `quote=True` by `_split_schema_by_dot`, preserving case-sensitivity in emitted SQL. Without the flag, the extracted parts keep `quote=None` and the preparer's `_requires_quotes` heuristic decides per-part (stripping inner quotes for all-lowercase parts, which matches pre-PR behaviour). Use `quoted_name("myschema", True)` or `MetaData(schema=quoted_name(..., True))` to opt into case-sensitivity on a per-value basis without enabling the flag.
|
|
31
|
+
- Add `create_snowflake_engine(url, schema=..., case_sensitive_schema=True)` helper that URL-encodes case-sensitive schema names using `%22` so the Snowflake connector receives the literal double-quoted form. Fix security vulnerability: schema names are now always URL-encoded regardless of `case_sensitive_schema`, preventing special characters (`?`, `#`, `/`) from being misinterpreted as URL delimiters by SQLAlchemy's URL parser.
|
|
32
|
+
- Add `snowflake.sqlalchemy.alembic_util.render_item` — a drop-in Alembic `render_item` hook for `env.py` that serialises `quoted_name` columns with `quote=True` correctly in generated migration files, preventing Alembic autogenerate from silently converting case-sensitive column names to uppercase.
|
|
33
|
+
- Emit `SnowflakeWarning` at DDL compile time when `Identity()` is used on a primary key column, alerting users that ORM flush operations will raise a `FlushError`. The warning is emitted once per unique `(table, column)` pair per Python process. Use `Sequence()` instead.
|
|
34
|
+
- Add support for cross-database schema reflection using `schema='database.schema'` notation. This allows reflecting and joining tables from different databases in a single session without raw SQL. ([#456](https://github.com/snowflakedb/snowflake-sqlalchemy/issues/456))
|
|
35
|
+
- Restored backward-compatible SQL generation for true division (`/`) when `div_is_floordiv=True`: the Snowflake compiler now correctly delegates to the SQLAlchemy base implementation, emitting `CAST(col AS NUMERIC)` for integer operands as it did before [#545](https://github.com/snowflakedb/snowflake-sqlalchemy/pull/545) introduced the override ([#618](https://github.com/snowflakedb/snowflake-sqlalchemy/issues/618)).
|
|
36
|
+
- Introduce composite key ordering, fixes [#450](https://github.com/snowflakedb/snowflake-sqlalchemy/issues/450)
|
|
37
|
+
- Optimise reflection performance (SNOW-689531, [#656](https://github.com/snowflakedb/snowflake-sqlalchemy/pull/656)):
|
|
38
|
+
- Add `get_multi_columns`, `get_multi_pk_constraint`, `get_multi_unique_constraints`, `get_multi_foreign_keys` for SQLAlchemy 2.x bulk reflection — each issues one schema-wide query per reflection pass instead of one query per table.
|
|
39
|
+
- SQLAlchemy 2.x `get_columns` now uses `DESC TABLE` directly (per-table, live) since `get_multi_columns` handles all bulk reflection; temporary tables and dynamic tables are reflected correctly without schema-wide queries.
|
|
40
|
+
- Fix `SHOW INDEXES IN TABLE` replacing the previous `SHOW TABLES LIKE` approach for single-table index reflection, eliminating SQL `LIKE` wildcard false-positives and case-sensitivity bugs.
|
|
41
|
+
- Add `_always_quote_join` helper that always quotes denormalised identifiers — ensures correct SQL for case-sensitive table and schema names in per-table reflection paths.
|
|
42
|
+
- Fix foreign key `referred_schema` resolution so reflected FKs always keep their actual schema unless the target lives in the connection's default schema. Previously FKs whose target shared the reflected non-default schema were reported with `referred_schema=None`, which caused SQLAlchemy's `_reflect_fk` to autoload from the wrong schema and raise `NoReferencedColumnError` during Alembic autogenerate.
|
|
43
|
+
- Add shared row-parsing helpers (`_parse_pk_rows`, `_parse_uk_rows`, `_parse_fk_rows`) so correctness fixes propagate to both per-table and schema-wide reflection paths.
|
|
44
|
+
- `cache_column_metadata=True` opt-in enables per-table `SHOW … IN TABLE` queries for `get_pk_constraint`, `get_unique_constraints`, `get_foreign_keys`, and `get_indexes` on SQLAlchemy 1.4.
|
|
45
|
+
- On SQLAlchemy 2.x, `get_pk_constraint`, `get_unique_constraints`, `get_foreign_keys`, and `get_indexes` now automatically use per-table `SHOW … IN TABLE` queries without any opt-in flag. Previously these methods always issued `SHOW … IN SCHEMA` even for single-table Inspector calls (e.g. `pandas.read_sql_table()`), causing ~20-second delays on schemas with thousands of tables (SNOW-689531).
|
|
46
|
+
|
|
47
|
+
- v1.9.0 (March 4, 2026)
|
|
48
|
+
- Add support for `DECFLOAT` and `VECTOR` data types
|
|
49
|
+
- Add server_version_info support
|
|
50
|
+
- Add support for `ILIKE` in queries
|
|
51
|
+
- Fix `SYSDATE()` rendering
|
|
52
|
+
- Fix and improve schema reflection (SNOW-593204, SNOW-2331576, SNOW-2852779)
|
|
53
|
+
- Fix crash when reflecting without specifying a schema, caused by `None` arguments in internal schema resolution ([#623](https://github.com/snowflakedb/snowflake-sqlalchemy/issues/623)).
|
|
54
|
+
- Fix crash when `SHOW TABLES` returns empty string table names, causing `IndexError` during reflection ([#296](https://github.com/snowflakedb/snowflake-sqlalchemy/issues/296)).
|
|
55
|
+
- Fix incomplete identity column reflection metadata, now includes all fields required by SQLAlchemy 2.0+ (`always`, `cycle`, `order`, etc.).
|
|
56
|
+
- Introduce shared helper for fully-qualified schema name resolution, replacing inconsistent ad-hoc patterns across reflection methods.
|
|
57
|
+
- Refactor column reflection internals into dedicated helpers to reduce complexity without changing behavior.
|
|
58
|
+
- Add `pytest-xdist` parallel test support via per-worker schema provisioning hooks.
|
|
59
|
+
- Bump `pandas` lower bound in `sa14` test environment from `<2.1` to `>=2.1.1,<2.2` to ensure pre-built wheels are available for Python 3.12
|
|
60
|
+
- Fix SQLAlchemy version parsing (SNOW-3066571)
|
|
61
|
+
- Document support for session parameters (like [QUERY_TAG](https://docs.snowflake.com/en/sql-reference/parameters#query-tag)), references: [#644](https://github.com/snowflakedb/snowflake-sqlalchemy/issues/495)
|
|
62
|
+
- Support timezone in timestamp and datetime types ([#199](https://github.com/snowflakedb/snowflake-sqlalchemy/issues/199))
|
|
63
|
+
|
|
14
64
|
- v1.8.2 (December 9, 2025)
|
|
15
65
|
- Updated supported max python version to 3.13
|
|
16
66
|
- Version 1.8.1 yanked due to max python version supported by `snowflake-connector-python`
|