Skip to content

Commit fec5468

Browse files
committed
Migrate to paramstyle="pyformat", following crate-python 2.2.0
1 parent 8d55b6c commit fec5468

11 files changed

Lines changed: 164 additions & 90 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Changelog
2+
- Migrated to `paramstyle="pyformat"`, following crate-python 2.2.0
23

34
## 2026/05/28 0.42.0
45
- Added support for SQL Alchemy 2.1

src/sqlalchemy_cratedb/dialect.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def process(value):
180180
class CrateDialect(default.DefaultDialect):
181181
name = "crate"
182182
driver = "crate-python"
183-
default_paramstyle = "qmark"
183+
default_paramstyle = "pyformat"
184184
statement_compiler = statement_compiler
185185
ddl_compiler = CrateDDLCompiler
186186
type_compiler = CrateTypeCompiler

tests/array_test.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,29 +69,35 @@ def test_create_with_array(self):
6969
t1.create(self.engine)
7070
fake_cursor.execute.assert_called_with(
7171
("\nCREATE TABLE t (\n\tint_array ARRAY(INT), \n\tstr_array ARRAY(STRING)\n)\n\n"),
72-
(),
72+
sa.util.immutabledict({}),
7373
)
7474

7575
def test_array_insert(self):
7676
trillian = self.User(name="Trillian", friends=["Arthur", "Ford"])
7777
self.session.add(trillian)
7878
self.session.commit()
7979
fake_cursor.execute.assert_called_with(
80-
("INSERT INTO users (name, friends, scores) VALUES (?, ?, ?)"),
81-
("Trillian", ["Arthur", "Ford"], None),
80+
(
81+
"INSERT INTO users (name, friends, scores) "
82+
"VALUES (%(name)s, %(friends)s, %(scores)s)"
83+
),
84+
{"friends": ["Arthur", "Ford"], "name": "Trillian", "scores": None},
8285
)
8386

8487
def test_any(self):
8588
s = self.session.query(self.User.name).filter(self.User.friends.any("arthur"))
8689
self.assertSQL(
87-
"SELECT users.name AS users_name FROM users WHERE ? = ANY (users.friends)", s
90+
"SELECT users.name AS users_name FROM users WHERE %(friends_1)s = ANY (users.friends)",
91+
s,
8892
)
8993

9094
def test_any_with_operator(self):
9195
s = self.session.query(self.User.name).filter(
9296
self.User.scores.any(6, operator=operators.lt)
9397
)
94-
self.assertSQL("SELECT users.name AS users_name FROM users WHERE ? < ANY (users.scores)", s)
98+
self.assertSQL(
99+
"SELECT users.name AS users_name FROM users WHERE %(scores_1)s < ANY (users.scores)", s
100+
)
95101

96102
def test_multidimensional_arrays(self):
97103
t1 = sa.Table(

tests/bulk_test.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -153,17 +153,20 @@ def test_bulk_save_modern(self):
153153
self.session.commit()
154154
(stmt, bulk_args), _ = fake_cursor.execute.call_args
155155

156-
expected_stmt = "INSERT INTO characters (name, age) VALUES (?, ?), (?, ?), (?, ?)"
156+
expected_stmt = (
157+
"INSERT INTO characters (name, age) "
158+
"VALUES (%(name__0)s, %(age__0)s), (%(name__1)s, %(age__1)s), (%(name__2)s, %(age__2)s)"
159+
)
157160
self.assertEqual(expected_stmt, stmt)
158161

159-
expected_bulk_args = (
160-
"Arthur",
161-
35,
162-
"Banshee",
163-
26,
164-
"Callisto",
165-
37,
166-
)
162+
expected_bulk_args = {
163+
"age__0": 35,
164+
"name__0": "Arthur",
165+
"age__1": 26,
166+
"name__1": "Banshee",
167+
"age__2": 37,
168+
"name__2": "Callisto",
169+
}
167170
self.assertSequenceEqual(expected_bulk_args, bulk_args)
168171

169172
@skipIf(sys.version_info < (3, 8), "SQLAlchemy/pandas is not supported on Python <3.8")

tests/compiler_test.py

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def test_select_with_ilike_no_escape(self):
9797
dedent("""
9898
SELECT mytable.name, mytable.data
9999
FROM mytable
100-
WHERE mytable.name ILIKE ?
100+
WHERE mytable.name ILIKE %(name_1)s
101101
""").strip(),
102102
) # noqa: W291
103103
else:
@@ -106,7 +106,7 @@ def test_select_with_ilike_no_escape(self):
106106
dedent("""
107107
SELECT mytable.name, mytable.data
108108
FROM mytable
109-
WHERE lower(mytable.name) LIKE lower(?)
109+
WHERE lower(mytable.name) LIKE lower(%(name_1)s)
110110
""").strip(),
111111
) # noqa: W291
112112

