现象描述
在命令行中通过 jupyter console
进入控制台, 发现输入命令时, 不会自动弹出提示. 比如:
a = 1 # 我在第一行输入了 `a = 1`
a # 当输入第一个字母 "a" 时, 按理来说应该弹出补全提示 " = 1", 但是没有
解决方法
该操作需要修改 jupyter-console
的源文件:
-
源文件位于:
{site-packages}/jupyter_console/ptshell.py
-
在第 47 行插入以下内容:
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory # <--- HERE
示意图:
... from prompt_toolkit import __version__ as ptk_version PTK3 = ptk_version.startswith('3.') if not PTK3: # use_ayncio_event_loop obsolete in PKT3 from prompt_toolkit.eventloop.defaults import use_asyncio_event_loop from prompt_toolkit.auto_suggest import AutoSuggestFromHistory # <--- HERE from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.document import Document from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode ...
-
在第 559 行插入以下内容:
auto_suggest=AutoSuggestFromHistory(), # <--------------------------- HERE
示意图:
... # Tell prompt_toolkit to use the asyncio event loop. # Obsolete in prompt_toolkit.v3 if not PTK3: use_asyncio_event_loop() self.pt_cli = PromptSession( auto_suggest=AutoSuggestFromHistory(), # <----------------------- HERE message=(lambda: PygmentsTokens(self.get_prompt_tokens())), multiline=True, complete_style=self.pt_complete_style, editing_mode=editing_mode, lexer=PygmentsLexer(get_pygments_lexer(lexer)), prompt_continuation=( lambda width, lineno, is_soft_wrap: PygmentsTokens( self.get_continuation_tokens(width) ) ), ... ) ...
即可解决.
测试一下效果
该测试场景模拟了 A 窗口启动了 ipython 内核服务, B 窗口使用 jupyter console
连接该服务, 并获得完美的自动补全功能.
# test/ipython_service.py
from IPython import embed_kernel
def hello():
print('hello world')
embed_kernel(user_ns={
'a' : 'alpha',
'b' : 'beta',
'hello': hello,
})
打开一个命令行, 作为 A 窗口, 输入以下命令:
python test/ipython_service.py
# 控制台出现打印信息:
# to connect another client to this kernel, use:
# --existing kernel-12345.json
再新开一个命令行, 作为 B 窗口, 输入以下命令:
jupyter console --existing 12345
尝试输入以下命令, 可以观察到自动补全的效果:
a, b
a + b # 当输入 "a" 时, 会提示 ", b"
a, b, hello() # 当输入 "a" 时, 会提示 " + b"; 继续输入 "a,", 会转为提示 " b"
...
exit()
# exit(keep_kernel=False) # 断开 B 且停止 A. (默认)
# exit(keep_kernel=True) # 断开 B 但不停止 A.
附录: 研究过程
prompt-toolkit
是一个 python 库, 用来给命令行 REPL 提供上下文感知, 自动补全, 历史记录等功能. 它是 ipython 和 jupyter 的重要依赖之一.
jupyter console
与 ipython
都会启动命令行界面, 但二者在体验上存在一些不同之处, 其中最显著的就是前者没有自动补全, 而后者有, 因此使用体验受到影响. 好在本文就是为了解决这个问题的.
观察 jupyter console -h
的参数, 有一个 --no-simple-prompt
, 是用来启用 prompt-toolkit
的功能的.
按理来说 jupyter console
提供这个参数, 就应该能够使用自动补全功能, 但本人测试最新版 (截至 2023-07-01) 并没有作用, 个人怀疑是 jupyter 的一个 bug.
此外, 根据官方文档描述, 启动 jupyter console
的命令行界面后, 使用下面的命令也能激活自动补全功能:
通过阅读 jupyter_console
的源代码, 发现 jupyter_console/ptshell.py
文件确实少了 prompt_toolkit.auto_suggest.AutoSuggestFromHistory
, 所以问题就好解决了, 把它作为参数传到 ZMQTerminalInteractiveShell.pt_cli
的实例化构造中即可.