def reenter(self, text, separate=False): """ Reenter is useful when we have to leave the spinner context manager but want to return to the same level we were before: with spinner.group('First Group') as gp: gp.write('Message 1') gp.write('Message 2') with gp.group('Second Group') as gp: gp.write('Message 3') gp.write('Message 4') # Some Other Write Logic... with spinner.group('Third Group', reenter=True) as gp: gp.write('Message 5') The above would output something like: ✔ First Group > Message 1 > Message 2 ✔ Second Group > Message 3 > Message 4 ✔ Third Group > Message 5 """ if separate: Cursor.newline() youngest = self._find_youngest_descendant() with youngest._parent.child(text) as desc: yield desc
def child(self, text, separate=True): """ [x] NOTE: -------- In general, things do not seem to work as well for cases when we chain the context managers: >>> with self._child(text) as group: >>> self._children.append(group) >>> yield group Not sure why, but it does mess with things a tiny bit. """ if separate: Cursor.newline() child = self._child(text) self._children.append(child) # [x] NOTE: This does not work perfectly if we reenter the cursor, but # at least does not mess up the spinner. That is why we use strict # mode to raise exceptions if you try to print. # Don't Silence STDOUT for now - makes debugging difficult. We want # to be able to temporarily disable the spinner. # with Cursor.silence_stdout(swallow=True): try: child.start() yield child finally: child.done()
def wrapped(instance, *args, **kwargs): instance.loop = asyncio.get_event_loop() user = instance.get_user() setattr(instance.loop, 'user', user) new_args = (user, ) + args Cursor.newline() return func(instance, *new_args, **kwargs)
async def shutdown(loop, spinner): """ The shutdown method that is tied to the Application hooks only accepts `app` as an argument, and we need the shutdown method tied to the exception hook to accept `loop`. Race conditions can sometimes lead to multiple shutdown attempts, which can raise errors due to the loop state. We check the global _shutdown status to make sure we avoid this and log in case it is avoidable. """ global _shutdown if _shutdown: spinner.warning('Instattack Already Shutdown...') return _shutdown = True async def shutdown_database(loop, child): with child.child('Closing DB Connections'): await tortoise.Tortoise.close_connections() async def shutdown_outstanding_tasks(loop, child): with child.child('Shutting Down Outstanding Tasks') as grandchild: futures = await cancel_remaining_tasks() if len(futures) != 0: with grandchild.child( f'Cancelled {len(futures)} Leftover Tasks' ) as great_grandchild: log_tasks = futures[:20] for i, task in enumerate(log_tasks): if task_is_third_party(task): great_grandchild.write( f'{task._coro.__name__} (Third Party)') else: great_grandchild.write(f'{task._coro.__name__}') if len(futures) > 20: great_grandchild.write("...") else: grandchild.write(f'No Leftover Tasks to Cancel') await shutdown_outstanding_tasks(loop, spinner) await shutdown_database(loop, spinner) Cursor.newline()
def start(self): if sys.stdout.isatty(): Cursor.hide() self._spin_thread = threading.Thread(target=self._spin) self._spin_thread.start()
def _move_to_head(self): i = 0 while i < self.lines: Cursor.move_up() i += 1
def _move_to_newline(self): i = 0 while i < self.lines: Cursor.move_down() i += 1 Cursor.newline()
def _print(self, text): with self._temporary_newline(): Cursor.overwrite(text, newline=False) Cursor.carriage_return()
def _print_head(cls, text): Cursor.overwrite(text, newline=False) Cursor.carriage_return()
def wrapped(instance, *args, **kwargs): instance.loop = asyncio.get_event_loop() new_args = (instance.app.pargs.username, ) + args Cursor.newline() return func(instance, *new_args, **kwargs)
def wrapped(instance, *args, **kwargs): instance.loop = asyncio.get_event_loop() Cursor.newline() return func(instance, *args, **kwargs)