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

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -25,7 +25,10 @@ from unittest.mock import MagicMock
25
25
 
26
26
  import sqlalchemy as sa
27
27
  from sqlalchemy.orm import Session
28
- from sqlalchemy.ext.declarative import declarative_base
28
+ try:
29
+ from sqlalchemy.orm import declarative_base
30
+ except ImportError:
31
+ from sqlalchemy.ext.declarative import declarative_base
29
32
 
30
33
  from crate.client.sqlalchemy.types import Craty
31
34
  from crate.client.sqlalchemy.predicates import match
@@ -52,14 +55,14 @@ class SqlAlchemyMatchTest(TestCase):
52
55
  self.assertEqual(expected_str, str(actual_expr).replace('\n', ''))
53
56
 
54
57
  def set_up_character_and_session(self):
55
- Base = declarative_base(bind=self.engine)
58
+ Base = declarative_base()
56
59
 
57
60
  class Character(Base):
58
61
  __tablename__ = 'characters'
59
62
  name = sa.Column(sa.String, primary_key=True)
60
63
  info = sa.Column(Craty)
61
64
 
62
- session = Session()
65
+ session = Session(bind=self.engine)
63
66
  return session, Character
64
67
 
65
68
  def test_simple_match(self):
@@ -27,7 +27,10 @@ from crate.client.sqlalchemy.types import Object
27
27
 
28
28
  import sqlalchemy as sa
29
29
  from sqlalchemy.orm import Session
30
- from sqlalchemy.ext.declarative import declarative_base
30
+ try:
31
+ from sqlalchemy.orm import declarative_base
32
+ except ImportError:
33
+ from sqlalchemy.ext.declarative import declarative_base
31
34
 
32
35
  from crate.client.cursor import Cursor
33
36
 
@@ -42,7 +45,7 @@ class SqlAlchemyUpdateTest(TestCase):
42
45
 
43
46
  def setUp(self):
44
47
  self.engine = sa.create_engine('crate://')
45
- self.base = declarative_base(bind=self.engine)
48
+ self.base = declarative_base()
46
49
 
47
50
  class Character(self.base):
48
51
  __tablename__ = 'characters'
@@ -53,7 +56,7 @@ class SqlAlchemyUpdateTest(TestCase):
53
56
  ts = sa.Column(sa.DateTime, onupdate=datetime.utcnow)
54
57
 
55
58
  self.character = Character
56
- self.session = Session()
59
+ self.session = Session(bind=self.engine)
57
60
 
58
61
  @patch('crate.client.connection.Cursor', FakeCursor)
59
62
  def test_onupdate_is_triggered(self):
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8; -*-
2
+ import sys
3
+ import warnings
4
+ from unittest import TestCase, skipIf
5
+
6
+ from crate.client.sqlalchemy import SA_1_4, SA_VERSION
7
+ from crate.testing.util import ExtraAssertions
8
+
9
+
10
+ class SqlAlchemyWarningsTest(TestCase, ExtraAssertions):
11
+
12
+ @skipIf(SA_VERSION >= SA_1_4, "There is no deprecation warning for "
13
+ "SQLAlchemy 1.3 on higher versions")
14
+ def test_sa13_deprecation_warning(self):
15
+ """
16
+ Verify that a `DeprecationWarning` is issued when running SQLAlchemy 1.3.
17
+
18
+ https://docs.python.org/3/library/warnings.html#testing-warnings
19
+ """
20
+ with warnings.catch_warnings(record=True) as w:
21
+
22
+ # Cause all warnings to always be triggered.
23
+ warnings.simplefilter("always")
24
+
25
+ # Trigger a warning by importing the SQLAlchemy dialect module.
26
+ # Because it already has been loaded, unload it beforehand.
27
+ del sys.modules["crate.client.sqlalchemy"]
28
+ import crate.client.sqlalchemy # noqa: F401
29
+
30
+ # Verify details of the SA13 EOL/deprecation warning.
31
+ self.assertEqual(len(w), 1)
32
+ self.assertIsSubclass(w[-1].category, DeprecationWarning)
33
+ self.assertIn("SQLAlchemy 1.3 is effectively EOL.", str(w[-1].message))
@@ -1,12 +1,37 @@
1
1
  import datetime
2
2
 
3
+ from .connection import Connection
3
4
  from .http import Client
