Skip to content

Commit

Permalink
Added flag to allow customer to test new behavior of div_is_floordiv …
Browse files Browse the repository at this point in the history
…that will be introduce, using new flag force_div_floordiv allow to test the new division behavior.

Update sa14:scripts to ignore feature_v20 from execution
  • Loading branch information
sfc-gh-jmartinezramirez committed Nov 22, 2024
1 parent c871c24 commit 5578bd9
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 17 deletions.
5 changes: 4 additions & 1 deletion DESCRIPTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ Source code is also available at:

- (Unreleased)
- Add support for partition by to copy into <location>
- Fix flag `div_is_floordiv` to `False` in `SnowflakeDialect` to avoid division wrong CAST when trying to do a integer division when using `/`
- Added `force_div_is_floordiv` flag to override `div_is_floordiv` new default value `False` in `SnowflakeDialect`.
- With the flag in `False`, the `/` division operator will be treated as a float division and `//` as a floor division.
- This flag is added to maintain backward compatibility with the previous behavior of Snowflake Dialect division.
- This flag will be removed in the future and Snowflake Dialect will use `div_is_floor_div` as `False`.

- v1.7.0(November 21, 2024)

Expand Down
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ extra-dependencies = ["SQLAlchemy>=1.4.19,<2.0.0"]
features = ["development", "pandas"]
python = "3.8"

[tool.hatch.envs.sa14.scripts]
test-dialect = "pytest --ignore_v20_test -ra -vvv --tb=short --cov snowflake.sqlalchemy --cov-append --junitxml ./junit.xml --ignore=tests/sqlalchemy_test_suite tests/"
test-dialect-compatibility = "pytest --ignore_v20_test -ra -vvv --tb=short --cov snowflake.sqlalchemy --cov-append --junitxml ./junit.xml tests/sqlalchemy_test_suite"
test-dialect-aws = "pytest --ignore_v20_test -m \"aws\" -ra -vvv --tb=short --cov snowflake.sqlalchemy --cov-append --junitxml ./junit.xml --ignore=tests/sqlalchemy_test_suite tests/"

[tool.hatch.envs.default.env-vars]
COVERAGE_FILE = "coverage.xml"
SQLACHEMY_WARN_20 = "1"
Expand Down Expand Up @@ -131,4 +136,5 @@ markers = [
"requires_external_volume: tests that needs a external volume to be executed",
"external: tests that could but should only run on our external CI",
"feature_max_lob_size: tests that could but should only run on our external CI",
"feature_v20: tests that could but should only run on SqlAlchemy v20",
]
13 changes: 13 additions & 0 deletions src/snowflake/sqlalchemy/snowdialect.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,19 @@ class SnowflakeDialect(default.DefaultDialect):

supports_identity_columns = True

def __init__(
self,
force_div_is_floordiv: bool = True,
**kwargs,
):
default.DefaultDialect.__init__(self, **kwargs)
self.force_div_is_floordiv = force_div_is_floordiv
self.div_is_floordiv = force_div_is_floordiv

def initialize(self, connection):
super().initialize(connection)
self.div_is_floordiv = self.force_div_is_floordiv

@classmethod
def dbapi(cls):
return cls.import_dbapi()
Expand Down
20 changes: 20 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,26 @@
TEST_SCHEMA = f"sqlalchemy_tests_{str(uuid.uuid4()).replace('-', '_')}"


def pytest_addoption(parser):
parser.addoption(
"--ignore_v20_test",
action="store_true",
default=False,
help="skip sqlalchemy 2.0 exclusive tests",
)


def pytest_collection_modifyitems(config, items):
if config.getoption("--ignore_v20_test"):
# --ignore_v20_test given in cli: skip sqlalchemy 2.0 tests
skip_feature_v2 = pytest.mark.skip(
reason="need remove --ignore_v20_test option to run"
)
for item in items:
if "feature_v20" in item.keywords:
item.add_marker(skip_feature_v2)


@pytest.fixture(scope="session")
def on_travis():
return os.getenv("TRAVIS", "").lower() == "true"
Expand Down
82 changes: 66 additions & 16 deletions tests/test_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
# Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved.
#

