#python #ipython
Вопрос:
Если я напишу
ls *.txt
в ячейку в блокноте IPython, затем он правильно выполняется. Однако, если я попытаюсь преобразовать ячейку с помощью TransformerManager().transform_cell
, ничего не произойдет, и я получу недопустимый синтаксис Python:
>>> from IPython.core.inputtransformer2 import TransformerManager
>>> import ast
>>> TransformerManager().transform_cell('ls *.txt')
'ls *.txtn'
>>> ast.parse('ls *.txtn')
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"
То, что я ищу, — это способ обнаружения автоматических машин без выполнения кода
Комментарии:
1. Я полагаю, вам нужно выяснить, кто/что занимается
automagics
этим . Это может быть особенностью REPL высокого уровня, которая сравнивает начало строки с доступнымmagics
.TransformerManager
Код доступен для чтения.2. Обратите внимание, что это
x=ls *.py
также приводит к синтаксической ошибке, хотяx=!lis *.py
это нормально. Это начало линии получает специальную обработку. Та же проблема, еслиls
это одна из нескольких строк в ячейке или многострочный ввод.3. Кроме того, чтобы получить эквивалентный код, вам нужно использовать a
%
вместо a!
.TransformerManager().transform_cell('%ls *.txt')
->"get_ipython().run_line_magic('ls', '*.txt')n"
Ответ №1:
Автоматизация-это особенность работающего ядра, а не синтаксис. Например, 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
Под капотом, насколько я понимаю, когда ячейка выдает определенные ошибки , такие как SyntaxError
или NameError
, она отправляется на предварительные фильтры, и если ее можно преобразовать в магию, она улавливается предварительным фильтром AutoMagicChecker
и преобразуется. Мое понимание в основном основано на этом комментарии к проблеме IPython GitHub:
Входные преобразователи применяются построчно, но фильтры предварительной очистки применяются только при запуске кода. Таким образом, «недопустимая» [недопустимая строка] запускает попытку выполнения, а затем включаются предварительные фильтры и могут преобразовать ее в допустимый код.
— Томас Клюйвер, 11 июля 2015 года
Теперь, если у вас есть работающее ядро, вы могли бы использовать предфильтры, что-то вроде этого:
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', '')"
Комментарии:
1. Отличный ответ. Когда вы пишете «если у вас есть работающее ядро» — что, если у меня его нет? В конце концов, я буду запускать это в скрипте Python — как я могу запустить ядро изнутри, чтобы подключиться к нему
get_ipython
?2. Хм, я не уверен. Вы рассматривали возможность написания сценария IPython вместо этого?