【问题标题】:IPython detect automagicsIPython 检测自动魔法
【发布时间】:2021-06-13 16:15:17
【问题描述】:

如果我写

ls *.txt

进入 IPython 笔记本中的单元格,然后它会正确执行。但是,如果我尝试使用 TransformerManager().transform_cell 转换单元格,则没有任何反应,并且我得到无效的 Python 语法:

>>> from IPython.core.inputtransformer2 import TransformerManager
>>> import ast
>>> TransformerManager().transform_cell('ls *.txt')
'ls *.txt\n'
>>> ast.parse('ls *.txt\n')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ignoring_gravity/miniconda3/envs/tmp/lib/python3.8/ast.py", line 47, in parse
    return compile(source, filename, mode, flags,
  File "<unknown>", line 1
    ls *.txt
        ^
SyntaxError: invalid syntax

有没有办法以返回有效 Python 代码的方式转换自动魔法?没有自动魔术的等效代码将被转换如下:

>>> TransformerManager().transform_cell('!ls *.txt')
"get_ipython().system('ls *.txt')\n"

我正在寻找的是一种检测自动魔法的方法运行代码

【问题讨论】:

  • 我想你需要找出谁/什么处理了automagics。它可能是高级 REPL 的一个特殊功能,将行的开头与可用的magics 进行比较。 TransformerManager 代码可供阅读。
  • 注意x=ls *.py 也会产生语法错误,而x=!lis *.py 很好。该行的开头得到特殊处理。如果ls 是单元格或多行输入中的几行之一,则同样的问题。
  • 题外话,但要获得等效代码,您需要使用% 而不是!TransformerManager().transform_cell('%ls *.txt') -> "get_ipython().run_line_magic('ls', '*.txt')\n"

标签: python ipython


【解决方案1】:

Automagics 是运行内核的一个特性,而不是语法。例如,cd 本身就是一个有效的自动魔法,除非它被 Python 名称所遮蔽,或者如果 %automagic 被禁用。

In [1]: cd
/home/wja

In [2]: cd = 'CD'

In [3]: cd
Out[3]: 'CD'

In [4]: del cd

In [5]: cd
/home/wja

In [6]: %automagic 0

Automagic is OFF, % prefix IS needed for line magics.

In [7]: cd
Traceback (most recent call last):
  File "<ipython-input-7-9c6465b4471e>", line 1, in <module>
    cd
NameError: name 'cd' is not defined

在底层,据我了解,当一个单元格抛出某些错误(如 SyntaxErrorNameError)时,它会被发送到预过滤器,如果它可以转化为魔法,它就会被预过滤器 @987654322 捕获@ 并转换。我的理解主要基于this comment on an IPython GitHub issue

输入转换器逐行应用,但预过滤器仅在代码运行时应用。所以 'invalid' [an invalid line] 会触发执行尝试,然后预过滤器介入并可能将其转换为有效代码。

--Thomas Kluyver,2015 年 7 月 11 日

现在,如果您确实有一个正在运行的内核,您可以使用预过滤器,如下所示:

In [1]: ip = get_ipython()  # The running kernel

In [3]: source = ip.prefilter('cd')  # Transform

In [4]: source
Out[4]: "get_ipython().run_line_magic('cd', '')"

In [5]: exec(source)  # Run, just to prove it works
/home/wja

或者,很长的路:

In [2]: from IPython.core.splitinput import LineInfo

In [3]: line_info = LineInfo('cd')  # Parse

In [4]: ip = get_ipython()

In [5]: ip.prefilter_manager.checkers  # List of prefilters
Out[5]:
[<EmacsChecker(priority=100, enabled=False)>,
 <MacroChecker(priority=250, enabled=True)>,
 <IPyAutocallChecker(priority=300, enabled=True)>,
 <AssignmentChecker(priority=600, enabled=True)>,
 <AutoMagicChecker(priority=700, enabled=True)>,
 <PythonOpsChecker(priority=900, enabled=True)>,
 <AutocallChecker(priority=1000, enabled=True)>]

In [6]: for checker in ip.prefilter_manager.checkers:
   ...:     handler = checker.check(line_info)
   ...:     if handler:  # Find the first one that matches
   ...:         break
   ...:

In [7]: handler
Out[7]: <IPython.core.prefilter.MagicHandler at 0x7f01e8ccc7f0>

In [10]: handler.handle(line_info)  # Transform
Out[10]: "get_ipython().run_line_magic('cd', '')"

【讨论】:

  • 优秀的答案。当你写“如果你有一个正在运行的内核”时——如果我没有怎么办?最后,我将在 Python 脚本中运行它 - 如何从其中启动内核,以便可以使用 get_ipython 连接到它?
  • 嗯,我不确定。您是否考虑过编写 IPython 脚本?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 2016-05-19
相关资源
最近更新 更多