import pytest
from sqlalchemy import Integer, String, and_, func, select
from sqlalchemy.schema import DropColumnComment, DropTableComment
from sqlalchemy.sql import column, quoted_name, table
from sqlalchemy.testing.assertions import AssertsCompiledSQL

from snowflake.sqlalchemy import snowdialect
from src.snowflake.sqlalchemy.snowdialect import SnowflakeDialect

table1 = table(
"table1", column("id", Integer), column("name", String), column("value", Integer)
Expand Down Expand Up @@ -122,31 +124,79 @@ def test_outer_lateral_join():
)


def test_division_operator():
col1 = column("col1")
col2 = column("col2")
def test_division_operator_with_force_div_is_floordiv_false():
col1 = column("col1", Integer)
col2 = column("col2", Integer)
stmt = col1 / col2
assert str(stmt.compile(dialect=snowdialect.dialect())) == "col1 / col2"
assert (
str(stmt.compile(dialect=SnowflakeDialect(force_div_is_floordiv=False)))
== "col1 / col2"
)


def test_division_operator_with_denominator_expr_force_div_is_floordiv_false():
col1 = column("col1", Integer)
col2 = column("col2", Integer)
stmt = col1 / func.sqrt(col2)
assert (
str(stmt.compile(dialect=SnowflakeDialect(force_div_is_floordiv=False)))
== "col1 / sqrt(col2)"
)


def test_division_operator_with_force_div_is_floordiv_default_true():
col1 = column("col1", Integer)
col2 = column("col2", Integer)
stmt = col1 / col2
assert (
str(stmt.compile(dialect=SnowflakeDialect())) == "col1 / CAST(col2 AS NUMERIC)"
)


def test_division_operator_with_denominator_expr():
col1 = column("col1")
col2 = column("col2")
def test_division_operator_with_denominator_expr_force_div_is_floordiv_default_true():
col1 = column("col1", Integer)
col2 = column("col2", Integer)
stmt = col1 / func.sqrt(col2)
assert str(stmt.compile(dialect=snowdialect.dialect())) == "col1 / sqrt(col2)"
assert (
str(stmt.compile(dialect=SnowflakeDialect()))
== "col1 / CAST(sqrt(col2) AS NUMERIC)"
)


def test_floor_division_operator():
col1 = column("col1")
col2 = column("col2")
@pytest.mark.feature_v20
def test_floor_division_operator_force_div_is_floordiv_false():
col1 = column("col1", Integer)
col2 = column("col2", Integer)
stmt = col1 // col2
assert str(stmt.compile(dialect=snowdialect.dialect())) == "FLOOR(col1 / col2)"
assert (
str(stmt.compile(dialect=SnowflakeDialect(force_div_is_floordiv=False)))
== "FLOOR(col1 / col2)"
)


def test_floor_division_operator_with_denominator_expr():
col1 = column("col1")
col2 = column("col2")
@pytest.mark.feature_v20
def test_floor_division_operator_with_denominator_expr_force_div_is_floordiv_false():
col1 = column("col1", Integer)
col2 = column("col2", Integer)
stmt = col1 // func.sqrt(col2)
assert (
str(stmt.compile(dialect=snowdialect.dialect())) == "FLOOR(col1 / sqrt(col2))"
str(stmt.compile(dialect=SnowflakeDialect(force_div_is_floordiv=False)))
== "FLOOR(col1 / sqrt(col2))"
)


@pytest.mark.feature_v20
def test_floor_division_operator_force_div_is_floordiv_default_true():
col1 = column("col1", Integer)
col2 = column("col2", Integer)
stmt = col1 // col2
assert str(stmt.compile(dialect=SnowflakeDialect())) == "col1 / col2"


@pytest.mark.feature_v20
def test_floor_division_operator_with_denominator_expr_force_div_is_floordiv_default_true():
col1 = column("col1", Integer)
col2 = column("col2", Integer)
stmt = col1 // func.sqrt(col2)
res = stmt.compile(dialect=SnowflakeDialect())
assert str(res) == "FLOOR(col1 / sqrt(col2))"

0 comments on commit 5578bd9

Please sign in to comment.