Запуск простого Python скрипта из программы Ada - PullRequest
0 голосов
/ 03 апреля 2020

Есть ли у кого-нибудь самый простой способ запустить скрипт Python из проекта Ada?

Скрипт Python в этом случае имеет печать только в oop, с sleep, поэтому на каждой итерации должны выводиться аргументы.

Используемый мной сценарий Python:

import sys
import time

for index in range(10):
    print(sys.argv)
    time.sleep(1)

При подходе, который я пытаюсь запустить, он запускается как пакетный сценарий, поэтому с использованием

with Text_IO;
with Interfaces.C; use Interfaces.C;
procedure systest2 is
   function Sys (Arg : Char_Array) return Integer;
   pragma Import(C, Sys, "system");
   Ret_Val : Integer;
begin
   Ret_Val := Sys(To_C("python testpy.py arg1 arg2"));
end systest2;

Проблема в том, что выполнение блокирует скрипт, а это означает, что распечатки Python печатаются только в конце выполнения.

Я знаю, что Существует решение (запустить Python из Ады) на основе GNATCOLL, но я не смог найти ни одного примера для его запуска.

Обновление

Просто для прояснить. Поэтому я постараюсь немного упростить вопрос. Я хочу сделать эквивалент этого в C:

#include <stdio.h>
#include <stdlib.h>
int main(){
  system("python testpy.py ddddd");
  return 0;
}

В этом случае он не блокирует распечатки testpy.py.

Но я делаю это

with Interfaces.C; use Interfaces.C;
procedure systest2 is
   function Sys (Arg : Char_Array) return Integer;
   pragma Import(C, Sys, "system");
   Ret_Val : Integer;
begin
   Ret_Val := Sys(To_C("python testpy.py arg1 arg2"));
end systest2;

, который блокирует скрипт testpy.py до конца. Этого не должно быть.

Итак, пожалуйста, как мне это исправить?

1 Ответ

3 голосов
/ 04 апреля 2020

Ниже приведен пример, который может помочь (протестировано с GNAT CE 2019 на Linux). Он основан на пакете GNAT.Expect и примере, приведенном в одной из статей о драгоценных камнях AdaCore . В этом примере создается новый процесс, и трубы автоматически подключаются.

Два замечания:

  • Важно запустить интерпретатор python с отключенной буферизацией ввода / вывода (используя опцию -u). Если это нежелательно, вы также можете использовать опцию flu sh в операторе print в Python 3, т.е. print(..., flush=True). Если вы не отключите буферизацию ввода-вывода или flu sh буфер ввода-вывода за print, у вас возникнут тайм-ауты.

  • Сценарий Python , на данный момент, просто убит с помощью оператора Close (он просто посылает сигнал SIGKILL на Linux).

main.adb

with Ada.Text_IO; use Ada.Text_IO;
with GNAT.Expect; use GNAT.Expect;
with GNAT.OS_Lib; use GNAT.OS_Lib;

procedure Main is

   Command : constant String := "python -u test.py 123";
   Pd      : Process_Descriptor;
   Args    : Argument_List_Access;
   Result  : Expect_Match;

begin

   Args := Argument_String_To_List (Command);

   Non_Blocking_Spawn
      (Pd,
       Command     => Args (Args'First).all,
       Args        => Args (Args'First + 1 .. Args'Last),
       Buffer_Size => 0);  

   for I in 1 .. 10 loop

      Expect (Pd, Result, Regexp => "\d+", Timeout => 2_000);

      case Result is    
         when Expect_Timeout =>
            Put_Line ("Expect timed out.");   
         when 1  =>
            Put_Line ("Received: " & Expect_Out_Match (Pd));
         when others =>
            raise Program_Error;            
      end case;

      Put_Line ("Doing other stuff...");

   end loop;

   Close (Pd);
   Free (Args);

exception
   when Process_Died =>

      Put_Line ("Process died.");
      Close (Pd);
      Free (Args);

end Main;

test.py

import sys
import time

while True:

    print(sys.argv[1])
    time.sleep(1)

выход

$ ./main
Received: 123
Doing other stuff...
Received: 123
Doing other stuff...
Received: 123

(repeated another 7 times).
...