运行 来自 Ada 程序的简单 Python 脚本

Running a simple Python script from Ada program

是否有人可以通过最简单的方法从 Ada 项目中 运行 Python 脚本?

本例中的 Python 脚本只有循环打印和睡眠,因此每次迭代都应打印参数。

我使用的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 打印输出仅在执行结束时立即打印。

我知道有一个基于 GNATCOLL 的解决方案(来自 Ada 的 运行 Python),但我找不到 运行 它的任何示例。

更新

澄清一下。 所以我会尽量简化这个问题。我想在 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 脚本直到结束。这不应该发生。

那么,请问我该如何解决这个问题?

下面是一个可能有帮助的示例(在 Linux 上使用 GNAT CE 2019 进行了测试)。它基于 GNAT.Expect 包和 AdaCore's Gem articles 之一中给出的示例。在该示例中,生成了一个新进程并自动连接了管道。

两个备注:

  • 运行 禁用 I/O 缓冲(使用 -u 选项)的 python 解释器很重要。如果这是不可取的,那么您也可以在 Python 3 中的 print 语句中使用 flush 选项,即 print(..., flush=True)。如果您不禁用 I/O 缓冲或刷新 print 后面的 I/O 缓冲区,您将 运行 超时。

  • Python 脚本目前刚刚通过 Close 语句终止(它只是在 Linux 上发送 SIGKILL 信号) .

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).