#!/usr/bin/env python
# -*- coding: utf-8 -*-
import asyncio
import subprocess
from asyncio.events import get_event_loop_policy
from typing import List, Any
try:
    # get_event_loop() is one of the most frequently called
    # functions in asyncio.  Pure Python implementation is
    # about 4 times slower than C-accelerated.
    # noinspection PyProtectedMember,PyProtectedMember
    from _asyncio import (
        _get_running_loop,
        _set_running_loop,
        get_running_loop,
        get_event_loop,
    )
except ImportError:
    # noinspection PyProtectedMember,PyProtectedMember
    from asyncio.events import (
        _get_running_loop,
        _set_running_loop,
        get_running_loop,
        get_event_loop,
    )
import logging
import multiprocessing
# from multiprocessing.process import current_process
import platform
import shlex
import threading
# from threading and _threading_local
import sys as _sys
try:
    # noinspection PyProtectedMember
    from _thread import _local as local
    # noinspection PyProtectedMember,PyProtectedMember
    from _thread import _excepthook as excepthook, _ExceptHookArgs as ExceptHookArgs
except ImportError:
    # Simple Python implementation if _thread._excepthook() is not available
    from traceback import print_exception as _print_exception
    from collections import namedtuple
    from _threading_local import local
    _ExceptHookArgs = namedtuple(
        "ExceptHookArgs", "exc_type exc_value exc_traceback thread"
    )
    def ExceptHookArgs(args):
        """Return a namedtuple of 'exc_type exc_value exc_traceback thread'."""
        return _ExceptHookArgs(*args)
    # def excepthook(args, /):
    # fun fact this is py3.8 only!
    def excepthook(*args):
        """Handle uncaught `threading.Thread.run` exception."""
        if args.exc_type == SystemExit:
            # silently ignore SystemExit
            return
        if _sys is not None and _sys.stderr is not None:
            stderr = _sys.stderr
        elif args.thread is not None:
            # noinspection PyProtectedMember
            stderr = args.thread._stderr
            if stderr is None:
                # do nothing if sys.stderr is None and sys.stderr was None
                # when the thread was created
                return
        else:
            # do nothing if sys.stderr is None and args.thread is None
            return
        if args.thread is not None:
            name = args.thread.name
        else:
            name = threading.get_ident()
        print(f"Exception in thread {name}:", file=stderr, flush=True)
        _print_exception(args.exc_type, args.exc_value, args.exc_traceback, file=stderr)
        stderr.flush()
# try:
#     from curio import Task
# except:
#     from asyncio.tasks import Task
from curio import Kernel, timeout_after, TaskTimeout
from curio.debug import logcrash, longblock
# from asyncio.tasks import current_task, all_tasks, create_task
# messes up %run
# try:
#     from trio import run as _async_run
# except:
#     from asyncio import run as _async_run
from IPython.core.getipython import get_ipython
[docs]def children():
    """Return `multiprocessing.active_children`. Simply to save the typing."""
    return multiprocessing.active_children() 
[docs]def enable_multiprocessing_logging(level=50):
    """Log to stderr."""
    logger = multiprocessing.log_to_stderr()
    logger.setLevel(level)
    return logger 
[docs]async def system_command(command_to_run):
    """Run a system command using prompt_toolkit's run_system_command.
    Examples
    --------
    ::
        In [40]: await system_command('ls')  # +NORMALIZE_WHITESPACE
        01_rehashx.py       20_aliases.py        31_yank_last_arg.py
        36_ptutils.py     cscope.out  05_log.py           21_fzf.py
        kb.py              41_numpy_init.py  event_loops.py 06_help_helpers.py
        22_alias_manager.py  bottom_toolbar.py  43_matplotlib.py
        interpreter.py 10_envvar.py        23_git_commands.py   34_completion.py
        __init__.py       repralias.py
        clipboard.py     30_readline.py       35_lexer.py
        __main__.py       tags
    .. doctest::
        >>> await _ip.pt_app.app.run_async(print('hi'))
        hi
    Whoo!
    """
    if hasattr(command_to_run, "startswith"):
        com = shlex.quote(command_to_run)
        com: List[Any] = shlex.split(com)
    else:
        if not hasattr(command_to_run, "append"):
            raise TypeError
    await get_ipython().pt_app.app.run_system_command(
        command=com, wait_for_enter=False, wait_text="", display_before_text=""
    ) 
[docs]def initialize_kernel():
    """Initialize a `curio.Kernel`."""
    return Kernel() 
[docs]async def kernel_run(command, kernel):
    return await kernel.run(
        subprocess.run(
            shlex.split(shlex.quote(command)),
            stderr=subprocess.PIPE,
            stdout=subprocess.PIPE,
        )
    ) 
[docs]async def subproc(command):
    results = []
    try:
        async with timeout_after(0.5):
            # TODO: might want to preprocess the command
            out = await subprocess.run(
                [command], stdout=subprocess.PIPE, stderr=subprocess.PIPE
            )
    except TaskTimeout as e:
        results.append("timeout")
        results.append(e.stdout)
        results.append(e.stderr)
    return results 
if __name__ == "__main__":
    # Me trying to shut the loggers up
    if len(asyncio.log.logger.root.handlers) > 0:
        asyncio.log.logger.root.handlers.pop()
    if len(asyncio.log.logger.handlers) > 0:
        asyncio.log.logger.handlers.pop()
    asyncio.log.logger.setLevel(99)
    asyncio.log.logger.root.setLevel(99)
    if len(logging.root.handlers) > 0:
        logging.root.handlers.pop()
    logging.root.setLevel(99)
    asyncio.log.logger.disabled = True
    asyncio.log.logger.root.disabled = True
    event_policy = get_event_loop_policy()
    try:
        loop = get_running_loop()
    except RuntimeError:
        # sigh
        loop = event_policy.new_event_loop()
    if not platform.platform().startswith("Win"):
        # This raises a NotImplementedError on Windows
        watcher = event_policy.get_child_watcher()