IPython обнаруживает автоматические средства

#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 вместо этого?