4
5
  from crate.client import connect
5
6
  from unittest import TestCase
6
7
 
8
+ from ..testing.settings import crate_host
9
+
7
10
 
8
11
  class ConnectionTest(TestCase):
9
12
 
13
+ def test_connection_mock(self):
14
+ """
15
+ For testing purposes it is often useful to replace the client used for
16
+ communication with the CrateDB server with a stub or mock.
17
+
18
+ This can be done by passing an object of the Client class when calling the
19
+ ``connect`` method.
20
+ """
21
+
22
+ class MyConnectionClient:
23
+ active_servers = ["localhost:4200"]
24
+
25
+ def __init__(self):
26
+ pass
27
+
28
+ def server_infos(self, server):
29
+ return ("localhost:4200", "my server", "0.42.0")
30
+
31
+ connection = connect([crate_host], client=MyConnectionClient())
32
+ self.assertIsInstance(connection, Connection)
33
+ self.assertEqual(connection.client.server_infos("foo"), ('localhost:4200', 'my server', '0.42.0'))
34
+
10
35
  def test_lowest_server_version(self):
11
36
  infos = [(None, None, '0.42.3'),
12
37
  (None, None, '0.41.8'),
crate/client/tests.py CHANGED
@@ -27,7 +27,6 @@ import socket
27
27
  import unittest
28
28
  import doctest
29
29
  from pprint import pprint
30
- from datetime import datetime
31
30
  from http.server import HTTPServer, BaseHTTPRequestHandler
32
31
  import ssl
33
32
  import time
@@ -37,12 +36,11 @@ import logging
37
36
  import stopit
38
37
 
39
38
  from crate.testing.layer import CrateLayer
40
- from crate.testing.tests import crate_path, docs_path
39
+ from crate.testing.settings import \
40
+ crate_host, crate_path, crate_port, \
41
+ crate_transport_port, docs_path, localhost
41
42
  from crate.client import connect
42
- from crate.client.sqlalchemy.dialect import CrateDialect
43
- from crate.client.test_util import ClientMocked
44
43
 
45
- from . import http
46
44
  from .test_cursor import CursorTest
47
45
  from .test_connection import ConnectionTest
48
46
  from .test_http import (
@@ -56,7 +54,6 @@ from .test_http import (
56
54
  TestDefaultSchemaHeader,
57
55
  )
58
56
  from .sqlalchemy.tests import test_suite as sqlalchemy_test_suite
59
- from .sqlalchemy.types import ObjectArray
60
57
 
61
58
  log = logging.getLogger('crate.testing.layer')
62
59
  ch = logging.StreamHandler()
@@ -70,10 +67,6 @@ def cprint(s):
70
67
  print(s)
71
68
 
72
69
 
73
- def setUpMocked(test):
74
- test.globs['connection_client_mocked'] = ClientMocked()
75
-
76
-
77
70
  settings = {
78
71
  'udc.enabled': 'false',
79
72
  'lang.js.enabled': 'true',
@@ -85,11 +78,6 @@ settings = {
85
78
  'auth.host_based.config.99.user': 'me',
86
79
  'auth.host_based.config.99.method': 'password',
87
80
  }
88
- crate_port = 44209
89
- crate_transport_port = 44309
90
- local = '127.0.0.1'
91
- crate_host = "{host}:{port}".format(host=local, port=crate_port)
92
- crate_uri = "http://%s" % crate_host
93
81
  crate_layer = None
94
82
 
95
83
 
@@ -113,24 +101,16 @@ def ensure_cratedb_layer():
113
101
  crate_layer = CrateLayer('crate',
114
102
  crate_home=crate_path(),
115
103
  port=crate_port,
116
- host=local,
104
+ host=localhost,
117
105
  transport_port=crate_transport_port,
118
106
  settings=settings)
119
107
  return crate_layer
120
108
 
121
109
 
122
- def refresh(table):
123
- with connect(crate_host) as conn:
124
- cursor = conn.cursor()
125
- cursor.execute("refresh table %s" % table)
126
-
127
-
128
- def setUpWithCrateLayer(test):
129
- test.globs['HttpClient'] = http.Client
110
+ def setUpCrateLayerBaseline(test):
130
111
  test.globs['crate_host'] = crate_host
131
112
  test.globs['pprint'] = pprint
132
113
  test.globs['print'] = cprint
133
- test.globs["refresh"] = refresh
134
114
 
135
115
  with connect(crate_host) as conn:
136
116
  cursor = conn.cursor()
@@ -151,62 +131,69 @@ def setUpWithCrateLayer(test):
151
131
  # create blob table
152
132
  cursor.execute("create blob table myfiles clustered into 1 shards " +
153
133
  "with (number_of_replicas=0)")
134
+
154
135
  # create users
155
136
  cursor.execute("CREATE USER me WITH (password = 'my_secret_pw')")
156
137
  cursor.execute("CREATE USER trusted_me")
157
138
 
139
+ cursor.close()
158
140
 
159
- def setUpCrateLayerAndSqlAlchemy(test):
160
- setUpWithCrateLayer(test)
161
- import sqlalchemy as sa
162
- from sqlalchemy.ext.declarative import declarative_base
163
- from sqlalchemy.orm import sessionmaker
164
141
 
165
- with connect(crate_host) as conn:
166
- cursor = conn.cursor()
167
- cursor.execute("""create table characters (
168
- id string primary key,
169
- name string,
170
- quote string,
171
- details object,
172
- more_details array(object),
173
- INDEX name_ft using fulltext(name) with (analyzer = 'english'),
174
- INDEX quote_ft using fulltext(quote) with (analyzer = 'english')
175
- )""")
176
- cursor.execute("CREATE VIEW characters_view AS SELECT * FROM characters")
142
+ def setUpCrateLayerSqlAlchemy(test):
143
+ """
144
+ Setup tables and views needed for SQLAlchemy tests.
145
+ """
146
+ setUpCrateLayerBaseline(test)
177
147
 
178
- with connect(crate_host) as conn:
179
- cursor = conn.cursor()
180
- cursor.execute("""create table cities (
181
- name string primary key,
182
- coordinate geo_point,
183
- area geo_shape
184
- ) """)
185
-
186
- engine = sa.create_engine('crate://{0}'.format(crate_host))
187
- Base = declarative_base()
188
-
189
- class Location(Base):
190
- __tablename__ = 'locations'
191
- name = sa.Column(sa.String, primary_key=True)
192
- kind = sa.Column(sa.String)
193
- date = sa.Column(sa.Date, default=lambda: datetime.utcnow().date())
194
- datetime_tz = sa.Column(sa.DateTime, default=datetime.utcnow)
195
- datetime_notz = sa.Column(sa.DateTime, default=datetime.utcnow)
196
- nullable_datetime = sa.Column(sa.DateTime)
197
- nullable_date = sa.Column(sa.Date)
198
- flag = sa.Column(sa.Boolean)
199
- details = sa.Column(ObjectArray)
200
-
201
- Session = sessionmaker(engine)
202
- session = Session()
203
- test.globs['sa'] = sa
204
- test.globs['engine'] = engine
205
- test.globs['Location'] = Location
206
- test.globs['Base'] = Base
207
- test.globs['session'] = session
208
- test.globs['Session'] = Session
209
- test.globs['CrateDialect'] = CrateDialect
148
+ ddl_statements = [
149
+ """
150
+ CREATE TABLE characters (
151
+ id STRING PRIMARY KEY,
152
+ name STRING,
153
+ quote STRING,
154
+ details OBJECT,
155
+ more_details ARRAY(OBJECT),
156
+ INDEX name_ft USING fulltext(name) WITH (analyzer = 'english'),
157
+ INDEX quote_ft USING fulltext(quote) WITH (analyzer = 'english')
158
+ )""",
159
+ """
160
+ CREATE VIEW characters_view
161
+ AS SELECT * FROM characters
162
+ """,
163
+ """
164
+ CREATE TABLE cities (
165
+ name STRING PRIMARY KEY,
166
+ coordinate GEO_POINT,
167
+ area GEO_SHAPE
168
+ )"""
169
+ ]
170
+ _execute_statements(ddl_statements, on_error="raise")
171
+
172
+
173
+ def tearDownDropEntitiesBaseline(test):
174
+ """
175
+ Drop all tables, views, and users created by `setUpWithCrateLayer*`.
176
+ """
177
+ ddl_statements = [
178
+ "DROP TABLE locations",
179
+ "DROP BLOB TABLE myfiles",
180
+ "DROP USER me",
181
+ "DROP USER trusted_me",
182
+ ]
183
+ _execute_statements(ddl_statements)
184
+
185
+
186
+ def tearDownDropEntitiesSqlAlchemy(test):
187
+ """
188
+ Drop all tables, views, and users created by `setUpWithCrateLayer*`.
189
+ """
190
+ tearDownDropEntitiesBaseline(test)
191
+ ddl_statements = [
192
+ "DROP TABLE characters",
193
+ "DROP VIEW characters_view",
194
+ "DROP TABLE cities",
195
+ ]
196
+ _execute_statements(ddl_statements)
210
197
 
211
198
 
212
199
  class HttpsTestServerLayer:
@@ -298,7 +285,6 @@ class HttpsTestServerLayer:
298
285
 
299
286
 
300
287
  def setUpWithHttps(test):
301
- test.globs['HttpClient'] = http.Client
302
288
  test.globs['crate_host'] = "https://{0}:{1}".format(
303
289
  HttpsTestServerLayer.HOST, HttpsTestServerLayer.PORT
304
290
  )
@@ -319,43 +305,33 @@ def setUpWithHttps(test):
319
305
  )
320
306
 
321
307
 
322
- def _try_execute(cursor, stmt):
308
+ def _execute_statements(statements, on_error="ignore"):
309
+ with connect(crate_host) as conn:
310
+ cursor = conn.cursor()
311
+ for stmt in statements:
312
+ _execute_statement(cursor, stmt, on_error=on_error)
313
+ cursor.close()
314
+
315
+
316
+ def _execute_statement(cursor, stmt, on_error="ignore"):
323
317
  try:
324
318
  cursor.execute(stmt)
325
- except Exception:
319
+ except Exception: # pragma: no cover
326
320
  # FIXME: Why does this croak on statements like ``DROP TABLE cities``?
327
321
  # Note: When needing to debug the test environment, you may want to
328
322
  # enable this logger statement.
329
323
  # log.exception("Executing SQL statement failed")
330
- pass
331
-
332
-
333
- def tearDownWithCrateLayer(test):
334
- # clear testing data
335
- with connect(crate_host) as conn:
336
- for stmt in ["DROP TABLE locations",
337
- "DROP BLOB TABLE myfiles",
338
- "DROP TABLE characters",
339
- "DROP VIEW characters_view",
340
- "DROP TABLE cities",
341
- "DROP USER me",
342
- "DROP USER trusted_me",
343
- ]:
344
- _try_execute(conn.cursor(), stmt)
324
+ if on_error == "ignore":
325
+ pass
326
+ elif on_error == "raise":
327
+ raise
345
328
 
346
329
 
347
330
  def test_suite():
348
331
  suite = unittest.TestSuite()
349
332
  flags = (doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS)
350
333
 
351
- s = doctest.DocFileSuite(
352
- 'doctests/cursor.txt',
353
- 'doctests/connection.txt',
354
- setUp=setUpMocked,
355
- optionflags=flags,
356
- encoding='utf-8'
357
- )
358
- suite.addTest(s)
334
+ # Unit tests.
359
335
  suite.addTest(unittest.makeSuite(CursorTest))
360
336
  suite.addTest(unittest.makeSuite(HttpClientTest))
361
337
  suite.addTest(unittest.makeSuite(KeepAliveClientTest))
@@ -371,34 +347,32 @@ def test_suite():
371
347
  suite.addTest(doctest.DocTestSuite('crate.client.http'))
372
348
 
373
349
  s = doctest.DocFileSuite(
374
- 'doctests/https.txt',
375
- setUp=setUpWithHttps,
350
+ 'docs/by-example/connection.rst',
351
+ 'docs/by-example/cursor.rst',
352
+ module_relative=False,
376
353
  optionflags=flags,
377
354
  encoding='utf-8'
378
355
  )
379
- s.layer = HttpsTestServerLayer()
380
356
  suite.addTest(s)
381
357
 
382
358
  s = doctest.DocFileSuite(
383
- 'sqlalchemy/doctests/itests.txt',
384
- 'sqlalchemy/doctests/dialect.txt',
385
- 'sqlalchemy/doctests/reflection.txt',
386
- setUp=setUpCrateLayerAndSqlAlchemy,
387
- tearDown=tearDownWithCrateLayer,
359
+ 'docs/by-example/https.rst',
360
+ module_relative=False,
361
+ setUp=setUpWithHttps,
388
362
  optionflags=flags,
389
363
  encoding='utf-8'
390
364
  )
391
- s.layer = ensure_cratedb_layer()
365
+ s.layer = HttpsTestServerLayer()
392
366
  suite.addTest(s)
393
367
 
368
+ # Integration tests.
394
369
  s = doctest.DocFileSuite(
395
- 'doctests/http.txt',
396
- 'doctests/blob.txt',
397
- 'doctests/client.txt',
398
- 'doctests/mocking.txt',
399
- 'doctests/blob.txt',
400
- setUp=setUpWithCrateLayer,
401
- tearDown=tearDownWithCrateLayer,
370
+ 'docs/by-example/http.rst',
371
+ 'docs/by-example/client.rst',
372
+ 'docs/by-example/blob.rst',
373
+ module_relative=False,
374
+ setUp=setUpCrateLayerBaseline,
375
+ tearDown=tearDownDropEntitiesBaseline,
402
376
  optionflags=flags,
403
377
  encoding='utf-8'
404
378
  )
@@ -406,9 +380,14 @@ def test_suite():
406
380
  suite.addTest(s)
407
381
 
408
382
  s = doctest.DocFileSuite(
409
- 'doctests/sqlalchemy.txt',
410
- setUp=setUpCrateLayerAndSqlAlchemy,
411
- tearDown=tearDownWithCrateLayer,
383
+ 'docs/by-example/sqlalchemy/getting-started.rst',
384
+ 'docs/by-example/sqlalchemy/crud.rst',
385
+ 'docs/by-example/sqlalchemy/working-with-types.rst',
386
+ 'docs/by-example/sqlalchemy/advanced-querying.rst',
387
+ 'docs/by-example/sqlalchemy/inspection-reflection.rst',
388
+ module_relative=False,
389
+ setUp=setUpCrateLayerSqlAlchemy,
390
+ tearDown=tearDownDropEntitiesSqlAlchemy,
412
391
  optionflags=flags,
413
392
  encoding='utf-8'
414
393
  )
crate/testing/layer.py CHANGED
@@ -321,12 +321,12 @@ class CrateLayer(object):
321
321
  sys.stderr.write('\nCrate instance ready.\n')
322
322
 
323
323
  def stop(self):
324
+ self.conn_pool.clear()
324
325
  if self.process:
325
326
  self.process.terminate()
326
327
  self.process.communicate(timeout=10)
327
328
  self.process.stdout.close()
328
329
  self.process = None
329
- self.conn_pool.clear()
330
330
  self.monitor.stop()
331
331
  self._clean()
332
332
 
@@ -0,0 +1,51 @@
1
+ # vi: set encoding=utf-8
2
+ # -*- coding: utf-8; -*-
3
+ #
4
+ # Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
5
+ # license agreements. See the NOTICE file distributed with this work for
6
+ # additional information regarding copyright ownership. Crate licenses
7
+ # this file to you under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License. You may
9
+ # obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16
+ # License for the specific language governing permissions and limitations
17
+ # under the License.
18
+ #
19
+ # However, if you have executed another commercial license agreement
20
+ # with Crate these terms will supersede the license and you may use the
21
+ # software solely pursuant to the terms of the relevant commercial agreement.
22
+ from __future__ import absolute_import
23
+
24
+ import os
25
+
26
+
27
+ def docs_path(*parts):
28
+ return os.path.abspath(
29
+ os.path.join(
30
+ os.path.dirname(os.path.dirname(__file__)), *parts
31
+ )
32
+ )
33
+
34
+
35
+ def project_root(*parts):
36
+ return os.path.abspath(
37
+ os.path.join(docs_path("..", ".."), *parts)
38
+ )
39
+
40
+
41
+ def crate_path(*parts):
42
+ return os.path.abspath(
43
+ project_root("parts", "crate", *parts)
44
+ )
45
+
46
+
47
+ crate_port = 44209
48
+ crate_transport_port = 44309
49
+ localhost = '127.0.0.1'
50
+ crate_host = "{host}:{port}".format(host=localhost, port=crate_port)
51
+ crate_uri = "http://%s" % crate_host