@@ -122,7 +122,7 @@ def test_select_with_not_ilike_no_escape(self):
122122
dedent("""
123123
SELECT mytable.name, mytable.data
124124
FROM mytable
125-
WHERE lower(mytable.name) NOT LIKE lower(?)
125+
WHERE lower(mytable.name) NOT LIKE lower(%(name_1)s)
126126
""").strip(),
127127
) # noqa: W291
128128
else:
@@ -131,7 +131,7 @@ def test_select_with_not_ilike_no_escape(self):
131131
dedent("""
132132
SELECT mytable.name, mytable.data
133133
FROM mytable
134-
WHERE mytable.name NOT ILIKE ?
134+
WHERE mytable.name NOT ILIKE %(name_1)s
135135
""").strip(),
136136
) # noqa: W291
137137

@@ -167,11 +167,13 @@ def test_select_with_offset(self):
167167
statement = str(selectable.compile(bind=self.crate_engine))
168168
if SA_VERSION >= SA_1_4:
169169
self.assertEqual(
170-
statement, "SELECT mytable.name, mytable.data \nFROM mytable\n LIMIT ALL OFFSET ?"
170+
statement,
171+
"SELECT mytable.name, mytable.data \nFROM mytable\n LIMIT ALL OFFSET %(param_1)s",
171172
)
172173
else:
173174
self.assertEqual(
174-
statement, "SELECT mytable.name, mytable.data \nFROM mytable \n LIMIT ALL OFFSET ?"
175+
statement,
176+
"SELECT mytable.name, mytable.data \nFROM mytable \n LIMIT ALL OFFSET %(param_1)s",
175177
)
176178

177179
def test_select_with_limit(self):
@@ -180,7 +182,9 @@ def test_select_with_limit(self):
180182
"""
181183
selectable = self.mytable.select().limit(42)
182184
statement = str(selectable.compile(bind=self.crate_engine))
183-
self.assertEqual(statement, "SELECT mytable.name, mytable.data \nFROM mytable \n LIMIT ?")
185+
self.assertEqual(
186+
statement, "SELECT mytable.name, mytable.data \nFROM mytable \n LIMIT %(param_1)s"
187+
)
184188

185189
def test_select_with_offset_and_limit(self):
186190
"""
@@ -189,7 +193,9 @@ def test_select_with_offset_and_limit(self):
189193
selectable = self.mytable.select().offset(5).limit(42)
190194
statement = str(selectable.compile(bind=self.crate_engine))
191195
self.assertEqual(
192-
statement, "SELECT mytable.name, mytable.data \nFROM mytable \n LIMIT ? OFFSET ?"
196+
statement,
197+
"SELECT mytable.name, mytable.data \n"
198+
"FROM mytable \n LIMIT %(param_1)s OFFSET %(param_2)s",
193199
)
194200

