From e7898d6c08b7efe5ef7750e6e4dbe08ad3ff0683 Mon Sep 17 00:00:00 2001 From: Igor Mineev Date: Wed, 10 Mar 2021 19:20:39 +0300 Subject: [PATCH] Add forwarding msgpack packer and unpacker to call function --- tarantool/connection.py | 15 ++++----- tarantool/request.py | 58 +++++++++++++++++----------------- tarantool/response.py | 69 +++++++++++++++++++++-------------------- 3 files changed, 73 insertions(+), 69 deletions(-) diff --git a/tarantool/connection.py b/tarantool/connection.py index 0ff39b58..15c4cadf 100644 --- a/tarantool/connection.py +++ b/tarantool/connection.py @@ -281,7 +281,7 @@ def _read_response(self): # Read the packet return self._recv(length) - def _send_request_wo_reconnect(self, request): + def _send_request_wo_reconnect(self, request, unpacker=None): ''' :rtype: `Response` instance or subclass @@ -293,7 +293,7 @@ def _send_request_wo_reconnect(self, request): while True: try: self._socket.sendall(bytes(request)) - response = request.response_class(self, self._read_response()) + response = request.response_class(self, self._read_response(), unpacker=unpacker) break except SchemaReloadException as e: self.update_schema(e.schema_version) @@ -364,7 +364,7 @@ def check(): # Check that connection is alive attempt += 1 self.handshake() - def _send_request(self, request): + def _send_request(self, request, unpacker=None): ''' Send the request to the server through the socket. Return an instance of `Response` class. @@ -378,7 +378,7 @@ def _send_request(self, request): self._opt_reconnect() - return self._send_request_wo_reconnect(request) + return self._send_request_wo_reconnect(request, unpacker=unpacker) def load_schema(self): self.schema.fetch_space_all() @@ -392,7 +392,7 @@ def flush_schema(self): self.schema.flush() self.load_schema() - def call(self, func_name, *args): + def call(self, func_name, *args, msgpack_packer=None, msgpack_unpacker=None): ''' Execute CALL request. Call stored Lua function. @@ -409,8 +409,9 @@ def call(self, func_name, *args): if len(args) == 1 and isinstance(args[0], (list, tuple)): args = args[0] - request = RequestCall(self, func_name, args, self.call_16) - response = self._send_request(request) + request = RequestCall(self, func_name, args, self.call_16, + packer=msgpack_packer) + response = self._send_request(request, unpacker=msgpack_unpacker) return response def eval(self, expr, *args): diff --git a/tarantool/request.py b/tarantool/request.py index d1a5a829..a6540682 100644 --- a/tarantool/request.py +++ b/tarantool/request.py @@ -70,37 +70,39 @@ class Request(object): ''' request_type = None - def __init__(self, conn): + def __init__(self, conn, packer=None): self._bytes = None self.conn = conn self._sync = None self._body = '' self.response_class = Response - - packer_kwargs = dict() - - # use_bin_type=True is default since msgpack-1.0.0. - # - # The option controls whether to pack binary (non-unicode) - # string values as mp_bin or as mp_str. - # - # The default behaviour of the connector is to pack both - # bytes and Unicode strings as mp_str. - # - # msgpack-0.5.0 (and only this version) warns when the - # option is unset: - # - # | FutureWarning: use_bin_type option is not specified. - # | Default value of the option will be changed in future - # | version. - # - # The option is supported since msgpack-0.4.0, so we can - # just always set it for all msgpack versions to get rid - # of the warning on msgpack-0.5.0 and to keep our - # behaviour on msgpack-1.0.0. - packer_kwargs['use_bin_type'] = False - - self.packer = msgpack.Packer(**packer_kwargs) + self.packer = packer + + if self.packer is None: + packer_kwargs = dict() + + # use_bin_type=True is default since msgpack-1.0.0. + # + # The option controls whether to pack binary (non-unicode) + # string values as mp_bin or as mp_str. + # + # The default behaviour of the connector is to pack both + # bytes and Unicode strings as mp_str. + # + # msgpack-0.5.0 (and only this version) warns when the + # option is unset: + # + # | FutureWarning: use_bin_type option is not specified. + # | Default value of the option will be changed in future + # | version. + # + # The option is supported since msgpack-0.4.0, so we can + # just always set it for all msgpack versions to get rid + # of the warning on msgpack-0.5.0 and to keep our + # behaviour on msgpack-1.0.0. + packer_kwargs['use_bin_type'] = False + + self.packer = msgpack.Packer(**packer_kwargs) def _dumps(self, src): return self.packer.pack(src) @@ -269,10 +271,10 @@ class RequestCall(Request): request_type = REQUEST_TYPE_CALL # pylint: disable=W0231 - def __init__(self, conn, name, args, call_16): + def __init__(self, conn, name, args, call_16, packer=None): if call_16: self.request_type = REQUEST_TYPE_CALL16 - super(RequestCall, self).__init__(conn) + super(RequestCall, self).__init__(conn, packer=packer) assert isinstance(args, (list, tuple)) request_body = self._dumps({IPROTO_FUNCTION_NAME: name, diff --git a/tarantool/response.py b/tarantool/response.py index 24464fda..868140d9 100644 --- a/tarantool/response.py +++ b/tarantool/response.py @@ -38,7 +38,7 @@ class Response(Sequence): and parses binary packet received from the server. ''' - def __init__(self, conn, response): + def __init__(self, conn, response, unpacker=None): ''' Create an instance of `Response` using data received from the server. @@ -53,39 +53,40 @@ def __init__(self, conn, response): # created in the __new__(). # super(Response, self).__init__() - unpacker_kwargs = dict() - - # Decode msgpack arrays into Python lists by default (not tuples). - # Can be configured in the Connection init - unpacker_kwargs['use_list'] = conn.use_list - - # Use raw=False instead of encoding='utf-8'. - if msgpack.version >= (0, 5, 2) and conn.encoding == 'utf-8': - # Get rid of the following warning. - # > PendingDeprecationWarning: encoding is deprecated, - # > Use raw=False instead. - unpacker_kwargs['raw'] = False - elif conn.encoding is not None: - unpacker_kwargs['encoding'] = conn.encoding - - # raw=False is default since msgpack-1.0.0. - # - # The option decodes mp_str to bytes, not a Unicode - # string (when True). - if msgpack.version >= (1, 0, 0) and conn.encoding is None: - unpacker_kwargs['raw'] = True - - # encoding option is not supported since msgpack-1.0.0, - # but it is handled in the Connection constructor. - assert(msgpack.version < (1, 0, 0) or conn.encoding in (None, 'utf-8')) - - # strict_map_key=True is default since msgpack-1.0.0. - # - # The option forbids non-string keys in a map (when True). - if msgpack.version >= (1, 0, 0): - unpacker_kwargs['strict_map_key'] = False - - unpacker = msgpack.Unpacker(**unpacker_kwargs) + if unpacker is None: + unpacker_kwargs = dict() + + # Decode msgpack arrays into Python lists by default (not tuples). + # Can be configured in the Connection init + unpacker_kwargs['use_list'] = conn.use_list + + # Use raw=False instead of encoding='utf-8'. + if msgpack.version >= (0, 5, 2) and conn.encoding == 'utf-8': + # Get rid of the following warning. + # > PendingDeprecationWarning: encoding is deprecated, + # > Use raw=False instead. + unpacker_kwargs['raw'] = False + elif conn.encoding is not None: + unpacker_kwargs['encoding'] = conn.encoding + + # raw=False is default since msgpack-1.0.0. + # + # The option decodes mp_str to bytes, not a Unicode + # string (when True). + if msgpack.version >= (1, 0, 0) and conn.encoding is None: + unpacker_kwargs['raw'] = True + + # encoding option is not supported since msgpack-1.0.0, + # but it is handled in the Connection constructor. + assert(msgpack.version < (1, 0, 0) or conn.encoding in (None, 'utf-8')) + + # strict_map_key=True is default since msgpack-1.0.0. + # + # The option forbids non-string keys in a map (when True). + if msgpack.version >= (1, 0, 0): + unpacker_kwargs['strict_map_key'] = False + + unpacker = msgpack.Unpacker(**unpacker_kwargs) unpacker.feed(response) header = unpacker.unpack()