30

我有一个程序,它有一个小文件结构,然后使用

python do_work.py foo bar

我希望我的 Rails 用户按下一个按钮并让他们发生这种情况,结果要么上传到某个地方,要么只是作为下载链接或类似的东西扔给他们 - 输出do_work.py(比如说,它是result.txt

我还想澄清一下,该脚本会导致在文件系统上创建 3 个单独的文件,这些文件不是文本文件(这无关紧要,也不是真正的问题)

最好的方法是什么?rake 可以运行 exec Python 吗?更重要的是,这在heroku上可行吗?

我的系统上安装了 Python,但 sockmonk 提供的答案似乎不起作用 - 它返回 nil。请注意,其他命令ls似乎有效。

会不会是权限问题?

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

顺便说一句,尝试这个irb

%x(python)

在 irb 内部启动 Python 终端。但是,无论出于何种原因,它都不会使用参数。

4

5 回答 5

27

您的index方法不起作用,因为python --version将其版本输出到 STDERR,而不是 STDOUT。如果您不需要分离这些流,您可以将 STDERR 重定向到 STDOUT:

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

此调用是同步的,因此在运行脚本 ( python do_work.py foo bar 2>&1) 后,您应该能够读取它生成的文件。

如果脚本由于某种原因无法创建文件,您现在将在value变量中看到异常,因为错误消息通常会发送到 STDERR。

如果要将 STDERR 与 STDOUT 分开,请使用Open3模块。

请注意,脚本需要一些时间才能运行,因此调用可能会重叠。我会在这里使用队列来防止这种情况。

并且不要忘记检查用户输入的数据。永远不要将它直接传递给脚本。

于 2013-05-05T04:33:59.150 回答
4

它部分取决于数据的格式。如果它不是太长并且可以直接在浏览器中呈现,您可以在 rails 控制器中执行以下操作:

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

假设结果是纯 ASCII 文本,结果将直接进入他们的浏览器。如果 do_work.py 的参数来自用户,那么您必须首先验证它们,这样您就不会为自己创建一个讨厌的漏洞。在这种情况下,使用 system() 调用可能会更安全。

如果您想将结果作为文件发回,请查看 ruby​​ 的 Tempfile 类来创建文件(以一种不会永远存在的方式),以及 rails 的 send_file 和 send_data 命令,以获得一些不同的选项来发回结果那样。

于 2013-04-30T18:01:36.437 回答
3

utapyngo 的答案几乎涵盖了您需要知道的所有内容。我将回答这部分:

顺便说一下,在 irb 中尝试这个: %x(python) 在 irb 内部启动 python 终端。但是,无论出于何种原因,它都不会使用参数。

要将参数传递给您的 python 脚本,只需传递它。例子:

[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" 

这适用于 ruby​​ 1.8、1.9 和 2.0。

于 2013-05-07T20:22:43.883 回答
1

这取决于您想要集成 python 脚本的深度。有一些方法可以直接从 ruby​​ 调用 python 模块。

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

这将使您受益于直接从您的 python 脚本获取输出,而不是通过 I/O 设备。

于 2013-05-10T00:44:32.930 回答
1

我会做类似以下的事情。

在后台异步执行此任务。一旦结果准备好报告给用户。

实现这一目标的一种方法是使用Open3延迟作业gem。

看看 Open3 模块中的popen3方法。

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

在您的情况下,您可以将Open3.popen3语句更改为以下内容

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

注意:您应该提供 python 脚本的完整路径

然后使用delayed_job gem 将其作为后台任务运行。

您还应该有一个轮询机制,它将轮询系统以查看是否设置了标志,这意味着结果已准备好,然后将其提供给用户。

于 2013-05-10T02:16:04.130 回答