~bzr-pqm/bzr/bzr.dev

3245.4.31 by Andrew Bennetts
Fix year in copyright statement of message.py
1
# Copyright (C) 2008 Canonical Ltd
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
16
6379.6.3 by Jelmer Vernooij
Use absolute_import.
17
from __future__ import absolute_import
18
3195.3.24 by Andrew Bennetts
Implement read_streamed_body on ConventionalResponseHandler.
19
import collections
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
20
from cStringIO import StringIO
21
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
22
from bzrlib import (
23
    debug,
24
    errors,
25
    )
26
from bzrlib.trace import mutter
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
27
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
28
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
29
class MessageHandler(object):
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
30
    """Base class for handling messages received via the smart protocol.
31
32
    As parts of a message are received, the corresponding PART_received method
33
    will be called.
34
    """
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
35
36
    def __init__(self):
37
        self.headers = None
38
39
    def headers_received(self, headers):
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
40
        """Called when message headers are received.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
41
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
42
        This default implementation just stores them in self.headers.
43
        """
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
44
        self.headers = headers
45
46
    def byte_part_received(self, byte):
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
47
        """Called when a 'byte' part is received.
48
49
        Note that a 'byte' part is a message part consisting of exactly one
50
        byte.
51
        """
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
52
        raise NotImplementedError(self.byte_received)
53
54
    def bytes_part_received(self, bytes):
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
55
        """Called when a 'bytes' part is received.
56
57
        A 'bytes' message part can contain any number of bytes.  It should not
58
        be confused with a 'byte' part, which is always a single byte.
59
        """
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
60
        raise NotImplementedError(self.bytes_received)
61
62
    def structure_part_received(self, structure):
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
63
        """Called when a 'structure' part is received.
64
65
        :param structure: some structured data, which will be some combination
66
            of list, dict, int, and str objects.
67
        """
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
68
        raise NotImplementedError(self.bytes_received)
69
70
    def protocol_error(self, exception):
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
71
        """Called when there is a protocol decoding error.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
72
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
73
        The default implementation just re-raises the exception.
74
        """
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
75
        raise
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
76
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
77
    def end_received(self):
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
78
        """Called when the end of the message is received."""
3245.4.27 by Andrew Bennetts
Tidy some XXXs in bzrlib/smart/message.py.
79
        # No-op by default.
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
80
        pass
81
82
83
class ConventionalRequestHandler(MessageHandler):
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
84
    """A message handler for "conventional" requests.
85
86
    "Conventional" is used in the sense described in
87
    doc/developers/network-protocol.txt: a simple message with arguments and an
88
    optional body.
3842.3.4 by Andrew Bennetts
TestStacking.test_fetch_copies_from_stacked_on now passes using the VersionedFile.insert_record_stream RPC; lots of debugging cruft needs removal though.
89
90
    Possible states:
3842.3.19 by Andrew Bennetts
Tweaks suggested by review.
91
     * args: expecting args
92
     * body: expecting body (terminated by receiving a post-body status)
93
     * error: expecting post-body error
94
     * end: expecting end of message
95
     * nothing: finished
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
96
    """
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
97
98
    def __init__(self, request_handler, responder):
99
        MessageHandler.__init__(self)
100
        self.request_handler = request_handler
101
        self.responder = responder
3842.3.4 by Andrew Bennetts
TestStacking.test_fetch_copies_from_stacked_on now passes using the VersionedFile.insert_record_stream RPC; lots of debugging cruft needs removal though.
102
        self.expecting = 'args'
103
        self._should_finish_body = False
104
        self._response_sent = False
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
105
106
    def protocol_error(self, exception):
3245.4.50 by Andrew Bennetts
Clarify the code a little.
107
        if self.responder.response_sent:
108
            # We can only send one response to a request, no matter how many
109
            # errors happen while processing it.
110
            return
111
        self.responder.send_error(exception)
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
112
113
    def byte_part_received(self, byte):
3923.5.1 by Andrew Bennetts
Add _SmartClient.call_with_body_bytes, plus some server-side code for handling bodies delivered in multiple parts.
114
        if self.expecting == 'body':
3923.5.4 by Andrew Bennetts
Allow a request's body part(s) to be followed by an error.
115
            if byte == 'S':
116
                # Success.  Nothing more to come except the end of message.
117
                self.expecting = 'end'
118
            elif byte == 'E':
119
                # Error.  Expect an error structure.
120
                self.expecting = 'error'
121
            else:
3842.3.4 by Andrew Bennetts
TestStacking.test_fetch_copies_from_stacked_on now passes using the VersionedFile.insert_record_stream RPC; lots of debugging cruft needs removal though.
122
                raise errors.SmartProtocolError(
123
                    'Non-success status byte in request body: %r' % (byte,))