195201
def test_insert_multivalues(self):
@@ -220,7 +226,10 @@ def test_insert_multivalues(self):
220226
records = [{"name": f"foo_{i}"} for i in range(3)]
221227
insertable = self.mytable.insert().values(records)
222228
statement = str(insertable.compile(bind=self.crate_engine))
223-
self.assertEqual(statement, "INSERT INTO mytable (name) VALUES (?), (?), (?)")
229+
self.assertEqual(
230+
statement,
231+
"INSERT INTO mytable (name) VALUES (%(name_m0)s), (%(name_m1)s), (%(name_m2)s)",
232+
)
224233

225234
@skipIf(
226235
SA_VERSION < SA_2_0,
@@ -263,7 +272,7 @@ def test_insert_manyvalues(self):
263272
records = [{"name": f"foo_{i}"} for i in range(record_count)]
264273
insertable = self.mytable.insert()
265274
statement = str(insertable.compile(bind=self.crate_engine))
266-
self.assertEqual(statement, "INSERT INTO mytable (name, data) VALUES (?, ?)")
275+
self.assertEqual(statement, "INSERT INTO mytable (name, data) VALUES (%(name)s, %(data)s)")
267276

268277
with mock.patch(
269278
"crate.client.http.Client.sql", autospec=True, return_value={"cols": []}
@@ -278,12 +287,18 @@ def test_insert_manyvalues(self):
278287
client_mock.mock_calls,
279288
[
280289
mock.call(
281-
mock.ANY, "INSERT INTO mytable (name) VALUES (?), (?)", ("foo_0", "foo_1"), None
290+
mock.ANY,
291+
"INSERT INTO mytable (name) VALUES ($1), ($2)",
292+
["foo_0", "foo_1"],
293+
None,
282294
),
283295
mock.call(
284-
mock.ANY, "INSERT INTO mytable (name) VALUES (?), (?)", ("foo_2", "foo_3"), None
296+
mock.ANY,
297+
"INSERT INTO mytable (name) VALUES ($1), ($2)",
298+
["foo_2", "foo_3"],
299+
None,
285300
),
286-
mock.call(mock.ANY, "INSERT INTO mytable (name) VALUES (?)", ("foo_4",), None),
301+
mock.call(mock.ANY, "INSERT INTO mytable (name) VALUES ($1)", ["foo_4"], None),
287302
],
288303
)
289304

tests/create_table_test.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class User(self.Base):
7575
"\n\tdouble_col DOUBLE, "
7676
"\n\tPRIMARY KEY (string_col)\n)\n\n"
7777
),
78-
(),
78+
sa.util.immutabledict({}),
7979
)
8080

8181
def test_column_obj(self):
@@ -90,7 +90,7 @@ class DummyTable(self.Base):
9090
"\nCREATE TABLE dummy (\n\tpk STRING NOT NULL, \n\tobj_col OBJECT, "
9191
"\n\tPRIMARY KEY (pk)\n)\n\n"
9292
),
93-
(),
93+
sa.util.immutabledict({}),
9494
)
9595

9696
def test_table_clustered_by(self):
@@ -109,7 +109,7 @@ class DummyTable(self.Base):
109109
"PRIMARY KEY (pk)\n"
110110
") CLUSTERED BY (p)\n\n"
111111
),
112-
(),
112+
sa.util.immutabledict({}),
113113
)
114114

115115
def test_column_computed(self):
@@ -127,7 +127,7 @@ class DummyTable(self.Base):
127127
"PRIMARY KEY (ts)\n"
128128
")\n\n"
129129
),
130-
(),
130+
sa.util.immutabledict({}),
131131
)
132132

133133
def test_column_computed_virtual(self):
@@ -155,7 +155,7 @@ class DummyTable(self.Base):
155155
"PRIMARY KEY (pk)\n"
156156
") PARTITIONED BY (p)\n\n"
157157
),
158-
(),
158+
sa.util.immutabledict({}),
159159
)
160160

