It looks like Python 3's futures library lacks set_exception_info
entirely. We'll just give up and use set_exception in that case.
- no-check-commit because the underbar naming is just saner here
indygreg |
hg-reviewers |
It looks like Python 3's futures library lacks set_exception_info
entirely. We'll just give up and use set_exception in that case.
Automatic diff as part of commit; lint not applicable. |
Automatic diff as part of commit; unit tests not applicable. |
Path | Packages | |||
---|---|---|---|---|
M | mercurial/httppeer.py (3 lines) | |||
M | mercurial/localrepo.py (2 lines) | |||
M | mercurial/pycompat.py (6 lines) | |||
M | mercurial/wireprotov1peer.py (8 lines) |
if meta['cbor']: | if meta['cbor']: | ||||
payload = util.bytesio(meta['data']) | payload = util.bytesio(meta['data']) | ||||
decoder = cbor.CBORDecoder(payload) | decoder = cbor.CBORDecoder(payload) | ||||
while payload.tell() + 1 < len(meta['data']): | while payload.tell() + 1 < len(meta['data']): | ||||
try: | try: | ||||
result.append(decoder.decode()) | result.append(decoder.decode()) | ||||
except Exception: | except Exception: | ||||
f.set_exception_info(*sys.exc_info()[1:]) | pycompat.future_set_exception_info( | ||||
f, sys.exc_info()[1:]) | |||||
continue | continue | ||||
else: | else: | ||||
result.append(meta['data']) | result.append(meta['data']) | ||||
if meta['eos']: | if meta['eos']: | ||||
f.set_result(result) | f.set_result(result) | ||||
del results[request.requestid] | del results[request.requestid] | ||||
# method on the peer and return a resolved future. | # method on the peer and return a resolved future. | ||||
fn = getattr(self._peer, pycompat.sysstr(command)) | fn = getattr(self._peer, pycompat.sysstr(command)) | ||||
f = pycompat.futures.Future() | f = pycompat.futures.Future() | ||||
try: | try: | ||||
result = fn(**args) | result = fn(**args) | ||||
except Exception: | except Exception: | ||||
f.set_exception_info(*sys.exc_info()[1:]) | pycompat.future_set_exception_info(f, sys.exc_info()[1:]) | ||||
else: | else: | ||||
f.set_result(result) | f.set_result(result) | ||||
return f | return f | ||||
def sendcommands(self): | def sendcommands(self): | ||||
self._sent = True | self._sent = True | ||||
import cookielib | import cookielib | ||||
import cPickle as pickle | import cPickle as pickle | ||||
import httplib | import httplib | ||||
import Queue as _queue | import Queue as _queue | ||||
import SocketServer as socketserver | import SocketServer as socketserver | ||||
import xmlrpclib | import xmlrpclib | ||||
from .thirdparty.concurrent import futures | from .thirdparty.concurrent import futures | ||||
def future_set_exception_info(f, exc_info): | |||||
f.set_exception_info(*exc_info) | |||||
else: | else: | ||||
import concurrent.futures as futures | import concurrent.futures as futures | ||||
import http.cookiejar as cookielib | import http.cookiejar as cookielib | ||||
import http.client as httplib | import http.client as httplib | ||||
import pickle | import pickle | ||||
import queue as _queue | import queue as _queue | ||||
import socketserver | import socketserver | ||||
import xmlrpc.client as xmlrpclib | import xmlrpc.client as xmlrpclib | ||||
def future_set_exception_info(f, exc_info): | |||||
f.set_exception(exc_info[0]) | |||||
empty = _queue.Empty | empty = _queue.Empty | ||||
queue = _queue.Queue | queue = _queue.Queue | ||||
def identity(a): | def identity(a): | ||||
return a | return a | ||||
if ispy3: | if ispy3: | ||||
import builtins | import builtins |
# Future was cancelled. Ignore it. | # Future was cancelled. Ignore it. | ||||
if not f.set_running_or_notify_cancel(): | if not f.set_running_or_notify_cancel(): | ||||
return | return | ||||
try: | try: | ||||
result = fn(**pycompat.strkwargs(args)) | result = fn(**pycompat.strkwargs(args)) | ||||
except Exception: | except Exception: | ||||
f.set_exception_info(*sys.exc_info()[1:]) | pycompat.future_set_exception_info(f, sys.exc_info()[1:]) | ||||
else: | else: | ||||
f.set_result(result) | f.set_result(result) | ||||
return | return | ||||
# Batch commands are a bit harder. First, we have to deal with the | # Batch commands are a bit harder. First, we have to deal with the | ||||
# @batchable coroutine. That's a bit annoying. Furthermore, we also | # @batchable coroutine. That's a bit annoying. Furthermore, we also | ||||
# need to preserve streaming. i.e. it should be possible for the | # need to preserve streaming. i.e. it should be possible for the | ||||
# futures to resolve as data is coming in off the wire without having | # futures to resolve as data is coming in off the wire without having | ||||
# to wait for the final byte of the final response. We do this by | # to wait for the final byte of the final response. We do this by | ||||
# spinning up a thread to read the responses. | # spinning up a thread to read the responses. | ||||
requests = [] | requests = [] | ||||
states = [] | states = [] | ||||
for command, args, fn, f in calls: | for command, args, fn, f in calls: | ||||
# Future was cancelled. Ignore it. | # Future was cancelled. Ignore it. | ||||
if not f.set_running_or_notify_cancel(): | if not f.set_running_or_notify_cancel(): | ||||
continue | continue | ||||
try: | try: | ||||
batchable = fn.batchable(fn.__self__, | batchable = fn.batchable(fn.__self__, | ||||
**pycompat.strkwargs(args)) | **pycompat.strkwargs(args)) | ||||
except Exception: | except Exception: | ||||
f.set_exception_info(*sys.exc_info()[1:]) | pycompat.future_set_exception_info(f, sys.exc_info()[1:]) | ||||
return | return | ||||
# Encoded arguments and future holding remote result. | # Encoded arguments and future holding remote result. | ||||
try: | try: | ||||
encodedargs, fremote = next(batchable) | encodedargs, fremote = next(batchable) | ||||
except Exception: | except Exception: | ||||
f.set_exception_info(*sys.exc_info()[1:]) | pycompat.future_set_exception_info(f, sys.exc_info()[1:]) | ||||
return | return | ||||
requests.append((command, encodedargs)) | requests.append((command, encodedargs)) | ||||
states.append((command, f, batchable, fremote)) | states.append((command, f, batchable, fremote)) | ||||
if not requests: | if not requests: | ||||
return | return | ||||
# about it. | # about it. | ||||
remoteresult = next(wireresults) | remoteresult = next(wireresults) | ||||
fremote.set(remoteresult) | fremote.set(remoteresult) | ||||
# And ask the coroutine to decode that value. | # And ask the coroutine to decode that value. | ||||
try: | try: | ||||
result = next(batchable) | result = next(batchable) | ||||
except Exception: | except Exception: | ||||
f.set_exception_info(*sys.exc_info()[1:]) | pycompat.future_set_exception_info(f, sys.exc_info()[1:]) | ||||
else: | else: | ||||
f.set_result(result) | f.set_result(result) | ||||
@zi.implementer(repository.ipeercommands, repository.ipeerlegacycommands) | @zi.implementer(repository.ipeercommands, repository.ipeerlegacycommands) | ||||
class wirepeer(repository.peer): | class wirepeer(repository.peer): | ||||
"""Client-side interface for communicating with a peer repository. | """Client-side interface for communicating with a peer repository. | ||||
Methods commonly call wire protocol commands of the same name. | Methods commonly call wire protocol commands of the same name. |