[MERGE] Add ErrorFromSmartServer exception, and raise it from read_response_tuple for all protocol versions (protocol v3 patch 5/7)
Andrew Bennetts
andrew at canonical.com
Wed May 14 13:32:41 BST 2008
John Arbash Meinel wrote:
> John Arbash Meinel has voted tweak.
> Status is now: Conditionally approved
> Comment:
> Is peaking at "error_tuple[]" the right way to do it?
> You do stuff like:
>
> if e.error_tuple = (some, value):
>
> and
>
> if e.error_tuple[0] == 'xxxx':
>
> I would worry if error_tuple is empty, then the latter would raise an
> IndexError instead of the original error. I would be happier if the
> errors were more standardized, so you would have:
> e.error_type or some other member that represents the first entry in
> error_tuple.
>
> Otherwise, I think I would use slices instead of direct indexes. So
> something like:
>
> if e.error_tuple[:1] == ('xxxxx',):
>
> That way if the tuple is empty, you get () != ('xxxx',) rather than an
> index error. (Of course, error_tuple can't be None, etc.
I've added these lines to ErrorFromSmartServer's __init__:
try:
self.error_verb = error_tuple[0]
except IndexError:
self.error_verb = None
self.error_args = error_tuple[1:]
And I've changed remote.py to use these new attributes when appropriate. I
still do “err.error_tuple == ...” sometimes, as equality is always safe, and is
more precise. (If unexpected data is received, I'd rather the client raised an
error rather than ignoring it.)
> + try:
> + response = self._client.call_expecting_body(
> + 'Repository.get_revision_graph', path, revision_id)
> + except errors.ErrorFromSmartServer, err:
> + if err.error_tuple[0] == 'nosuchrevision':
> + raise NoSuchRevision(self, revision_id)
> + if response[0][0] != 'ok':
>
> ^-- I think there is a latent bug here. If an error is raised which is
> not
> "NoSuchRevision" then it will fall through. But 'response' isn't set
> either,
> because an exception was raised. I think you need:
>
> + if err.error_tuple[0] == 'nosuchrevision':
> + raise NoSuchRevision(self, revision_id)
> + raise
> + if response[0][0] != 'ok':
You're right. It'd be nice to have a more reusable way to convert error
responses into exceptions, so these mistakes are harder to make.
I've fixed this instance, and added a test
(test_remote.TestRepositoryGetRevisionGraph.test_unexpected_error).
> + except errors.ErrorFromSmartServer, err:
> + if err.error_tuple[0] == 'LockContention':
> + raise errors.LockContention('(remote lock)')
> + elif err.error_tuple[0] == 'UnlockableTransport':
> + raise
> errors.UnlockableTransport(self.bzrdir.root_transport)
> + elif err.error_tuple[0] == 'LockFailed':
> + raise errors.LockFailed(err.error_tuple[1],
> err.error_tuple[2])
>
> ^- More of a side question. why is the other error "nobranch" but these
> errors
> are all 'LockContention' (CamelCase). Seems inconsistent. Unless the
> first is
> a plain response and the others are exceptions?
Hysterical raisins. Early errors codes tended to be alllower, newer ones have
been CamelCase.
> + if self._requested_parents is not None and len(ancestry) !=
> 0:
> + self._requested_parents.update(present_keys)
> + mutter('Current RemoteRepository graph hit rate: %d%%',
> + 100.0 * len(self._requested_parents) /
> len(ancestry))
>
> ^- Since we are here, *I* would really like it if this printed the
> actual
> counts for _requested_parents and ancestry.
I agree (and not log if the numbers are the same as the previous time we
logged them), but this patch is plenty big enough without adding random
drive-bys.
I'll happily review a quick patch from you to make that change though.
> Again here:
> @@ -1503,10 +1518,11 @@
> self._ensure_real()
> self._clear_cached_state()
> return self._real_branch.set_last_revision_info(revno,
> revision_id)
> + except errors.ErrorFromSmartServer, err:
> + if err.error_tuple[0] == 'NoSuchRevision':
> + raise NoSuchRevision(self, err.error_tuple[1])
> if response == ('ok',):
> self._clear_cached_state()
> - elif response[0] == 'NoSuchRevision':
> - raise NoSuchRevision(self, response[1])
> else:
> raise errors.UnexpectedSmartServerResponse(response)
>
> I think you need the plain 'raise' section. Should we have explicit
> tests for
> these?
Good catch. I've added a test for this case.
> + client.add_success_response_with_body('', 'ok')
>
> ^- Why does 'add_success_...' need to supply 'ok'. Do some of them
> return
> something other than 'ok' for success?
Well, many uses of add_success_response do, obviously.
add_success_response_with_body doesn't at the moment, but there's no particular
reason why it couldn't. I'd rather leave this explicit (and consistent with
add_success_response).
Again, thanks for the review.
-Andrew.
More information about the bazaar
mailing list