Skip to content

Commit ec5c2bb

Browse files
feat: Bump SQLAlchemy dependency to 2.0.34 (#220)
Closes #32.
1 parent c6c6305 commit ec5c2bb

File tree

6 files changed

+461
-415
lines changed

6 files changed

+461
-415
lines changed

Diff for: .github/workflows/test.yml

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ jobs:
3838
TARGET_SNOWFLAKE_ROLE: ${{secrets.TARGET_SNOWFLAKE_ROLE}}
3939
strategy:
4040
fail-fast: false
41+
max-parallel: 2
4142
matrix:
4243
python-version:
4344
- "3.12"

Diff for: poetry.lock

+423-377
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ python = ">=3.8"
1818
cryptography = ">=40,<44"
1919
snowflake-sqlalchemy = "~=1.6.1"
2020
snowflake-connector-python = { version = "<4.0.0", extras = ["secure-local-storage"] }
21-
sqlalchemy = "<2"
21+
sqlalchemy = "~=2.0.31"
2222

2323
[tool.poetry.dependencies.singer-sdk]
2424
version = "~=0.40.0a1"

Diff for: target_snowflake/connector.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -469,23 +469,23 @@ def put_batches_to_stage(self, sync_id: str, files: Sequence[str]) -> None:
469469
sync_id: The sync ID for the batch.
470470
files: The files containing records to upload.
471471
"""
472-
with self._connect() as conn:
472+
with self._connect() as conn, conn.begin():
473473
for file_uri in files:
474474
put_statement, kwargs = self._get_put_statement(
475475
sync_id=sync_id,
476476
file_uri=file_uri,
477477
)
478478
# sqlalchemy.text stripped a slash, which caused windows to fail so we used bound parameters instead
479479
# See https://github.com/MeltanoLabs/target-snowflake/issues/87 for more information about this error
480-
conn.execute(put_statement, file_uri=file_uri, **kwargs)
480+
conn.execute(put_statement, {"file_uri": file_uri, **kwargs})
481481

482482
def create_file_format(self, file_format: str) -> None:
483483
"""Create a file format in the schema.
484484
485485
Args:
486486
file_format: The name of the file format.
487487
"""
488-
with self._connect() as conn:
488+
with self._connect() as conn, conn.begin():
489489
file_format_statement, kwargs = self._get_file_format_statement(
490490
file_format=file_format,
491491
)
@@ -510,7 +510,7 @@ def merge_from_stage(
510510
schema: The schema of the data.
511511
key_properties: The primary key properties of the data.
512512
"""
513-
with self._connect() as conn:
513+
with self._connect() as conn, conn.begin():
514514
merge_statement, kwargs = self._get_merge_from_stage_statement(
515515
full_table_name=full_table_name,
516516
schema=schema,
@@ -536,7 +536,7 @@ def copy_from_stage(
536536
sync_id: The sync ID for the batch.
537537
file_format: The name of the file format.
538538
"""
539-
with self._connect() as conn:
539+
with self._connect() as conn, conn.begin():
540540
copy_statement, kwargs = self._get_copy_statement(
541541
full_table_name=full_table_name,
542542
schema=schema,
@@ -552,7 +552,7 @@ def drop_file_format(self, file_format: str) -> None:
552552
Args:
553553
file_format: The name of the file format.
554554
"""
555-
with self._connect() as conn:
555+
with self._connect() as conn, conn.begin():
556556
drop_statement, kwargs = self._get_drop_file_format_statement(
557557
file_format=file_format,
558558
)
@@ -565,7 +565,7 @@ def remove_staged_files(self, sync_id: str) -> None:
565565
Args:
566566
sync_id: The sync ID for the batch.
567567
"""
568-
with self._connect() as conn:
568+
with self._connect() as conn, conn.begin():
569569
remove_statement, kwargs = self._get_stage_files_remove_statement(
570570
sync_id=sync_id,
571571
)

Diff for: tests/core.py

+26-28
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import pytest
66
import snowflake.sqlalchemy.custom_types as sct
7-
import sqlalchemy
7+
import sqlalchemy as sa
88
from singer_sdk.testing.suites import TestSuite
99
from singer_sdk.testing.target_tests import (
1010
TargetArrayData,
@@ -33,7 +33,7 @@ def validate(self) -> None:
3333
f"{self.target.config['database']}.{self.target.config['default_target_schema']}.test_{self.name}".upper()
3434
)
3535
result = connector.connection.execute(
36-
f"select * from {table} order by 1",
36+
sa.text(f"select * from {table} order by 1"),
3737
)
3838
assert result.rowcount == 4
3939
row = result.first()
@@ -45,7 +45,7 @@ def validate(self) -> None:
4545
assert row[1] == '[\n "apple",\n "orange",\n "pear"\n]'
4646
table_schema = connector.get_table(table)
4747
expected_types = {
48-
"id": sqlalchemy.DECIMAL,
48+
"id": sa.DECIMAL,
4949
"fruits": sct.VARIANT,
5050
"_sdc_extracted_at": sct.TIMESTAMP_NTZ,
5151
"_sdc_batched_at": sct.TIMESTAMP_NTZ,
@@ -69,8 +69,8 @@ def validate(self) -> None:
6969
table = f"{self.target.config['database']}.{self.target.config['default_target_schema']}.ForecastingTypeToCategory".upper() # noqa: E501
7070
table_schema = connector.get_table(table)
7171
expected_types = {
72-
"id": sqlalchemy.VARCHAR,
73-
"isdeleted": sqlalchemy.types.BOOLEAN,
72+
"id": sa.VARCHAR,
73+
"isdeleted": sa.types.BOOLEAN,
7474
"createddate": sct.TIMESTAMP_NTZ,
7575
"createdbyid": sct.STRING,
7676
"lastmodifieddate": sct.TIMESTAMP_NTZ,
@@ -79,8 +79,8 @@ def validate(self) -> None:
7979
"forecastingtypeid": sct.STRING,
8080
"forecastingitemcategory": sct.STRING,
8181
"displayposition": sct.NUMBER,
82-
"isadjustable": sqlalchemy.types.BOOLEAN,
83-
"isowneradjustable": sqlalchemy.types.BOOLEAN,
82+
"isadjustable": sa.types.BOOLEAN,
83+
"isowneradjustable": sa.types.BOOLEAN,
8484
"age": sct.NUMBER,
8585
"newcamelcasedattribute": sct.STRING,
8686
"_attribute_startswith_underscore": sct.STRING,
@@ -107,7 +107,7 @@ def validate(self) -> None:
107107
f"{self.target.config['database']}.{self.target.config['default_target_schema']}.test_{self.name}".upper()
108108
)
109109
result = connector.connection.execute(
110-
f"select * from {table} order by 1",
110+
sa.text(f"select * from {table} order by 1"),
111111
)
112112
expected_value = {
113113
1: 100,
@@ -150,7 +150,7 @@ def validate(self) -> None:
150150
f"{self.target.config['database']}.{self.target.config['default_target_schema']}.{self.stream_name}".upper()
151151
)
152152
connector.connection.execute(
153-
f"select * from {table} order by 1",
153+
sa.text(f"select * from {table} order by 1"),
154154
)
155155

156156
table_schema = connector.get_table(table)
@@ -185,7 +185,7 @@ def validate(self) -> None:
185185
f"{self.target.config['database']}.{self.target.config['default_target_schema']}.{table_name}".upper()
186186
)
187187
connector.connection.execute(
188-
f"select * from {table} order by 1",
188+
sa.text(f"select * from {table} order by 1"),
189189
)
190190
# TODO: more assertions
191191

@@ -241,7 +241,7 @@ def validate(self) -> None:
241241
f"{self.target.config['database']}.{self.target.config['default_target_schema']}.{table_name}".upper()
242242
)
243243
result = connector.connection.execute(
244-
f"select * from {table} order by 1",
244+
sa.text(f"select * from {table} order by 1"),
245245
)
246246
assert result.rowcount == 2
247247
row = result.first()
@@ -276,7 +276,7 @@ def validate(self) -> None:
276276
f"{self.target.config['database']}.{self.target.config['default_target_schema']}.test_{self.name}".upper()
277277
)
278278
result = connector.connection.execute(
279-
f"select * from {table} order by 1",
279+
sa.text(f"select * from {table} order by 1"),
280280
)
281281
assert result.rowcount == 6
282282
row = result.first()
@@ -291,7 +291,7 @@ def validate(self) -> None:
291291
"id": sct.NUMBER,
292292
"a1": sct.DOUBLE,
293293
"a2": sct.STRING,
294-
"a3": sqlalchemy.types.BOOLEAN,
294+
"a3": sa.types.BOOLEAN,
295295
"a4": sct.VARIANT,
296296
"a5": sct.VARIANT,
297297
"a6": sct.NUMBER,
@@ -325,7 +325,7 @@ def validate(self) -> None:
325325
connector = self.target.default_sink_class.connector_class(self.target.config)
326326
table = f"{self.target.config['database']}.{self.target.config['default_target_schema']}.{self.name}".upper()
327327
result = connector.connection.execute(
328-
f"select * from {table}",
328+
sa.text(f"select * from {table}"),
329329
)
330330
assert result.rowcount == 2
331331
row = result.first()
@@ -347,7 +347,7 @@ def validate(self) -> None:
347347
connector = self.target.default_sink_class.connector_class(self.target.config)
348348
table = f"{self.target.config['database']}.{self.target.config['default_target_schema']}.{self.name}".upper()
349349
result = connector.connection.execute(
350-
f"select * from {table}",
350+
sa.text(f"select * from {table}"),
351351
)
352352
assert result.rowcount == 1
353353
row = result.first()
@@ -366,7 +366,7 @@ def validate(self) -> None:
366366
connector = self.target.default_sink_class.connector_class(self.target.config)
367367
table = f"{self.target.config['database']}.{self.target.config['default_target_schema']}.{self.name}".upper()
368368
result = connector.connection.execute(
369-
f"select * from {table}",
369+
sa.text(f"select * from {table}"),
370370
)
371371
assert result.rowcount == 1
372372
row = result.first()
@@ -400,7 +400,7 @@ def setup(self) -> None:
400400
connector = self.target.default_sink_class.connector_class(self.target.config)
401401
table = f"{self.target.config['database']}.{self.target.config['default_target_schema']}.{self.name}".upper()
402402
connector.connection.execute(
403-
f"""
403+
sa.text(f"""
404404
CREATE OR REPLACE TABLE {table} (
405405
ID VARCHAR(16777216),
406406
COL_STR VARCHAR(16777216),
@@ -416,14 +416,14 @@ def setup(self) -> None:
416416
_SDC_TABLE_VERSION NUMBER(38,0),
417417
PRIMARY KEY (ID)
418418
)
419-
""",
419+
"""),
420420
)
421421

422422
def validate(self) -> None:
423423
connector = self.target.default_sink_class.connector_class(self.target.config)
424424
table = f"{self.target.config['database']}.{self.target.config['default_target_schema']}.{self.name}".upper()
425425
result = connector.connection.execute(
426-
f"select * from {table}",
426+
sa.text(f"select * from {table}"),
427427
)
428428
assert result.rowcount == 1
429429
row = result.first()
@@ -438,7 +438,7 @@ def setup(self) -> None:
438438
connector = self.target.default_sink_class.connector_class(self.target.config)
439439
table = f"{self.target.config['database']}.{self.target.config['default_target_schema']}.{self.name}".upper()
440440
connector.connection.execute(
441-
f"""
441+
sa.text(f"""
442442
CREATE OR REPLACE TABLE {table} (
443443
ID VARCHAR(16777216),
444444
COL_STR VARCHAR(16777216),
@@ -454,7 +454,7 @@ def setup(self) -> None:
454454
_SDC_TABLE_VERSION NUMBER(38,0),
455455
PRIMARY KEY (ID)
456456
)
457-
""",
457+
"""),
458458
)
459459

460460

@@ -471,7 +471,7 @@ def setup(self) -> None:
471471
connector = self.target.default_sink_class.connector_class(self.target.config)
472472
table = f"{self.target.config['database']}.{self.target.config['default_target_schema']}.\"order\"".upper()
473473
connector.connection.execute(
474-
f"""
474+
sa.text(f"""
475475
CREATE OR REPLACE TABLE {table} (
476476
ID VARCHAR(16777216),
477477
COL_STR VARCHAR(16777216),
@@ -487,7 +487,7 @@ def setup(self) -> None:
487487
_SDC_TABLE_VERSION NUMBER(38,0),
488488
PRIMARY KEY (ID)
489489
)
490-
""",
490+
"""),
491491
)
492492

493493

@@ -505,9 +505,7 @@ def singer_filepath(self) -> Path:
505505
def validate(self) -> None:
506506
connector = self.target.default_sink_class.connector_class(self.target.config)
507507
table = f"{self.target.config['database']}.{self.target.config['default_target_schema']}.\"order\"".upper()
508-
result = connector.connection.execute(
509-
f"select * from {table}",
510-
)
508+
result = connector.connection.execute(sa.text(f"select * from {table}"))
511509
assert result.rowcount == 1
512510
row = result.first()
513511
assert len(row) == 13, f"Row has unexpected length {len(row)}"
@@ -554,13 +552,13 @@ def setup(self) -> None:
554552
table = f"{self.target.config['database']}.{self.target.config['default_target_schema']}.{self.name}".upper()
555553
# Seed the 2 columns from tap schema and an unused third column to assert explicit inserts are working
556554
connector.connection.execute(
557-
f"""
555+
sa.text(f"""
558556
CREATE OR REPLACE TABLE {table} (
559557
COL1 VARCHAR(16777216),
560558
COL3 TIMESTAMP_NTZ(9),
561559
COL2 BOOLEAN
562560
)
563-
""",
561+
"""),
564562
)
565563

566564
@property

Diff for: tests/test_target_snowflake.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from typing import Any
99

1010
import pytest
11+
import sqlalchemy as sa
1112
from singer_sdk.testing import TargetTestRunner, get_target_test_class
1213

1314
from target_snowflake.target import TargetSnowflake
@@ -46,11 +47,11 @@ def resource(self, runner, connection):
4647
https://github.com/meltano/sdk/tree/main/tests/samples
4748
"""
4849
connection.execute(
49-
f"create schema {runner.config['database']}.{runner.config['default_target_schema']}",
50+
sa.text(f"create schema {runner.config['database']}.{runner.config['default_target_schema']}"),
5051
)
5152
yield
5253
connection.execute(
53-
f"drop schema if exists {runner.config['database']}.{runner.config['default_target_schema']}",
54+
sa.text(f"drop schema if exists {runner.config['database']}.{runner.config['default_target_schema']}"),
5455
)
5556

5657

0 commit comments

Comments
 (0)