124
        else:
125
            raise errors.SmartProtocolError(
126
                'Unexpected message part: byte(%r)' % (byte,))
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
127
128
    def structure_part_received(self, structure):
3923.5.4 by Andrew Bennetts
Allow a request's body part(s) to be followed by an error.
129
        if self.expecting == 'args':
130
            self._args_received(structure)
131
        elif self.expecting == 'error':
132
            self._error_received(structure)
133
        else:
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
134
            raise errors.SmartProtocolError(
135
                'Unexpected message part: structure(%r)' % (structure,))
3923.5.4 by Andrew Bennetts
Allow a request's body part(s) to be followed by an error.
136
137
    def _args_received(self, args):
3842.3.4 by Andrew Bennetts
TestStacking.test_fetch_copies_from_stacked_on now passes using the VersionedFile.insert_record_stream RPC; lots of debugging cruft needs removal though.
138
        self.expecting = 'body'
4634.6.30 by Andrew Bennetts
Remove SmartServerRequest.dispatch_command, fix SmartServerRequest.args_received.
139
        self.request_handler.args_received(args)
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
140
        if self.request_handler.finished_reading:
3842.3.4 by Andrew Bennetts
TestStacking.test_fetch_copies_from_stacked_on now passes using the VersionedFile.insert_record_stream RPC; lots of debugging cruft needs removal though.
141
            self._response_sent = True
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
142
            self.responder.send_response(self.request_handler.response)
3842.3.4 by Andrew Bennetts
TestStacking.test_fetch_copies_from_stacked_on now passes using the VersionedFile.insert_record_stream RPC; lots of debugging cruft needs removal though.
143
            self.expecting = 'end'
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
144
3923.5.4 by Andrew Bennetts
Allow a request's body part(s) to be followed by an error.
145
    def _error_received(self, error_args):
146
        self.expecting = 'end'
147
        self.request_handler.post_body_error_received(error_args)
148
3842.3.4 by Andrew Bennetts
TestStacking.test_fetch_copies_from_stacked_on now passes using the VersionedFile.insert_record_stream RPC; lots of debugging cruft needs removal though.
149
    def bytes_part_received(self, bytes):
150
        if self.expecting == 'body':
151
            self._should_finish_body = True
152
            self.request_handler.accept_body(bytes)
153
        else:
154
            raise errors.SmartProtocolError(
155
                'Unexpected message part: bytes(%r)' % (bytes,))
156
157
    def end_received(self):
3923.5.2 by Andrew Bennetts
Completely delegate handling of request body chunks to the command object. The default implementation accumulates, like the existing behaviour.
158
        if self.expecting not in ['body', 'end']:
3923.5.3 by Andrew Bennetts
Raise a better exception if a premature message end happens.
159
            raise errors.SmartProtocolError(
160
                'End of message received prematurely (while expecting %s)'
3923.5.2 by Andrew Bennetts
Completely delegate handling of request body chunks to the command object. The default implementation accumulates, like the existing behaviour.
161
                % (self.expecting,))
3842.3.4 by Andrew Bennetts
TestStacking.test_fetch_copies_from_stacked_on now passes using the VersionedFile.insert_record_stream RPC; lots of debugging cruft needs removal though.
162
        self.expecting = 'nothing'
163
        self.request_handler.end_received()
3923.5.2 by Andrew Bennetts
Completely delegate handling of request body chunks to the command object. The default implementation accumulates, like the existing behaviour.
164
        if not self.request_handler.finished_reading:
165
            raise errors.SmartProtocolError(
166
                "Complete conventional request was received, but request "
167
                "handler has not finished reading.")
3842.3.4 by Andrew Bennetts
TestStacking.test_fetch_copies_from_stacked_on now passes using the VersionedFile.insert_record_stream RPC; lots of debugging cruft needs removal though.
168
        if not self._response_sent:
169
            self.responder.send_response(self.request_handler.response)
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
170
171
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
172
class ResponseHandler(object):
173
    """Abstract base class for an object that handles a smart response."""
174
175
    def read_response_tuple(self, expect_body=False):
176
        """Reads and returns the response tuple for the current request.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
177
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
178
        :keyword expect_body: a boolean indicating if a body is expected in the
179
            response.  Some protocol versions needs this information to know
180
            when a response is finished.  If False, read_body_bytes should
181
            *not* be called afterwards.  Defaults to False.
182
        :returns: tuple of response arguments.
183
        """
184
        raise NotImplementedError(self.read_response_tuple)
