You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/prompt_toolkit/eventloop/base.py

185 lines
5.6 KiB

"""
Base event loop interface.
The naming convention is kept similar to asyncio as much as possible.
A special thanks to asyncio (tulip), Twisted, Tornado and Trollius for setting
a good example on how to implement event loops. Possible, in the future, we'll
run entirely on top of asyncio, but right now, we're still supporting Python 2.
"""
from __future__ import unicode_literals
from abc import ABCMeta, abstractmethod
from six import with_metaclass
from prompt_toolkit.log import logger
import sys
__all__ = [
'EventLoop',
'get_traceback_from_context',
]
class EventLoop(with_metaclass(ABCMeta, object)):
"""
Eventloop interface.
"""
def __init__(self):
self._exception_handler = None
@abstractmethod
def run_until_complete(self, future, inputhook=None):
"""
Keep running until this future has been set.
Return the Future's result, or raise its exception.
"""
def run_forever(self, inputhook=None):
"""
Run loop forever.
"""
f = self.create_future()
self.run_until_complete(f, inputhook=inputhook)
@abstractmethod
def close(self):
"""
Clean up of resources. Eventloop cannot be reused a second time after
this call.
"""
@abstractmethod
def add_reader(self, fd, callback):
"""
Start watching the file descriptor for read availability and then call
the callback.
"""
@abstractmethod
def remove_reader(self, fd):
"""
Stop watching the file descriptor for read availability.
"""
def add_win32_handle(self, handle, callback):
"""
Add a Windows Handle to the event loop.
(Only applied to win32 loops.)
"""
raise NotImplementedError
def remove_win32_handle(self, handle):
"""
Remove a Windows Handle from the event loop.
(Only applied to win32 loops.)
"""
raise NotImplementedError
@abstractmethod
def run_in_executor(self, callback, _daemon=False):
"""
Run a long running function in a background thread. (This is
recommended for code that could block the event loop.)
Similar to Twisted's ``deferToThread``.
"""
@abstractmethod
def call_from_executor(self, callback, _max_postpone_until=None):
"""
Call this function in the main event loop. Similar to Twisted's
``callFromThread``.
:param _max_postpone_until: `None` or `time.time` value. For internal
use. If the eventloop is saturated, consider this task to be low
priority and postpone maximum until this timestamp. (For instance,
repaint is done using low priority.)
Note: In the past, this used to be a datetime.datetime instance,
but apparently, executing `time.time` is more efficient: it
does fewer system calls. (It doesn't read /etc/localtime.)
"""
def create_future(self):
"""
Create a `Future` object that is attached to this loop.
This is the preferred way of creating futures.
"""
from .future import Future
return Future(loop=self)
def set_exception_handler(self, handler):
"""
Set the exception handler.
"""
assert handler is None or callable(handler)
self._exception_handler = handler
def get_exception_handler(self):
"""
Return the exception handler.
"""
return self._exception_handler
def call_exception_handler(self, context):
"""
Call the current event loop exception handler.
(Similar to ``asyncio.BaseEventLoop.call_exception_handler``.)
"""
if self._exception_handler:
try:
self._exception_handler(context)
except Exception:
logger.error('Exception in default exception handler',
exc_info=True)
else:
try:
self.default_exception_handler(context)
except Exception:
logger.error('Exception in default exception handler '
'while handling an unexpected error '
'in custom exception handler',
exc_info=True)
def default_exception_handler(self, context):
"""
Default exception handling.
Thanks to asyncio for this function!
"""
message = context.get('message')
if not message:
message = 'Unhandled exception in event loop'
exception = context.get('exception')
if exception is not None:
tb = get_traceback_from_context(context)
exc_info = (type(exception), exception, tb)
else:
exc_info = False
log_lines = [message]
for key in sorted(context):
if key in ('message', 'exception'):
continue
value = context[key]
value = repr(value)
log_lines.append('{}: {}'.format(key, value))
logger.error('\n'.join(log_lines), exc_info=exc_info)
def get_traceback_from_context(context):
"""
Get the traceback object from the context.
"""
exception = context.get('exception')
if exception:
if hasattr(exception, '__traceback__'):
return exception.__traceback__
else:
# call_exception_handler() is usually called indirectly
# from an except block. If it's not the case, the traceback
# is undefined...
return sys.exc_info()[2]
return None