crate 0.29.0__py2.py3-none-any.whl → 0.30.1__py2.py3-none-any.whl

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.
Files changed (43) hide show
  1. crate/client/__init__.py +1 -1
  2. crate/client/_pep440.py +501 -0
  3. crate/client/connection.py +3 -3
  4. crate/client/sqlalchemy/__init__.py +24 -0
  5. crate/client/sqlalchemy/compat/__init__.py +0 -0
  6. crate/client/sqlalchemy/compat/api13.py +156 -0
  7. crate/client/sqlalchemy/compat/core10.py +264 -0
  8. crate/client/sqlalchemy/compat/core14.py +359 -0
  9. crate/client/sqlalchemy/compat/core20.py +447 -0
  10. crate/client/sqlalchemy/compiler.py +1 -481
  11. crate/client/sqlalchemy/dialect.py +32 -17
  12. crate/client/sqlalchemy/sa_version.py +4 -3
  13. crate/client/sqlalchemy/tests/__init__.py +17 -6
  14. crate/client/sqlalchemy/tests/array_test.py +6 -3
  15. crate/client/sqlalchemy/tests/bulk_test.py +7 -4
  16. crate/client/sqlalchemy/tests/compiler_test.py +10 -9
  17. crate/client/sqlalchemy/tests/connection_test.py +25 -11
  18. crate/client/sqlalchemy/tests/create_table_test.py +19 -16
  19. crate/client/sqlalchemy/tests/datetime_test.py +6 -3
  20. crate/client/sqlalchemy/tests/dialect_test.py +42 -13
  21. crate/client/sqlalchemy/tests/dict_test.py +17 -13
  22. crate/client/sqlalchemy/tests/function_test.py +6 -3
  23. crate/client/sqlalchemy/tests/insert_from_select_test.py +9 -6
  24. crate/client/sqlalchemy/tests/match_test.py +6 -3
  25. crate/client/sqlalchemy/tests/update_test.py +6 -3
  26. crate/client/sqlalchemy/tests/warnings_test.py +33 -0
  27. crate/client/test_connection.py +25 -0
  28. crate/client/tests.py +98 -119
  29. crate/testing/layer.py +1 -1
  30. crate/testing/settings.py +51 -0
  31. crate/testing/test_layer.py +188 -2
  32. crate/testing/tests.py +2 -38
  33. crate/testing/util.py +20 -0
  34. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/METADATA +10 -8
  35. crate-0.30.1.dist-info/RECORD +53 -0
  36. crate-0.29.0.dist-info/RECORD +0 -44
  37. /crate-0.29.0-py3.9-nspkg.pth → /crate-0.30.1-py3.9-nspkg.pth +0 -0
  38. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/LICENSE +0 -0
  39. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/NOTICE +0 -0
  40. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/WHEEL +0 -0
  41. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/entry_points.txt +0 -0
  42. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/namespace_packages.txt +0 -0
  43. {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/top_level.txt +0 -0
@@ -24,7 +24,7 @@ from collections import defaultdict
24
24
 
25
25
  import sqlalchemy as sa
26
26
  from sqlalchemy.dialects.postgresql.base import PGCompiler
27
- from sqlalchemy.sql import compiler, crud, selectable
27
+ from sqlalchemy.sql import compiler
28
28
  from .types import MutableDict, _Craty, Geopoint, Geoshape
29
29
  from .sa_version import SA_VERSION, SA_1_4
30
30
 
@@ -208,8 +208,6 @@ class CrateTypeCompiler(compiler.GenericTypeCompiler):
208
208
 
209
209
  class CrateCompiler(compiler.SQLCompiler):
210
210
 
211
- prefetch = []
212
-
213
211
  def visit_getitem_binary(self, binary, operator, **kw):
214
212
  return "{0}['{1}']".format(
215
213
  self.process(binary.left, **kw),
@@ -223,486 +221,8 @@ class CrateCompiler(compiler.SQLCompiler):
223
221
  self.process(element.right, **kw)
224
222
  )
225
223
 
226
- def returning_clause(self, stmt, returning_cols):
227
- columns = [
228
- self._label_select_column(None, c, True, False, {})
229
- for c in sa.sql.expression._select_iterables(returning_cols)
230
- ]
231
- return "RETURNING " + ", ".join(columns)
232
-
233
- def visit_update(self, update_stmt, **kw):
234
- """
235
- used to compile <sql.expression.Update> expressions
236
- Parts are taken from the SQLCompiler base class.
237
- """
238
-
239
- if SA_VERSION >= SA_1_4:
240
- return self.visit_update_14(update_stmt, **kw)
241
-
242
- if not update_stmt.parameters and \
243
- not hasattr(update_stmt, '_crate_specific'):
244
- return super(CrateCompiler, self).visit_update(update_stmt, **kw)
245
-
246
- self.isupdate = True
247
-
248
- extra_froms = update_stmt._extra_froms
249
-
250
- text = 'UPDATE '
251
-
252
- if update_stmt._prefixes:
253
- text += self._generate_prefixes(update_stmt,
254
- update_stmt._prefixes, **kw)
255
-
256
- table_text = self.update_tables_clause(update_stmt, update_stmt.table,
257
- extra_froms, **kw)
258
-
259
- dialect_hints = None
260
- if update_stmt._hints:
261
- dialect_hints, table_text = self._setup_crud_hints(
262
- update_stmt, table_text
263
- )
264
-
265
- # CrateDB patch.
266
- crud_params = self._get_crud_params(update_stmt, **kw)
267
-
268
- text += table_text
269
-
270
- text += ' SET '
271
-
272
- # CrateDB patch begin.
273
- include_table = extra_froms and \
274
- self.render_table_with_column_in_update_from
275
-
276
- set_clauses = []
277
-
278
- for k, v in crud_params:
279
- clause = k._compiler_dispatch(self,
280
- include_table=include_table) + \
281
- ' = ' + v
282
- set_clauses.append(clause)
283
-
284
- for k, v in update_stmt.parameters.items():
285
- if isinstance(k, str) and '[' in k:
286
- bindparam = sa.sql.bindparam(k, v)
287
- set_clauses.append(k + ' = ' + self.process(bindparam))
288
-
289
- text += ', '.join(set_clauses)
290
- # CrateDB patch end.
291
-
292
- if self.returning or update_stmt._returning:
293
- if not self.returning:
294
- self.returning = update_stmt._returning
295
- if self.returning_precedes_values:
296
- text += " " + self.returning_clause(
297
- update_stmt, self.returning)
298
-
299
- if extra_froms:
300
- extra_from_text = self.update_from_clause(
301
- update_stmt,
302
- update_stmt.table,
303
- extra_froms,
304
- dialect_hints,
305
- **kw)
306
- if extra_from_text:
307
- text += " " + extra_from_text
308
-
309
- if update_stmt._whereclause is not None:
310
- t = self.process(update_stmt._whereclause)
311
- if t:
312
- text += " WHERE " + t
313
-
314
- limit_clause = self.update_limit_clause(update_stmt)
315
- if limit_clause:
316
- text += " " + limit_clause
317
-
318
- if self.returning and not self.returning_precedes_values:
319
- text += " " + self.returning_clause(
320
- update_stmt, self.returning)
321
-
322
- return text
323
-
324
224
  def limit_clause(self, select, **kw):
325
225
  """
326
226
  Generate OFFSET / LIMIT clause, PostgreSQL-compatible.
327
227
  """
328
228
  return PGCompiler.limit_clause(self, select, **kw)
329
-
330
- def _get_crud_params(compiler, stmt, **kw):
331
- """ extract values from crud parameters
332
- taken from SQLAlchemy's crud module (since 1.0.x) and
333
- adapted for Crate dialect"""
334
-
335
- compiler.postfetch = []
336
- compiler.insert_prefetch = []
337
- compiler.update_prefetch = []
338
- compiler.returning = []
339
-
340
- # no parameters in the statement, no parameters in the
341
- # compiled params - return binds for all columns
342
- if compiler.column_keys is None and stmt.parameters is None:
343
- return [(c, crud._create_bind_param(compiler, c, None,
344
- required=True))
345
- for c in stmt.table.columns]
346
-
347
- if stmt._has_multi_parameters:
348
- stmt_parameters = stmt.parameters[0]
349
- else:
350
- stmt_parameters = stmt.parameters
351
-
352
- # getters - these are normally just column.key,
353
- # but in the case of mysql multi-table update, the rules for
354
- # .key must conditionally take tablename into account
355
- _column_as_key, _getattr_col_key, _col_bind_name = \
356
- crud._key_getters_for_crud_column(compiler, stmt)
357
-
358
- # if we have statement parameters - set defaults in the
359
- # compiled params
360
- if compiler.column_keys is None:
361
- parameters = {}
362
- else:
363
- parameters = dict((_column_as_key(key), crud.REQUIRED)
364
- for key in compiler.column_keys
365
- if not stmt_parameters or
366
- key not in stmt_parameters)
367
-
368
- # create a list of column assignment clauses as tuples
369
- values = []
370
-
371
- if stmt_parameters is not None:
372
- crud._get_stmt_parameters_params(
373
- compiler,
374
- parameters, stmt_parameters, _column_as_key, values, kw)
375
-
376
- check_columns = {}
377
-
378
- crud._scan_cols(compiler, stmt, parameters,
379
- _getattr_col_key, _column_as_key,
380
- _col_bind_name, check_columns, values, kw)
381
-
382
- if stmt._has_multi_parameters:
383
- values = crud._extend_values_for_multiparams(compiler, stmt,
384
- values, kw)
385
-
386
- return values
387
-
388
- def visit_update_14(self, update_stmt, **kw):
389
-
390
- compile_state = update_stmt._compile_state_factory(
391
- update_stmt, self, **kw
392
- )
393
- update_stmt = compile_state.statement
394
-
395
- toplevel = not self.stack
396
- if toplevel:
397
- self.isupdate = True
398
- if not self.compile_state:
399
- self.compile_state = compile_state
400
-
401
- extra_froms = compile_state._extra_froms
402
- is_multitable = bool(extra_froms)
403
-
404
- if is_multitable:
405
- # main table might be a JOIN
406
- main_froms = set(selectable._from_objects(update_stmt.table))
407
- render_extra_froms = [
408
- f for f in extra_froms if f not in main_froms
409
- ]
410
- correlate_froms = main_froms.union(extra_froms)
411
- else:
412
- render_extra_froms = []
413
- correlate_froms = {update_stmt.table}
414
-
415
- self.stack.append(
416
- {
417
- "correlate_froms": correlate_froms,
418
- "asfrom_froms": correlate_froms,
419
- "selectable": update_stmt,
420
- }
421
- )
422
-
423
- text = "UPDATE "
424
-
425
- if update_stmt._prefixes:
426
- text += self._generate_prefixes(
427
- update_stmt, update_stmt._prefixes, **kw
428
- )
429
-
430
- table_text = self.update_tables_clause(
431
- update_stmt, update_stmt.table, render_extra_froms, **kw
432
- )
433
-
434
- # CrateDB patch.
435
- crud_params = _get_crud_params_14(
436
- self, update_stmt, compile_state, **kw
437
- )
438
-
439
- if update_stmt._hints:
440
- dialect_hints, table_text = self._setup_crud_hints(
441
- update_stmt, table_text
442
- )
443
- else:
444
- dialect_hints = None
445
-
446
- if update_stmt._independent_ctes:
447
- for cte in update_stmt._independent_ctes:
448
- cte._compiler_dispatch(self, **kw)
449
-
450
- text += table_text
451
-
452
- text += " SET "
453
-
454
- # CrateDB patch begin.
455
- include_table = extra_froms and \
456
- self.render_table_with_column_in_update_from
457
-
458
- set_clauses = []
459
-
460
- for c, expr, value in crud_params:
461
- key = c._compiler_dispatch(self, include_table=include_table)
462
- clause = key + ' = ' + value
463
- set_clauses.append(clause)
464
-
465
- for k, v in compile_state._dict_parameters.items():
466
- if isinstance(k, str) and '[' in k:
467
- bindparam = sa.sql.bindparam(k, v)
468
- clause = k + ' = ' + self.process(bindparam)
469
- set_clauses.append(clause)
470
-
471
- text += ', '.join(set_clauses)
472
- # CrateDB patch end.
473
-
474
- if self.returning or update_stmt._returning:
475
- if self.returning_precedes_values:
476
- text += " " + self.returning_clause(
477
- update_stmt, self.returning or update_stmt._returning
478
- )
479
-
480
- if extra_froms:
481
- extra_from_text = self.update_from_clause(
482
- update_stmt,
483
- update_stmt.table,
484
- render_extra_froms,
485
- dialect_hints,
486
- **kw
487
- )
488
- if extra_from_text:
489
- text += " " + extra_from_text
490
-
491
- if update_stmt._where_criteria:
492
- t = self._generate_delimited_and_list(
493
- update_stmt._where_criteria, **kw
494
- )
495
- if t:
496
- text += " WHERE " + t
497
-
498
- limit_clause = self.update_limit_clause(update_stmt)
499
- if limit_clause:
500
- text += " " + limit_clause
501
-
502
- if (
503
- self.returning or update_stmt._returning
504
- ) and not self.returning_precedes_values:
505
- text += " " + self.returning_clause(
506
- update_stmt, self.returning or update_stmt._returning
507
- )
508
-
509
- if self.ctes:
510
- nesting_level = len(self.stack) if not toplevel else None
511
- text = self._render_cte_clause(nesting_level=nesting_level) + text
512
-
513
- self.stack.pop(-1)
514
-
515
- return text
516
-
517
-
518
- def _get_crud_params_14(compiler, stmt, compile_state, **kw):
519
- """create a set of tuples representing column/string pairs for use
520
- in an INSERT or UPDATE statement.
521
-
522
- Also generates the Compiled object's postfetch, prefetch, and
523
- returning column collections, used for default handling and ultimately
524
- populating the CursorResult's prefetch_cols() and postfetch_cols()
525
- collections.
526
-
527
- """
528
- from sqlalchemy.sql.crud import _key_getters_for_crud_column
529
- from sqlalchemy.sql.crud import _create_bind_param
530
- from sqlalchemy.sql.crud import REQUIRED
531
- from sqlalchemy.sql.crud import _get_stmt_parameter_tuples_params
532
- from sqlalchemy.sql.crud import _get_update_multitable_params
533
- from sqlalchemy.sql.crud import _scan_insert_from_select_cols
534
- from sqlalchemy.sql.crud import _scan_cols
535
- from sqlalchemy import exc # noqa: F401
536
- from sqlalchemy.sql.crud import _extend_values_for_multiparams
537
-
538
- compiler.postfetch = []
539
- compiler.insert_prefetch = []
540
- compiler.update_prefetch = []
541
- compiler.returning = []
542
-
543
- # getters - these are normally just column.key,
544
- # but in the case of mysql multi-table update, the rules for
545
- # .key must conditionally take tablename into account
546
- (
547
- _column_as_key,
548
- _getattr_col_key,
549
- _col_bind_name,
550
- ) = getters = _key_getters_for_crud_column(compiler, stmt, compile_state)
551
-
552
- compiler._key_getters_for_crud_column = getters
553
-
554
- # no parameters in the statement, no parameters in the
555
- # compiled params - return binds for all columns
556
- if compiler.column_keys is None and compile_state._no_parameters:
557
- return [
558
- (
559
- c,
560
- compiler.preparer.format_column(c),
561
- _create_bind_param(compiler, c, None, required=True),
562
- )
563
- for c in stmt.table.columns
564
- ]
565
-
566
- if compile_state._has_multi_parameters:
567
- spd = compile_state._multi_parameters[0]
568
- stmt_parameter_tuples = list(spd.items())
569
- elif compile_state._ordered_values:
570
- spd = compile_state._dict_parameters
571
- stmt_parameter_tuples = compile_state._ordered_values
572
- elif compile_state._dict_parameters:
573
- spd = compile_state._dict_parameters
574
- stmt_parameter_tuples = list(spd.items())
575
- else:
576
- stmt_parameter_tuples = spd = None
577
-
578
- # if we have statement parameters - set defaults in the
579
- # compiled params
580
- if compiler.column_keys is None:
581
- parameters = {}
582
- elif stmt_parameter_tuples:
583
- parameters = dict(
584
- (_column_as_key(key), REQUIRED)
585
- for key in compiler.column_keys
586
- if key not in spd
587
- )
588
- else:
589
- parameters = dict(
590
- (_column_as_key(key), REQUIRED) for key in compiler.column_keys
591
- )
592
-
593
- # create a list of column assignment clauses as tuples
594
- values = []
595
-
596
- if stmt_parameter_tuples is not None:
597
- _get_stmt_parameter_tuples_params(
598
- compiler,
599
- compile_state,
600
- parameters,
601
- stmt_parameter_tuples,
602
- _column_as_key,
603
- values,
604
- kw,
605
- )
606
-
607
- check_columns = {}
608
-
609
- # special logic that only occurs for multi-table UPDATE
610
- # statements
611
- if compile_state.isupdate and compile_state.is_multitable:
612
- _get_update_multitable_params(
613
- compiler,
614
- stmt,
615
- compile_state,
616
- stmt_parameter_tuples,
617
- check_columns,
618
- _col_bind_name,
619
- _getattr_col_key,
620
- values,
621
- kw,
622
- )
623
-
624
- if compile_state.isinsert and stmt._select_names:
625
- _scan_insert_from_select_cols(
626
- compiler,
627
- stmt,
628
- compile_state,
629
- parameters,
630
- _getattr_col_key,
631
- _column_as_key,
632
- _col_bind_name,
633
- check_columns,
634
- values,
635
- kw,
636
- )
637
- else:
638
- _scan_cols(
639
- compiler,
640
- stmt,
641
- compile_state,
642
- parameters,
643
- _getattr_col_key,
644
- _column_as_key,
645
- _col_bind_name,
646
- check_columns,
647
- values,
648
- kw,
649
- )
650
-
651
- # CrateDB patch.
652
- #
653
- # This sanity check performed by SQLAlchemy currently needs to be
654
- # deactivated in order to satisfy the rewriting logic of the CrateDB
655
- # dialect in `rewrite_update` and `visit_update`.
656
- #
657
- # It can be quickly reproduced by activating this section and running the
658
- # test cases::
659
- #
660
- # ./bin/test -vvvv -t dict_test
661
- #
662
- # That croaks like::
663
- #
664
- # sqlalchemy.exc.CompileError: Unconsumed column names: characters_name, data['nested']
665
- #
666
- # TODO: Investigate why this is actually happening and eventually mitigate
667
- # the root cause.
668
- """
669
- if parameters and stmt_parameter_tuples:
670
- check = (
671
- set(parameters)
672
- .intersection(_column_as_key(k) for k, v in stmt_parameter_tuples)
673
- .difference(check_columns)
674
- )
675
- if check:
676
- raise exc.CompileError(
677
- "Unconsumed column names: %s"
678
- % (", ".join("%s" % (c,) for c in check))
679
- )
680
- """
681
-
682
- if compile_state._has_multi_parameters:
683
- values = _extend_values_for_multiparams(
684
- compiler,
685
- stmt,
686
- compile_state,
687
- values,
688
- _column_as_key,
689
- kw,
690
- )
691
- elif (
692
- not values
693
- and compiler.for_executemany # noqa: W503
694
- and compiler.dialect.supports_default_metavalue # noqa: W503
695
- ):
696
- # convert an "INSERT DEFAULT VALUES"
697
- # into INSERT (firstcol) VALUES (DEFAULT) which can be turned
698
- # into an in-place multi values. This supports
699
- # insert_executemany_returning mode :)
700
- values = [
701
- (
702
- stmt.table.columns[0],
703
- compiler.preparer.format_column(stmt.table.columns[0]),
704
- "DEFAULT",
705
- )
706
- ]
707
-
708
- return values
@@ -28,11 +28,11 @@ from sqlalchemy.sql import functions
28
28
  from sqlalchemy.util import asbool, to_list
29
29
 
30
30
  from .compiler import (
31
- CrateCompiler,
32
31
  CrateTypeCompiler,
33
32
  CrateDDLCompiler
34
33
  )
35
34
  from crate.client.exceptions import TimezoneUnawareException
35
+ from .sa_version import SA_VERSION, SA_1_4, SA_2_0
36
36
  from .types import Object, ObjectArray
37
37
 
38
38
  TYPES_MAP = {
@@ -155,10 +155,21 @@ colspecs = {
155
155
  }
156
156
 
157
157
 
158
+ if SA_VERSION >= SA_2_0:
159
+ from .compat.core20 import CrateCompilerSA20
160
+ statement_compiler = CrateCompilerSA20
161
+ elif SA_VERSION >= SA_1_4:
162
+ from .compat.core14 import CrateCompilerSA14
163
+ statement_compiler = CrateCompilerSA14
164
+ else:
165
+ from .compat.core10 import CrateCompilerSA10
166
+ statement_compiler = CrateCompilerSA10
167
+
168
+
158
169
  class CrateDialect(default.DefaultDialect):
159
170
  name = 'crate'
160
171
  driver = 'crate-python'
161
- statement_compiler = CrateCompiler
172
+ statement_compiler = statement_compiler
162
173
  ddl_compiler = CrateDDLCompiler
163
174
  type_compiler = CrateTypeCompiler
164
175
  supports_native_boolean = True
@@ -208,19 +219,23 @@ class CrateDialect(default.DefaultDialect):
208
219
  return tuple(connection.connection.lowest_server_version.version)
209
220
 
210
221
  @classmethod
211
- def dbapi(cls):
222
+ def import_dbapi(cls):
212
223
  from crate import client
213
224
  return client
214
225
 
215
- def has_schema(self, connection, schema):
216
- return schema in self.get_schema_names(connection)
226
+ @classmethod
227
+ def dbapi(cls):
228
+ return cls.import_dbapi()
229
+
230
+ def has_schema(self, connection, schema, **kw):
231
+ return schema in self.get_schema_names(connection, **kw)
217
232
 
218
- def has_table(self, connection, table_name, schema=None):
219
- return table_name in self.get_table_names(connection, schema=schema)
233
+ def has_table(self, connection, table_name, schema=None, **kw):
234
+ return table_name in self.get_table_names(connection, schema=schema, **kw)
220
235
 
221
236
  @reflection.cache
222
237
  def get_schema_names(self, connection, **kw):
223
- cursor = connection.execute(
238
+ cursor = connection.exec_driver_sql(
224
239
  "select schema_name "
225
240
  "from information_schema.schemata "
226
241
  "order by schema_name asc"
@@ -229,21 +244,21 @@ class CrateDialect(default.DefaultDialect):
229
244
 
230
245
  @reflection.cache
231
246
  def get_table_names(self, connection, schema=None, **kw):
232
- cursor = connection.execute(
247
+ cursor = connection.exec_driver_sql(
233
248
  "SELECT table_name FROM information_schema.tables "
234
249
  "WHERE {0} = ? "
235
250
  "AND table_type = 'BASE TABLE' "
236
251
  "ORDER BY table_name ASC, {0} ASC".format(self.schema_column),
237
- [schema or self.default_schema_name]
252
+ (schema or self.default_schema_name, )
238
253
  )
239
254
  return [row[0] for row in cursor.fetchall()]
240
255
 
241
256
  @reflection.cache
242
257
  def get_view_names(self, connection, schema=None, **kw):
243
- cursor = connection.execute(
258
+ cursor = connection.exec_driver_sql(
244
259
  "SELECT table_name FROM information_schema.views "
245
260
  "ORDER BY table_name ASC, {0} ASC".format(self.schema_column),
246
- [schema or self.default_schema_name]
261
+ (schema or self.default_schema_name, )
247
262
  )
248
263
  return [row[0] for row in cursor.fetchall()]
249
264
 
@@ -254,11 +269,11 @@ class CrateDialect(default.DefaultDialect):
254
269
  "WHERE table_name = ? AND {0} = ? " \
255
270
  "AND column_name !~ ?" \
256
271
  .format(self.schema_column)
257
- cursor = connection.execute(
272
+ cursor = connection.exec_driver_sql(
258
273
  query,
259
- [table_name,
274
+ (table_name,
260
275
  schema or self.default_schema_name,
261
- r"(.*)\[\'(.*)\'\]"] # regex to filter subscript
276
+ r"(.*)\[\'(.*)\'\]") # regex to filter subscript
262
277
  )
263
278
  return [self._create_column_info(row) for row in cursor.fetchall()]
264
279
 
@@ -293,9 +308,9 @@ class CrateDialect(default.DefaultDialect):
293
308
  rows = result.fetchone()
294
309
  return set(rows[0] if rows else [])
295
310
 
296
- pk_result = engine.execute(
311
+ pk_result = engine.exec_driver_sql(
297
312
  query,
298
- [table_name, schema or self.default_schema_name]
313
+ (table_name, schema or self.default_schema_name)
299
314
  )
300
315
  pks = result_fun(pk_result)
301
316
  return {'constrained_columns': pks,
@@ -20,8 +20,9 @@
20
20
  # software solely pursuant to the terms of the relevant commercial agreement.
21
21
 
22
22
  import sqlalchemy as sa
23
- from distutils.version import StrictVersion as V
23
+ from crate.client._pep440 import Version
24
24
 
25
- SA_VERSION = V(sa.__version__)
25
+ SA_VERSION = Version(sa.__version__)
26
26
 
27
- SA_1_4 = V('1.4.0b1')
27
+ SA_1_4 = Version('1.4.0b1')
28
+ SA_2_0 = Version('2.0.0')
@@ -1,5 +1,14 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ from ..compat.api13 import monkeypatch_amend_select_sa14, monkeypatch_add_connectionfairy_driver_connection
4
+ from ..sa_version import SA_1_4, SA_VERSION
5
+
6
+ # `sql.select()` of SQLAlchemy 1.3 uses old calling semantics,
7
+ # but the test cases already need the modern ones.
8
+ if SA_VERSION < SA_1_4:
9
+ monkeypatch_amend_select_sa14()
10
+ monkeypatch_add_connectionfairy_driver_connection()
11
+
3
12
  from unittest import TestSuite, makeSuite
4
13
  from .connection_test import SqlAlchemyConnectionTest
5
14
  from .dict_test import SqlAlchemyDictTypeTest
@@ -9,10 +18,11 @@ from .update_test import SqlAlchemyUpdateTest
9
18
  from .match_test import SqlAlchemyMatchTest
10
19
  from .bulk_test import SqlAlchemyBulkTest
11
20
  from .insert_from_select_test import SqlAlchemyInsertFromSelectTest
12
- from .create_table_test import CreateTableTest
21
+ from .create_table_test import SqlAlchemyCreateTableTest
13
22
  from .array_test import SqlAlchemyArrayTypeTest
14
- from .dialect_test import DialectTest
15
- from .function_test import FunctionTest
23
+ from .dialect_test import SqlAlchemyDialectTest
24
+ from .function_test import SqlAlchemyFunctionTest
25
+ from .warnings_test import SqlAlchemyWarningsTest
16
26
 
17
27
 
18
28
  def test_suite():
@@ -23,11 +33,12 @@ def test_suite():
23
33
  tests.addTest(makeSuite(SqlAlchemyCompilerTest))
24
34
  tests.addTest(makeSuite(SqlAlchemyUpdateTest))
25
35
  tests.addTest(makeSuite(SqlAlchemyMatchTest))
26
- tests.addTest(makeSuite(CreateTableTest))
36
+ tests.addTest(makeSuite(SqlAlchemyCreateTableTest))
27
37
  tests.addTest(makeSuite(SqlAlchemyBulkTest))
28
38
  tests.addTest(makeSuite(SqlAlchemyInsertFromSelectTest))
29
39
  tests.addTest(makeSuite(SqlAlchemyInsertFromSelectTest))
30
- tests.addTest(makeSuite(DialectTest))
31
- tests.addTest(makeSuite(FunctionTest))
40
+ tests.addTest(makeSuite(SqlAlchemyDialectTest))
41
+ tests.addTest(makeSuite(SqlAlchemyFunctionTest))
32
42
  tests.addTest(makeSuite(SqlAlchemyArrayTypeTest))
43
+ tests.addTest(makeSuite(SqlAlchemyWarningsTest))
33
44
  return tests