为 Python 脚本提供远程 shell
Provide remote shell for Python script
我想创建一个方便的简单方法来远程连接到我的 运行ning Python 脚本(通过文件套接字、TCP 或其他方式)以获得远程交互 shell。
我认为通过 IPython 左右这会很容易。但是,我并没有真正找到任何好的例子。我试图启动 IPython.embed_kernel()
,但那是阻塞的。所以我尝试 运行 在另一个线程中,但这对我的脚本的其余部分有许多奇怪的副作用,我不想要任何副作用(不替换 sys.stdout
、sys.stderr
, sys.excepthook
或其他)并且它也没有用 - 我无法连接。我发现 this related bug report and this code snippet 建议使用 mock.patch('signal.signal')
但这也没有用。另外,我为什么需要它 - 我也不希望 IPython 注册任何信号处理程序。
还有一些 hack,例如 pyringe and my own pydbattach 可以附加到某些 运行ning Python 实例,但它们似乎太 hacky 了。
也许 QdbRemotePythonDebugger 可以帮助我?
我目前的解决方案是设置一个 IPython ZMQ 内核。我不只是使用
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()
请注意,此代码现已过时。我制作了一个包 here,它应该包含更新的版本,并且可以通过 pip 安装。
附加到 运行 CPython 进程的其他替代方案,无需事先准备。那些通常使用 OS 调试功能(或使用 gdb/lldb)附加到本机 CPython 进程,然后注入一些代码或仅分析本机 CPython 线程堆栈.
这里有其他备选方案,您可以预先准备 Python 脚本来侦听某些 (tcp/file) 套接字,从而为远程调试 and/or 提供一个接口 Python shell / REPL.
- winpdb(跨平台)远程调试器
- PyCharm IDE 远程调试器,
doc
- PyDev IDE 远程调试器
- Twisted Conch Manhole,
official example,
lothar.com example,
lysator.liu.se example,
related Whosebug question,
blog.futurefoundries.com (2013)
- 很简单manhole,对相关项目也有一些概述
- ispyd
- Eric IDE
- Trepan (based on pydb)
- rpdb
- rconsole
(rfoo 的一部分)
一些概述和收集的代码示例:
- (QGIS) Example code for PyDev, Winpdb, Eric
- Python Wiki: Python debugging tools,
Python Wiki: Python debuggers
(此概述来自 here。)
我想创建一个方便的简单方法来远程连接到我的 运行ning Python 脚本(通过文件套接字、TCP 或其他方式)以获得远程交互 shell。
我认为通过 IPython 左右这会很容易。但是,我并没有真正找到任何好的例子。我试图启动 IPython.embed_kernel()
,但那是阻塞的。所以我尝试 运行 在另一个线程中,但这对我的脚本的其余部分有许多奇怪的副作用,我不想要任何副作用(不替换 sys.stdout
、sys.stderr
, sys.excepthook
或其他)并且它也没有用 - 我无法连接。我发现 this related bug report and this code snippet 建议使用 mock.patch('signal.signal')
但这也没有用。另外,我为什么需要它 - 我也不希望 IPython 注册任何信号处理程序。
还有一些 hack,例如 pyringe and my own pydbattach 可以附加到某些 运行ning Python 实例,但它们似乎太 hacky 了。
也许 QdbRemotePythonDebugger 可以帮助我?
我目前的解决方案是设置一个 IPython ZMQ 内核。我不只是使用
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()
请注意,此代码现已过时。我制作了一个包 here,它应该包含更新的版本,并且可以通过 pip 安装。
附加到 运行 CPython 进程的其他替代方案,无需事先准备。那些通常使用 OS 调试功能(或使用 gdb/lldb)附加到本机 CPython 进程,然后注入一些代码或仅分析本机 CPython 线程堆栈.
这里有其他备选方案,您可以预先准备 Python 脚本来侦听某些 (tcp/file) 套接字,从而为远程调试 and/or 提供一个接口 Python shell / REPL.
- winpdb(跨平台)远程调试器
- PyCharm IDE 远程调试器, doc
- PyDev IDE 远程调试器
- Twisted Conch Manhole, official example, lothar.com example, lysator.liu.se example, related Whosebug question, blog.futurefoundries.com (2013)
- 很简单manhole,对相关项目也有一些概述
- ispyd
- Eric IDE
- Trepan (based on pydb)
- rpdb
- rconsole (rfoo 的一部分)
一些概述和收集的代码示例:
- (QGIS) Example code for PyDev, Winpdb, Eric
- Python Wiki: Python debugging tools, Python Wiki: Python debuggers
(此概述来自 here。)