2015-03-19 3 views
2

Я хочу создать удобный простой способ подключения удаленного сценария Python удаленно (через сокеты файлов, TCP или что-то еще) для получения удаленной интерактивной оболочки.Обеспечить удаленную оболочку для скрипта Python

Я думал, что это будет легко через IPython или так. Однако на самом деле я не нашел хорошего примера. Я попытался запустить IPython.embed_kernel(), но это блокировка. Поэтому я попытался запустить это в другом потоке, но у меня было много странных побочных эффектов для остальной части моего сценария, и я не хочу никаких побочных эффектов (без замены sys.stdout, sys.stderr, sys.excepthook или что-то еще), и это также не сработало - Я не мог соединиться. Я нашел this related bug report и this code snippet, которые предлагают использовать mock.patch('signal.signal'), но это также не сработало. Кроме того, зачем мне это нужно - я также не хочу, чтобы IPython регистрировал любые обработчики сигналов.

Есть также такие хаки, как pyringe и мой собственный pydbattach, чтобы прикрепить к некоторому запущенному экземпляру Python, но они кажутся слишком взломанными.

Может быть QdbRemotePythonDebugger может мне помочь?

ответ

1

Мое настоящее решение - установить ядро ​​Zython IPython. Я не просто использовать

IPython.embed_kernel() 

, потому что имеет много побочных эффектов, таких как возиться с sys.stdout, sys.stderr, sys.excepthook, signal.signal, и т.д., и я не хочу, чтобы эти побочные эффекты. Кроме того, embed_kernel() блокируется и на самом деле не работает из отдельного потока (см. here).

Итак, я придумал этот код, который, на мой взгляд, слишком сложный. (Вот почему я создал запрос функции here.)

def initIPythonKernel(): 
    # You can remotely connect to this kernel. See the output on stdout. 
    try: 
    import IPython.kernel.zmq.ipkernel 
    from IPython.kernel.zmq.ipkernel import Kernel 
    from IPython.kernel.zmq.heartbeat import Heartbeat 
    from IPython.kernel.zmq.session import Session 
    from IPython.kernel import write_connection_file 
    import zmq 
    from zmq.eventloop import ioloop 
    from zmq.eventloop.zmqstream import ZMQStream 
    IPython.kernel.zmq.ipkernel.signal = lambda sig, f: None # Overwrite. 
    except ImportError, e: 
    print "IPython import error, cannot start IPython kernel. %s" % e 
    return 
    import atexit 
    import socket 
    import logging 
    import threading 

    # Do in mainthread to avoid history sqlite DB errors at exit. 
    # https://github.com/ipython/ipython/issues/680 
    assert isinstance(threading.currentThread(), threading._MainThread) 
    try: 
    connection_file = "kernel-%s.json" % os.getpid() 
    def cleanup_connection_file(): 
     try: 
     os.remove(connection_file) 
     except (IOError, OSError): 
     pass 
    atexit.register(cleanup_connection_file) 

    logger = logging.Logger("IPython") 
    logger.addHandler(logging.NullHandler()) 
    session = Session(username=u'kernel') 

    context = zmq.Context.instance() 
    ip = socket.gethostbyname(socket.gethostname()) 
    transport = "tcp" 
    addr = "%s://%s" % (transport, ip) 
    shell_socket = context.socket(zmq.ROUTER) 
    shell_port = shell_socket.bind_to_random_port(addr) 
    iopub_socket = context.socket(zmq.PUB) 
    iopub_port = iopub_socket.bind_to_random_port(addr) 
    control_socket = context.socket(zmq.ROUTER) 
    control_port = control_socket.bind_to_random_port(addr) 

    hb_ctx = zmq.Context() 
    heartbeat = Heartbeat(hb_ctx, (transport, ip, 0)) 
    hb_port = heartbeat.port 
    heartbeat.start() 

    shell_stream = ZMQStream(shell_socket) 
    control_stream = ZMQStream(control_socket) 

    kernel = Kernel(session=session, 
        shell_streams=[shell_stream, control_stream], 
        iopub_socket=iopub_socket, 
        log=logger) 

    write_connection_file(connection_file, 
          shell_port=shell_port, iopub_port=iopub_port, control_port=control_port, hb_port=hb_port, 
          ip=ip) 

    print "To connect another client to this IPython kernel, use:", \ 
      "ipython console --existing %s" % connection_file 
    except Exception, e: 
    print "Exception while initializing IPython ZMQ kernel. %s" % e 
    return 

    def ipython_thread(): 
    kernel.start() 
    try: 
     ioloop.IOLoop.instance().start() 
    except KeyboardInterrupt: 
     pass 

    thread = threading.Thread(target=ipython_thread, name="IPython kernel") 
    thread.daemon = True 
    thread.start() 

Другие альтернативы прикрепиться к управлению процессом CPython без его готовили заранее. Обычно они используют возможности отладки ОС (или используют gdb/lldb) для присоединения к собственному процессу CPython, а затем вводят некоторый код или просто анализируют собственные стеки потоков CPython.

Вот и другие варианты, где вы подготовить сценарий Python заранее, чтобы слушать на некоторых (TCP/файла) гнездо для обеспечения интерфейса для удаленной отладки и/или просто оболочки Python/REPL.

Некоторые обзоры и собранные примеры кода: (. Этот обзор от here)

Смежные вопросы