Reformat with Black
No functional changes.
This commit is contained in:
@@ -38,7 +38,7 @@ def setup_asyncio_executor():
|
||||
|
||||
import sys
|
||||
|
||||
if sys.platform == 'win32':
|
||||
if sys.platform == "win32":
|
||||
asyncio.get_event_loop().close()
|
||||
# On Windows, the default event loop is SelectorEventLoop, which does
|
||||
# not support subprocesses. ProactorEventLoop should be used instead.
|
||||
@@ -55,6 +55,7 @@ def setup_asyncio_executor():
|
||||
# loop.set_debug(True)
|
||||
|
||||
from . import pillar
|
||||
|
||||
# No more than this many Pillar calls should be made simultaneously
|
||||
pillar.pillar_semaphore = asyncio.Semaphore(3, loop=loop)
|
||||
|
||||
@@ -72,7 +73,7 @@ def kick_async_loop(*args) -> bool:
|
||||
stop_after_this_kick = False
|
||||
|
||||
if loop.is_closed():
|
||||
log.warning('loop closed, stopping immediately.')
|
||||
log.warning("loop closed, stopping immediately.")
|
||||
return True
|
||||
|
||||
# Passing an explicit loop is required. Without it, the function uses
|
||||
@@ -81,12 +82,14 @@ def kick_async_loop(*args) -> bool:
|
||||
all_tasks = asyncio.all_tasks(loop=loop)
|
||||
|
||||
if not len(all_tasks):
|
||||
log.debug('no more scheduled tasks, stopping after this kick.')
|
||||
log.debug("no more scheduled tasks, stopping after this kick.")
|
||||
stop_after_this_kick = True
|
||||
|
||||
elif all(task.done() for task in all_tasks):
|
||||
log.debug('all %i tasks are done, fetching results and stopping after this kick.',
|
||||
len(all_tasks))
|
||||
log.debug(
|
||||
"all %i tasks are done, fetching results and stopping after this kick.",
|
||||
len(all_tasks),
|
||||
)
|
||||
stop_after_this_kick = True
|
||||
|
||||
# Clean up circular references between tasks.
|
||||
@@ -99,12 +102,12 @@ def kick_async_loop(*args) -> bool:
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
res = task.result()
|
||||
log.debug(' task #%i: result=%r', task_idx, res)
|
||||
log.debug(" task #%i: result=%r", task_idx, res)
|
||||
except asyncio.CancelledError:
|
||||
# No problem, we want to stop anyway.
|
||||
log.debug(' task #%i: cancelled', task_idx)
|
||||
log.debug(" task #%i: cancelled", task_idx)
|
||||
except Exception:
|
||||
print('{}: resulted in exception'.format(task))
|
||||
print("{}: resulted in exception".format(task))
|
||||
traceback.print_exc()
|
||||
|
||||
# for ref in gc.get_referrers(task):
|
||||
@@ -117,26 +120,26 @@ def kick_async_loop(*args) -> bool:
|
||||
|
||||
|
||||
def ensure_async_loop():
|
||||
log.debug('Starting asyncio loop')
|
||||
log.debug("Starting asyncio loop")
|
||||
result = bpy.ops.asyncio.loop()
|
||||
log.debug('Result of starting modal operator is %r', result)
|
||||
log.debug("Result of starting modal operator is %r", result)
|
||||
|
||||
|
||||
def erase_async_loop():
|
||||
global _loop_kicking_operator_running
|
||||
|
||||
log.debug('Erasing async loop')
|
||||
log.debug("Erasing async loop")
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.stop()
|
||||
|
||||
|
||||
class AsyncLoopModalOperator(bpy.types.Operator):
|
||||
bl_idname = 'asyncio.loop'
|
||||
bl_label = 'Runs the asyncio main loop'
|
||||
bl_idname = "asyncio.loop"
|
||||
bl_label = "Runs the asyncio main loop"
|
||||
|
||||
timer = None
|
||||
log = logging.getLogger(__name__ + '.AsyncLoopModalOperator')
|
||||
log = logging.getLogger(__name__ + ".AsyncLoopModalOperator")
|
||||
|
||||
def __del__(self):
|
||||
global _loop_kicking_operator_running
|
||||
@@ -153,8 +156,8 @@ class AsyncLoopModalOperator(bpy.types.Operator):
|
||||
global _loop_kicking_operator_running
|
||||
|
||||
if _loop_kicking_operator_running:
|
||||
self.log.debug('Another loop-kicking operator is already running.')
|
||||
return {'PASS_THROUGH'}
|
||||
self.log.debug("Another loop-kicking operator is already running.")
|
||||
return {"PASS_THROUGH"}
|
||||
|
||||
context.window_manager.modal_handler_add(self)
|
||||
_loop_kicking_operator_running = True
|
||||
@@ -162,7 +165,7 @@ class AsyncLoopModalOperator(bpy.types.Operator):
|
||||
wm = context.window_manager
|
||||
self.timer = wm.event_timer_add(0.00001, window=context.window)
|
||||
|
||||
return {'RUNNING_MODAL'}
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
def modal(self, context, event):
|
||||
global _loop_kicking_operator_running
|
||||
@@ -171,10 +174,10 @@ class AsyncLoopModalOperator(bpy.types.Operator):
|
||||
# erase_async_loop(). This is a signal that we really should stop
|
||||
# running.
|
||||
if not _loop_kicking_operator_running:
|
||||
return {'FINISHED'}
|
||||
return {"FINISHED"}
|
||||
|
||||
if event.type != 'TIMER':
|
||||
return {'PASS_THROUGH'}
|
||||
if event.type != "TIMER":
|
||||
return {"PASS_THROUGH"}
|
||||
|
||||
# self.log.debug('KICKING LOOP')
|
||||
stop_after_this_kick = kick_async_loop()
|
||||
@@ -182,29 +185,33 @@ class AsyncLoopModalOperator(bpy.types.Operator):
|
||||
context.window_manager.event_timer_remove(self.timer)
|
||||
_loop_kicking_operator_running = False
|
||||
|
||||
self.log.debug('Stopped asyncio loop kicking')
|
||||
return {'FINISHED'}
|
||||
self.log.debug("Stopped asyncio loop kicking")
|
||||
return {"FINISHED"}
|
||||
|
||||
return {'RUNNING_MODAL'}
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
class AsyncModalOperatorMixin:
|
||||
async_task = None # asyncio task for fetching thumbnails
|
||||
signalling_future = None # asyncio future for signalling that we want to cancel everything.
|
||||
log = logging.getLogger('%s.AsyncModalOperatorMixin' % __name__)
|
||||
signalling_future = (
|
||||
None # asyncio future for signalling that we want to cancel everything.
|
||||
)
|
||||
log = logging.getLogger("%s.AsyncModalOperatorMixin" % __name__)
|
||||
|
||||
_state = 'INITIALIZING'
|
||||
_state = "INITIALIZING"
|
||||
stop_upon_exception = False
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.modal_handler_add(self)
|
||||
self.timer = context.window_manager.event_timer_add(1 / 15, window=context.window)
|
||||
self.timer = context.window_manager.event_timer_add(
|
||||
1 / 15, window=context.window
|
||||
)
|
||||
|
||||
self.log.info('Starting')
|
||||
self.log.info("Starting")
|
||||
self._new_async_task(self.async_execute(context))
|
||||
|
||||
return {'RUNNING_MODAL'}
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
async def async_execute(self, context):
|
||||
"""Entry point of the asynchronous operator.
|
||||
@@ -215,7 +222,7 @@ class AsyncModalOperatorMixin:
|
||||
|
||||
def quit(self):
|
||||
"""Signals the state machine to stop this operator from running."""
|
||||
self._state = 'QUIT'
|
||||
self._state = "QUIT"
|
||||
|
||||
def execute(self, context):
|
||||
return self.invoke(context, None)
|
||||
@@ -223,46 +230,50 @@ class AsyncModalOperatorMixin:
|
||||
def modal(self, context, event):
|
||||
task = self.async_task
|
||||
|
||||
if self._state != 'EXCEPTION' and task and task.done() and not task.cancelled():
|
||||
if self._state != "EXCEPTION" and task and task.done() and not task.cancelled():
|
||||
ex = task.exception()
|
||||
if ex is not None:
|
||||
self._state = 'EXCEPTION'
|
||||
self.log.error('Exception while running task: %s', ex)
|
||||
self._state = "EXCEPTION"
|
||||
self.log.error("Exception while running task: %s", ex)
|
||||
if self.stop_upon_exception:
|
||||
self.quit()
|
||||
self._finish(context)
|
||||
return {'FINISHED'}
|
||||
return {"FINISHED"}
|
||||
|
||||
return {'RUNNING_MODAL'}
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
if self._state == 'QUIT':
|
||||
if self._state == "QUIT":
|
||||
self._finish(context)
|
||||
return {'FINISHED'}
|
||||
return {"FINISHED"}
|
||||
|
||||
return {'PASS_THROUGH'}
|
||||
return {"PASS_THROUGH"}
|
||||
|
||||
def _finish(self, context):
|
||||
self._stop_async_task()
|
||||
context.window_manager.event_timer_remove(self.timer)
|
||||
|
||||
def _new_async_task(self, async_task: typing.Coroutine, future: asyncio.Future = None):
|
||||
def _new_async_task(
|
||||
self, async_task: typing.Coroutine, future: asyncio.Future = None
|
||||
):
|
||||
"""Stops the currently running async task, and starts another one."""
|
||||
|
||||
self.log.debug('Setting up a new task %r, so any existing task must be stopped', async_task)
|
||||
self.log.debug(
|
||||
"Setting up a new task %r, so any existing task must be stopped", async_task
|
||||
)
|
||||
self._stop_async_task()
|
||||
|
||||
# Download the previews asynchronously.
|
||||
self.signalling_future = future or asyncio.Future()
|
||||
self.async_task = asyncio.ensure_future(async_task)
|
||||
self.log.debug('Created new task %r', self.async_task)
|
||||
self.log.debug("Created new task %r", self.async_task)
|
||||
|
||||
# Start the async manager so everything happens.
|
||||
ensure_async_loop()
|
||||
|
||||
def _stop_async_task(self):
|
||||
self.log.debug('Stopping async task')
|
||||
self.log.debug("Stopping async task")
|
||||
if self.async_task is None:
|
||||
self.log.debug('No async task, trivially stopped')
|
||||
self.log.debug("No async task, trivially stopped")
|
||||
return
|
||||
|
||||
# Signal that we want to stop.
|
||||
@@ -278,14 +289,14 @@ class AsyncModalOperatorMixin:
|
||||
try:
|
||||
loop.run_until_complete(self.async_task)
|
||||
except asyncio.CancelledError:
|
||||
self.log.info('Asynchronous task was cancelled')
|
||||
self.log.info("Asynchronous task was cancelled")
|
||||
return
|
||||
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
self.async_task.result() # This re-raises any exception of the task.
|
||||
except asyncio.CancelledError:
|
||||
self.log.info('Asynchronous task was cancelled')
|
||||
self.log.info("Asynchronous task was cancelled")
|
||||
except Exception:
|
||||
self.log.exception("Exception from asynchronous task")
|
||||
|
||||
|
Reference in New Issue
Block a user