161161
def test_table_number_of_shards_and_replicas(self):
@@ -172,7 +172,7 @@ class DummyTable(self.Base):
172172
"PRIMARY KEY (pk)\n"
173173
") CLUSTERED INTO 3 SHARDS WITH (number_of_replicas = 2)\n\n"
174174
),
175-
(),
175+
sa.util.immutabledict({}),
176176
)
177177

178178
def test_table_clustered_by_and_number_of_shards(self):
@@ -191,7 +191,7 @@ class DummyTable(self.Base):
191191
"PRIMARY KEY (pk, p)\n"
192192
") CLUSTERED BY (p) INTO 3 SHARDS\n\n"
193193
),
194-
(),
194+
sa.util.immutabledict({}),
195195
)
196196

197197
def test_table_translog_durability(self):
@@ -210,7 +210,7 @@ class DummyTable(self.Base):
210210
"PRIMARY KEY (pk)\n"
211211
""") WITH ("translog.durability" = 'async')\n\n"""
212212
),
213-
(),
213+
sa.util.immutabledict({}),
214214
)
215215

216216
def test_column_object_array(self):
@@ -227,7 +227,7 @@ class DummyTable(self.Base):
227227
"tags ARRAY(OBJECT), \n\t"
228228
"PRIMARY KEY (pk)\n)\n\n"
229229
),
230-
(),
230+
sa.util.immutabledict({}),
231231
)
232232

233233
def test_column_nullable(self):
@@ -246,7 +246,7 @@ class DummyTable(self.Base):
246246
"b INT NOT NULL, \n\t"
247247
"PRIMARY KEY (pk)\n)\n\n"
248248
),
249-
(),
249+
sa.util.immutabledict({}),
250250
)
251251

252252
def test_column_pk_nullable(self):
@@ -273,7 +273,7 @@ class DummyTable(self.Base):
273273
"b INT, \n\t"
274274
"PRIMARY KEY (pk)\n)\n\n"
275275
),
276-
(),
276+
sa.util.immutabledict({}),
277277
)
278278

279279
@pytest.mark.skip("CompileError not raised")
@@ -305,7 +305,7 @@ class DummyTable(self.Base):
305305
"c STRING, \n\t"
306306
"PRIMARY KEY (pk)\n)\n\n"
307307
),
308-
(),
308+
sa.util.immutabledict({}),
309309
)
310310

311311
def test_non_text_column_without_columnstore(self):
@@ -331,7 +331,7 @@ class DummyTable(self.Base):
331331
"a TIMESTAMP WITHOUT TIME ZONE DEFAULT now(), \n\t"
332332
"PRIMARY KEY (pk)\n)\n\n"
333333
),
334-
(),
334+
sa.util.immutabledict({}),
335335
)
336336

337337
def test_column_server_default_string(self):
@@ -348,7 +348,7 @@ class DummyTable(self.Base):
348348
"a STRING DEFAULT 'Zaphod', \n\t"
349349
"PRIMARY KEY (pk)\n)\n\n"
350350
),
351-
(),
351+
sa.util.immutabledict({}),
352352
)
353353

354354
def test_column_server_default_func(self):
@@ -365,7 +365,7 @@ class DummyTable(self.Base):
365365
"a TIMESTAMP WITHOUT TIME ZONE DEFAULT now(), \n\t"
366366
"PRIMARY KEY (pk)\n)\n\n"
367367
),
368-
(),
368+
sa.util.immutabledict({}),
369369
)
370370

371371
def test_column_server_default_text_constant(self):
@@ -382,7 +382,7 @@ class DummyTable(self.Base):
382382
"answer INT DEFAULT 42, \n\t"
383383
"PRIMARY KEY (pk)\n)\n\n"
384384
),
385-
(),
385+
sa.util.immutabledict({}),
386386
)
387387

388388
@skipIf(SA_VERSION < SA_2_0, "sa.Double was introduced in SA 2.0")

0 commit comments

Comments
 (0)