Skip to content

Commit c462575

Browse files
committed
api: extend connect with fetch_schema param
Added support of the fetch_schema parameter, which allows to ignore schema changes on the server. Closes #219
1 parent 1154b3d commit c462575

File tree

4 files changed

+103
-14
lines changed

4 files changed

+103
-14
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
### Added
1010
- Support custom packer and unpacker factories (#191).
1111

12+
- Support of the fetch_schema parameter for connection (#219).
13+
1214
### Changed
1315

1416
### Fixed

tarantool/connection.py

+57-11
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,8 @@ def __init__(self, host, port,
363363
ssl_ca_file=DEFAULT_SSL_CA_FILE,
364364
ssl_ciphers=DEFAULT_SSL_CIPHERS,
365365
packer_factory=default_packer_factory,
366-
unpacker_factory=default_unpacker_factory):
366+
unpacker_factory=default_unpacker_factory,
367+
fetch_schema=True):
367368
"""
368369
:param host: Server hostname or IP address. Use ``None`` for
369370
Unix sockets.
@@ -503,6 +504,17 @@ def __init__(self, host, port,
503504
callable[[:obj:`~tarantool.Connection`], :obj:`~msgpack.Unpacker`],
504505
optional
505506
507+
:param bool fetch_schema: If ``False``, allows to ignore schema
508+
changes on the server, schema updates are not automatically
509+
loaded. As a result, the methods become unavailable:
510+
:meth:`~tarantool.Connection.replace`,
511+
:meth:`~tarantool.Connection.insert`,
512+
:meth:`~tarantool.Connection.delete`,
513+
:meth:`~tarantool.Connection.upsert`,
514+
:meth:`~tarantool.Connection.update`,
515+
:meth:`~tarantool.Connection.select`.
516+
:type fetch_schema: :obj:`bool`, optional
517+
506518
:raise: :exc:`~tarantool.error.ConfigurationError`,
507519
:meth:`~tarantool.Connection.connect` exceptions
508520
@@ -533,8 +545,10 @@ def __init__(self, host, port,
533545
self.socket_timeout = socket_timeout
534546
self.reconnect_delay = reconnect_delay
535547
self.reconnect_max_attempts = reconnect_max_attempts
536-
self.schema = Schema(self)
537-
self.schema_version = 1
548+
self.fetch_schema = fetch_schema
549+
if self.fetch_schema:
550+
self.schema = Schema(self)
551+
self.schema_version = 1
538552
self._socket = None
539553
self.connected = False
540554
self.error = True
@@ -745,7 +759,8 @@ def connect(self):
745759
if self.transport == SSL_TRANSPORT:
746760
self.wrap_socket_ssl()
747761
self.handshake()
748-
self.load_schema()
762+
if self.fetch_schema:
763+
self.load_schema()
749764
self._check_features()
750765
except SslError as e:
751766
raise e
@@ -841,7 +856,8 @@ def _send_request_wo_reconnect(self, request, on_push=None, on_push_ctx=None):
841856
response = request.response_class(self, self._read_response())
842857
break
843858
except SchemaReloadException as e:
844-
self.update_schema(e.schema_version)
859+
if self.fetch_schema:
860+
self.update_schema(e.schema_version)
845861
continue
846862

847863
while response._code == IPROTO_CHUNK:
@@ -1089,11 +1105,16 @@ def replace(self, space_name, values, on_push=None, on_push_ctx=None):
10891105
:exc:`~tarantool.error.DatabaseError`,
10901106
:exc:`~tarantool.error.SchemaError`,
10911107
:exc:`~tarantool.error.NetworkError`,
1092-
:exc:`~tarantool.error.SslError`
1108+
:exc:`~tarantool.error.SslError`,
1109+
:exc:`~tarantool.error.NotSupportedError`
10931110
10941111
.. _replace: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/replace/
10951112
"""
10961113

1114+
if not self.fetch_schema:
1115+
raise NotSupportedError('This method is not available in ' +
1116+
'connection opened with fetch_schema=False')
1117+
10971118
if isinstance(space_name, str):
10981119
space_name = self.schema.get_space(space_name).sid
10991120
if on_push is not None and not callable(on_push):
@@ -1276,11 +1297,16 @@ def insert(self, space_name, values, on_push=None, on_push_ctx=None):
12761297
:exc:`~tarantool.error.DatabaseError`,
12771298
:exc:`~tarantool.error.SchemaError`,
12781299
:exc:`~tarantool.error.NetworkError`,
1279-
:exc:`~tarantool.error.SslError`
1300+
:exc:`~tarantool.error.SslError`,
1301+
:exc:`~tarantool.error.NotSupportedError`
12801302
12811303
.. _insert: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/insert/
12821304
"""
12831305

1306+
if not self.fetch_schema:
1307+
raise NotSupportedError('This method is not available in ' +
1308+
'connection opened with fetch_schema=False')
1309+
12841310
if isinstance(space_name, str):
12851311
space_name = self.schema.get_space(space_name).sid
12861312
if on_push is not None and not callable(on_push):
@@ -1315,11 +1341,16 @@ def delete(self, space_name, key, *, index=0, on_push=None, on_push_ctx=None):
13151341
:exc:`~tarantool.error.DatabaseError`,
13161342
:exc:`~tarantool.error.SchemaError`,
13171343
:exc:`~tarantool.error.NetworkError`,
1318-
:exc:`~tarantool.error.SslError`
1344+
:exc:`~tarantool.error.SslError`,
1345+
:exc:`~tarantool.error.NotSupportedError`
13191346
13201347
.. _delete: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/delete/
13211348
"""
13221349

1350+
if not self.fetch_schema:
1351+
raise NotSupportedError('This method is not available in ' +
1352+
'connection opened with fetch_schema=False')
1353+
13231354
key = wrap_key(key)
13241355
if isinstance(space_name, str):
13251356
space_name = self.schema.get_space(space_name).sid
@@ -1374,11 +1405,16 @@ def upsert(self, space_name, tuple_value, op_list, *, index=0, on_push=None, on_
13741405
:exc:`~tarantool.error.DatabaseError`,
13751406
:exc:`~tarantool.error.SchemaError`,
13761407
:exc:`~tarantool.error.NetworkError`,
1377-
:exc:`~tarantool.error.SslError`
1408+
:exc:`~tarantool.error.SslError`,
1409+
:exc:`~tarantool.error.NotSupportedError`
13781410
13791411
.. _upsert: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/upsert/
13801412
"""
13811413

1414+
if not self.fetch_schema:
1415+
raise NotSupportedError('This method is not available in ' +
1416+
'connection opened with fetch_schema=False')
1417+
13821418
if isinstance(space_name, str):
13831419
space_name = self.schema.get_space(space_name).sid
13841420
if isinstance(index, str):
@@ -1462,11 +1498,16 @@ def update(self, space_name, key, op_list, *, index=0, on_push=None, on_push_ctx
14621498
:exc:`~tarantool.error.DatabaseError`,
14631499
:exc:`~tarantool.error.SchemaError`,
14641500
:exc:`~tarantool.error.NetworkError`,
1465-
:exc:`~tarantool.error.SslError`
1501+
:exc:`~tarantool.error.SslError`,
1502+
:exc:`~tarantool.error.NotSupportedError`
14661503
14671504
.. _update: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/update/
14681505
"""
14691506

1507+
if not self.fetch_schema:
1508+
raise NotSupportedError('This method is not available in ' +
1509+
'connection opened with fetch_schema=False')
1510+
14701511
key = wrap_key(key)
14711512
if isinstance(space_name, str):
14721513
space_name = self.schema.get_space(space_name).sid
@@ -1648,11 +1689,16 @@ def select(self, space_name, key=None, *, offset=0, limit=0xffffffff, index=0, i
16481689
:exc:`~tarantool.error.DatabaseError`,
16491690
:exc:`~tarantool.error.SchemaError`,
16501691
:exc:`~tarantool.error.NetworkError`,
1651-
:exc:`~tarantool.error.SslError`
1692+
:exc:`~tarantool.error.SslError`,
1693+
:exc:`~tarantool.error.NotSupportedError`
16521694
16531695
.. _select: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/select/
16541696
"""
16551697

1698+
if not self.fetch_schema:
1699+
raise NotSupportedError('This method is not available in ' +
1700+
'connection opened with fetch_schema=False')
1701+
16561702
if iterator is None:
16571703
iterator = ITERATOR_EQ
16581704
if key is None or (isinstance(key, (list, tuple)) and

tarantool/request.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,13 @@ def header(self, length):
186186
"""
187187

188188
self._sync = self.conn.generate_sync()
189-
header = self._dumps({IPROTO_REQUEST_TYPE: self.request_type,
190-
IPROTO_SYNC: self._sync,
191-
IPROTO_SCHEMA_ID: self.conn.schema_version})
189+
header_fields = {
190+
IPROTO_REQUEST_TYPE: self.request_type,
191+
IPROTO_SYNC: self._sync,
192+
}
193+
if self.conn.fetch_schema:
194+
header_fields[IPROTO_SCHEMA_ID] = self.conn.schema_version
195+
header = self._dumps(header_fields)
192196

193197
return self._dumps(length + len(header)) + header
194198

test/suites/test_schema.py

+37
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import unittest
33
import tarantool
44
from .lib.tarantool_server import TarantoolServer
5+
from tarantool.error import NotSupportedError
56

67

78
# FIXME: I'm quite sure that there is a simpler way to count
@@ -43,6 +44,8 @@ def setUpClass(self):
4344
self.srv.start()
4445
self.con = tarantool.Connection(self.srv.host, self.srv.args['primary'],
4546
encoding=self.encoding)
47+
self.con_schema_disable = tarantool.Connection(self.srv.host, self.srv.args['primary'],
48+
encoding=self.encoding, fetch_schema=False)
4649
self.sch = self.con.schema
4750

4851
# The relevant test cases mainly target Python 2, where
@@ -341,9 +344,43 @@ def test_07_schema_version_update(self):
341344
self.srv.admin("box.schema.create_space('ttt22')")
342345
self.assertEqual(len(self.con.select('_space')), _space_len + 1)
343346

347+
def test_08_schema_fetch_disable(self):
348+
self.assertEqual(hasattr(self.con_schema_disable, 'schema_version'), False)
349+
self.assertEqual(hasattr(self.con_schema_disable, 'schema'), False)
350+
351+
testing_methods = {
352+
'replace': {
353+
'input': ['',[]],
354+
},
355+
'insert': {
356+
'input': ['',[]],
357+
},
358+
'delete': {
359+
'input': ['',0],
360+
},
361+
'upsert': {
362+
'input': ['',[],[]],
363+
},
364+
'update': {
365+
'input': ['', 0, []],
366+
},
367+
'select': {
368+
'input': [''],
369+
},
370+
}
371+
for method_case in testing_methods.keys():
372+
with self.subTest(name=method_case):
373+
testing_function = getattr(self.con_schema_disable, method_case)
374+
try:
375+
_ = testing_function(*testing_methods[method_case]['input'])
376+
except NotSupportedError as e:
377+
self.assertEqual(e.message, 'This method is not available in ' +
378+
'connection opened with fetch_schema=False')
379+
344380
@classmethod
345381
def tearDownClass(self):
346382
self.con.close()
383+
self.con_schema_disable.close()
347384
self.srv.stop()
348385
self.srv.clean()
349386

0 commit comments

Comments
 (0)