185
186
    def read_body_bytes(self, count=-1):
187
        """Read and return some bytes from the body.
188
189
        :param count: if specified, read up to this many bytes.  By default,
190
            reads the entire body.
191
        :returns: str of bytes from the response body.
192
        """
193
        raise NotImplementedError(self.read_body_bytes)
194
195
    def read_streamed_body(self):
196
        """Returns an iterable that reads and returns a series of body chunks.
197
        """
198
        raise NotImplementedError(self.read_streamed_body)
199
200
    def cancel_read_body(self):
201
        """Stop expecting a body for this response.
202
203
        If expect_body was passed to read_response_tuple, this cancels that
204
        expectation (and thus finishes reading the response, allowing a new
205
        request to be issued).  This is useful if a response turns out to be an
206
        error rather than a normal result with a body.
207
        """
208
        raise NotImplementedError(self.cancel_read_body)
209
210
211
class ConventionalResponseHandler(MessageHandler, ResponseHandler):
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
212
213
    def __init__(self):
214
        MessageHandler.__init__(self)
215
        self.status = None
216
        self.args = None
3195.3.24 by Andrew Bennetts
Implement read_streamed_body on ConventionalResponseHandler.
217
        self._bytes_parts = collections.deque()
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
218
        self._body_started = False
219
        self._body_stream_status = None
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
220
        self._body = None
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
221
        self._body_error_args = None
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
222
        self.finished_reading = False
223
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
224
    def setProtoAndMediumRequest(self, protocol_decoder, medium_request):
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
225
        self._protocol_decoder = protocol_decoder
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
226
        self._medium_request = medium_request
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
227
228
    def byte_part_received(self, byte):
229
        if byte not in ['E', 'S']:
230
            raise errors.SmartProtocolError(
231
                'Unknown response status: %r' % (byte,))
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
232
        if self._body_started:
233
            if self._body_stream_status is not None:
234
                raise errors.SmartProtocolError(
235
                    'Unexpected byte part received: %r' % (byte,))
236
            self._body_stream_status = byte
237
        else:
238
            if self.status is not None:
239
                raise errors.SmartProtocolError(
240
                    'Unexpected byte part received: %r' % (byte,))
241
            self.status = byte
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
242
243
    def bytes_part_received(self, bytes):
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
244
        self._body_started = True
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
245
        self._bytes_parts.append(bytes)
246
247
    def structure_part_received(self, structure):
3842.3.6 by Andrew Bennetts
Tweak bencode.py to decode sequences as tuples, not lists.
248
        if type(structure) is not tuple:
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
249
            raise errors.SmartProtocolError(
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
250
                'Args structure is not a sequence: %r' % (structure,))
251
        if not self._body_started:
252
            if self.args is not None:
253
                raise errors.SmartProtocolError(
254
                    'Unexpected structure received: %r (already got %r)'
255
                    % (structure, self.args))
256
            self.args = structure
257
        else:
258
            if self._body_stream_status != 'E':
259
                raise errors.SmartProtocolError(
260
                    'Unexpected structure received after body: %r'
261
                    % (structure,))
262
            self._body_error_args = structure
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
263
264
    def _wait_for_response_args(self):
265
        while self.args is None and not self.finished_reading:
266
            self._read_more()
267
268
    def _wait_for_response_end(self):
269
        while not self.finished_reading:
270
            self._read_more()
271
272
    def _read_more(self):
273
        next_read_size = self._protocol_decoder.next_read_size()
274
        if next_read_size == 0:
275
            # a complete request has been read.
276
            self.finished_reading = True
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
277
            self._medium_request.finished_reading()
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
278
            return
3750.1.2 by Vincent Ladeuil
Fixed as per Andrew's review.
279
        bytes = self._medium_request.read_bytes(next_read_size)
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
280
        if bytes == '':
281
            # end of file encountered reading from server
3461.2.1 by Andrew Bennetts
Avoid unnecessary reconnections to old servers when the first HPSS is an error in the right protocol version.
282
            if 'hpss' in debug.debug_flags:
283
                mutter(
284
                    'decoder state: buf[:10]=%r, state_accept=%s',
3702.2.1 by Andrew Bennetts
Fix '_in_buffer' AttributeError when using the -Dhpss debug flag.
285
                    self._protocol_decoder._get_in_buffer()[:10],
3461.2.2 by Andrew Bennetts
Tweak suggested by John.
286
                    self._protocol_decoder.state_accept.__name__)
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
287
            raise errors.ConnectionReset(
4509.2.1 by Martin Pool
Tweak hpss connection-dropped error message
288
                "Unexpected end of message. "
289
                "Please check connectivity and permissions, and report a bug "
290
                "if problems persist.")
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
291
        self._protocol_decoder.accept_bytes(bytes)
