Erlport / Python STDOUT захватить эликсир - PullRequest
1 голос
/ 04 июля 2019

Я пытаюсь передать STDOUT из Python / Erlport обратно в Elixir.У меня :python звонки работают нормально, я просто хочу отправить материал STDOUT из Python обратно в Elixir для регистрации, но я не могу понять, как этого добиться.Я знаю, что возможно , хотя я использую Python 2.7.

У меня есть оболочка Genserver вокруг модуля :python, так что мой вызов работает так:

pid = Python.start()
Python.call(pid, :bridge, :register_handler, [self()]) 

Python.call выглядит следующим образом:

def call(pid, module, function, args \\ []) do
  :python.call(pid, module, function, args)
end

Все, что из :bridge (то есть bridge.py) потеряно для STDOUT, если я не возвращаю что-либо явно (очевидно, остановив функцию).Что я могу сделать, чтобы захватить STDOUT?

Моя идея состояла в том, чтобы назвать что-то вроде Python.call(pid, :builtins, :print, [self()]), но это привело к куче ошибок, и я действительно не знаю, правильное ли это направление вообще.

Я действительно хочу передатьэто в канал Феникса, но это легкая часть (я надеюсь).Любой совет?Благодаря.

Ответы [ 2 ]

1 голос
/ 05 июля 2019

Моя идея состояла в том, чтобы вызвать что-то вроде Python.call(pid, :builtins, :print, [self()]), но это привело к куче ошибок, и я действительно не знаю, правильное ли это направление вообще.

self() - это не то, куда идет вывод, скорее self() - это аргумент для print, то есть то, что выводит питон.

Я думаю, erlport может обрабатывать только вызовы MFA (модуль, функция, аргумент), и поскольку print не является функцией в python 2.7, я думаю, что вам нужно обернуть функцию вокруг print, например :

myprint.py:

def print_this(str):
    print str

Я просто хочу отправить материал STDOUT из Python обратно в Elixir для ведение журнала, но я не могу понять, как этого добиться. я знаю это возможно, хотя я использую Python 2.7

Документы erlport говорят:

В качестве удобной функции ErlPort также поддерживает перенаправление Python. STDOUT для Erlang ...

Похоже, что это настройка по умолчанию, поэтому вам не нужно ничего делать, чтобы перенаправить стандартный вывод Python на стандартный вывод elixir. Тогда возникает вопрос: «Как записать стандартный вывод эликсира в файл?»

Я могу записать эликсир stdout в файл, подобный следующему:

friends.ex:

defmodule Friends do

  use Export.Python

  def go do

    #Get path to logfile:

    priv_path = :code.priv_dir(:friends)
    logfile_path = Path.join([priv_path, "log", "mylog.log"])

    #Redirect stdout:

    {:ok, io_pid} = File.open(logfile_path, [:append])
    Process.group_leader(self(), io_pid)

    #Send output to stdout:

    IO.puts "Am I in the log file??!"

    python_path = Path.expand("lib/python") 
    {:ok, py} = Python.start(
                 python: "python2.7",
                 python_path: python_path
               )

    Python.call(py, "myprint", "print_this", ["hello world!"])
    Python.call(py, "myprint", "print_this", ["goodbye..."])

    Python.stop(py)
  end

end

Это моя структура каталогов:

friends
    /lib
      /friends
      /python
          myprint.py
      friends.ex
   /priv
      /log
          mylog.log

В iex:

~/elixir_programs/friends$ iex -S mix
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Compiling 1 file (.ex)
Interactive Elixir (1.8.2) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> Friends.go
iex(2)>

В файле журнала:

Am I in the log file??!
hello world!
goodbye...
[33m[36m:ok[0m[33m[0m

(Я не знаю, что это за хлам в последней строке. Редактировать: Хммм ... это атом :ok, окруженный какими-то другими вещами.)

Если я закомментирую все внутри go() над строкой python_path, я получу:

iex(1)> Friends.go
hello world!
goodbye...
:ok

В файле ввода / вывода erlang / elixir выполняется запуск процесса, в который отправляются запросы либо на запись в файл, либо на чтение файла. Я думаю, что stdout отправляется любому процессу group_leader, и если ввод-вывод файла, обрабатывающего процесс, является group_leader, тогда stdout отправляется в файл.

Не знаю, мешает ли что-то с group_leader, когда вы используете GenServer. В erlang docs есть предупреждение :

Лидер группы должен редко меняться в приложениях с дерево наблюдения, потому что OTP предполагает лидер группы их процессы - это их мастер приложения.

.

0 голосов
/ 04 июля 2019

Для всех, кто застрял в такой ситуации: поскольку у меня есть Genserver для экземпляра :python, я просто использовал handle_info:

def handle_info({:python, message}, session) do
  message |> String.split("\n", trim: true)
  SomeWeb.Endpoint.broadcast("log", "update", %{body: message})

  {:stop, :normal,  session}
end
...