Jak zintegrować samodzielny skrypt Pythona z aplikacją Rails?

Mam program, który ma małą strukturę plików i jest uruchamiany za pomocą

python do_work.py foo bar

Chcę, aby moi użytkownicy rails nacisnęli przycisk i zrobili to dla nich, z wynikiem albo przesłanym gdzieś, albo po prostu rzuconym do nich jako link do pobrania lub coś w tym rodzaju-Wyjście do_work.py (powiedzmy, to result.txt)

Chcę również wyjaśnić, że skrypt powoduje utworzenie na systemie plików 3 oddzielnych plików, które nie są plikami tekstowymi (co nie powinno mieć znaczenia i to nie problem)

Jaki jest najlepszy sposób, aby to zrobić? Czy rake może uruchomić exec Python? Co ważniejsze, czy jest to wykonalne na heroku?

Mam zainstalowany Python w moim systemie, ale odpowiedź dostarczona przez sockmonk nie działa - zwraca zero. Pamiętaj, że inne polecenia takie jak ls wydają się działać.

Czy to może być problem z uprawnieniami?

def index
    value = %x( python --version )
    render :text => value
end

Nawiasem mówiąc, próbuję to w irb:

%x(python)

Wyświetla Terminal Pythona wewnątrz irb. Nie będzie weź params z jakiegokolwiek powodu jednak.

Author: Kevin Guan, 2013-04-30

5 answers

Twoja metoda index nie działa, ponieważ python --version wysyła swoją wersję na STDERR, a nie na STDOUT. Jeśli nie musisz rozdzielać tych strumieni, możesz po prostu przekierować STDERR na STDOUT:

value = %x(python --version 2>&1)

To wywołanie jest synchroniczne, więc po uruchomieniu skryptu (python do_work.py foo bar 2>&1) Powinieneś być w stanie odczytać wytworzone przez niego pliki.

Jeśli skrypt z jakiegoś powodu nie jest w stanie utworzyć plików, zobaczysz teraz wyjątek w zmiennej value, ponieważ komunikaty o błędach są zwykle wysyłane do STDERR.

Jeśli chcesz oddzielić STDERR od STDOUT, użyj modułu Open3.

Uważaj, że uruchomienie skryptu zajmuje trochę czasu, więc wywołania mogą się nakładać. Przydałaby mi się kolejka, żeby temu zapobiec.

I nie zapomnij sprawdzić danych wprowadzanych przez użytkownika. Nigdy nie przekazuj go bezpośrednio do skryptu.

 26
Author: utapyngo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-05 04:33:59

To częściowo zależy od formatu danych. Jeśli nie jest zbyt długi i może być renderowany bezpośrednio w przeglądarce, możesz po prostu zrobić coś takiego w kontrolerze rails:

result = `python do_work.py foo bar`
render :text => result

I zakładając, że wynik jest zwykłym tekstem ASCII, wynik trafi bezpośrednio do ich przeglądarki. Jeśli params do do_work.py pochodzą od użytkownika, musisz je najpierw zweryfikować, więc nie skończysz tworząc paskudną lukę dla siebie. Użycie wywołania system() byłoby prawdopodobnie bezpieczniejsze w tym case.

Jeśli chcesz wysłać wyniki z powrotem jako plik, spójrz na klasy Tempfile ruby do tworzenia pliku (w sposób, który nie pozostanie na zawsze), i polecenia rails send_file i send_data dla kilku różnych opcji, aby wysłać wyniki w ten sposób.

 4
Author: sockmonk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-30 18:01:36

ODPOWIEDŹ z utapyngo jest pokrycie prawie wszystko, co musisz wiedzieć. Odpowiem na tą część:

Nawiasem mówiąc, próbując tego w irb: %x (python) Przywołuje Terminal Pythona wewnątrz irb. To nie zajmie params z jakiegokolwiek powodu jednak.

Aby przekazać parametry do skryptu Pythona, po prostu go przekaż. Przykład:

[fotanus@thing ~]$ python a.py 
args:
['a.py']
[fotanus@thing ~]$ irb
1.8.7 :001 > %x(python a.py foo bar)
 => "args:\n['a.py', 'foo', 'bar']\n" 

Działa to na ruby 1.8, 1.9 i 2.0.

 3
Author: fotanus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-07 20:22:43

To zależy jak głęboko chcesz zintegrować skrypt Pythona. Istnieją sposoby na wywołanie modułów Pythona bezpośrednio z ruby.

Http://www.goto.info.waseda.ac.jp / ~fukusima/ruby/python-e.html

Dałoby to korzyści z uzyskania wyjścia bezpośrednio ze skryptu Pythona zamiast przechodzenia przez urządzenie We / Wy.

 1
Author: Bjoern Rennhak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-10 00:44:32

Zrobiłbym coś takiego.

Asynchronicznie wykonuje to zadanie w tle. A gdy wynik jest gotowy, zgłoś go użytkownikowi.

Można to osiągnąć używając Open3 i delayed_job gem.

Spójrz na metodę popen3 w module Open3.

Open3.popen3([env,] cmd... [, opts]) {|stdin, stdout, stderr, wait_thr|
  pid = wait_thr.pid # pid of the started process.
  ...
  exit_status = wait_thr.value # Process::Status object returned.
}

W Twoim przypadku możesz zmienić Open3.popen3 na coś w rodzaju następującego

Open3.popen3("python do_work.py foo bar"){
  ...
  # mechanism for reporting like setting a flag in database system
  # or queue system
}

Uwaga: Należy podać pełną ścieżkę to your python script

A następnie użyj Gem delayed_job, aby uruchomić to jako zadanie w tle.

Powinieneś również mieć mechanizm ankiety, który będzie sprawdzał system, aby sprawdzić, czy flaga jest ustawiona, co oznaczałoby, że wynik jest gotowy, a następnie podać go użytkownikowi.

 1
Author: Josnidhin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-10 02:23:12