292
3245.4.47 by Andrew Bennetts
Don't automatically send 'hello' requests from RemoteBzrDirFormat.probe_transport unless we have to (i.e. the transport is HTTP).
293
    def protocol_error(self, exception):
294
        # Whatever the error is, we're done with this request.
295
        self.finished_reading = True
296
        self._medium_request.finished_reading()
297
        raise
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
298
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
299
    def read_response_tuple(self, expect_body=False):
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
300
        """Read a response tuple from the wire."""
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
301
        self._wait_for_response_args()
3195.3.18 by Andrew Bennetts
call_with_body_bytes now works with v3 (e.g. test_copy_content_remote_to_local passes). Lots of debugging cruft, though.
302
        if not expect_body:
303
            self._wait_for_response_end()
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
304
        if 'hpss' in debug.debug_flags:
305
            mutter('   result:   %r', self.args)
306
        if self.status == 'E':
307
            self._wait_for_response_end()
5677.2.3 by Martin
Gut smart.message._translate_error as it duplicates logic in remote
308
            _raise_smart_server_error(self.args)
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
309
        return tuple(self.args)
310
311
    def read_body_bytes(self, count=-1):
312
        """Read bytes from the body, decoding into a byte stream.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
313
314
        We read all bytes at once to ensure we've checked the trailer for
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
315
        errors, and then feed the buffer back as read_body_bytes is called.
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
316
317
        Like the builtin file.read in Python, a count of -1 (the default) means
318
        read the entire body.
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
319
        """
3245.4.39 by Andrew Bennetts
Tweaks to bzrlib/smart/message.py suggested by John's review.
320
        # TODO: we don't necessarily need to buffer the full request if count
321
        # != -1.  (2008/04/30, Andrew Bennetts)
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
322
        if self._body is None:
3195.3.18 by Andrew Bennetts
call_with_body_bytes now works with v3 (e.g. test_copy_content_remote_to_local passes). Lots of debugging cruft, though.
323
            self._wait_for_response_end()
3245.4.25 by Andrew Bennetts
Add some -Dhpss mutters to the protocol v3 code, so that it gives comparable debug logging to earlier protocols.
324
            body_bytes = ''.join(self._bytes_parts)
325
            if 'hpss' in debug.debug_flags:
326
                mutter('              %d body bytes read', len(body_bytes))
327
            self._body = StringIO(body_bytes)
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
328
            self._bytes_parts = None
329
        return self._body.read(count)
330
3195.3.24 by Andrew Bennetts
Implement read_streamed_body on ConventionalResponseHandler.
331
    def read_streamed_body(self):
332
        while not self.finished_reading:
333
            while self._bytes_parts:
3245.4.25 by Andrew Bennetts
Add some -Dhpss mutters to the protocol v3 code, so that it gives comparable debug logging to earlier protocols.
334
                bytes_part = self._bytes_parts.popleft()
4574.1.1 by Martin Pool
Move 'byte part read' messages to -Dhpssdetail
335
                if 'hpssdetail' in debug.debug_flags:
4070.9.10 by Andrew Bennetts
Revert some cruft.
336
                    mutter('              %d byte part read', len(bytes_part))
3245.4.25 by Andrew Bennetts
Add some -Dhpss mutters to the protocol v3 code, so that it gives comparable debug logging to earlier protocols.
337
                yield bytes_part
3195.3.24 by Andrew Bennetts
Implement read_streamed_body on ConventionalResponseHandler.
338
            self._read_more()
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
339
        if self._body_stream_status == 'E':
5677.2.3 by Martin
Gut smart.message._translate_error as it duplicates logic in remote
340
            _raise_smart_server_error(self._body_error_args)
3195.3.24 by Andrew Bennetts
Implement read_streamed_body on ConventionalResponseHandler.
341
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
342
    def cancel_read_body(self):
343
        self._wait_for_response_end()
3245.4.5 by Andrew Bennetts
Implement interrupting body streams with an error.
344
345
5677.2.3 by Martin
Gut smart.message._translate_error as it duplicates logic in remote
346
def _raise_smart_server_error(error_tuple):
347
    """Raise exception based on tuple received from smart server
348
349
    Specific error translation is handled by bzrlib.remote._translate_error
350
    """
351
    if error_tuple[0] == 'UnknownMethod':
352
        raise errors.UnknownSmartMethod(error_tuple[1])
353
    raise errors.ErrorFromSmartServer(error_tuple)