python subprocess.Popen怎么能看到select.poll然后呢? (选择'module'对象没有属性'poll')

时间:2012-01-31 21:53:03

标签: python subprocess mrjob

我正在使用Yelp中的(真棒)mrjob库在Amazon的Elastic Map Reduce中运行我的python程序。它取决于标准python库中的子进程。从我的mac运行python2.7.2,一切都按预期工作

但是,当我在使用python2.7.2的Ubuntu LTS 11.04上使用完全相同的代码时,我遇到了一些奇怪的事情:

mrjob加载作业,然后尝试使用子进程与其子进程通信并生成此错误:

      File "/usr/local/lib/python2.7/dist-packages/mrjob-0.3.1-py2.7.egg/mrjob/emr.py", line 1212, in _build_steps
        steps = self._get_steps()
      File "/usr/local/lib/python2.7/dist-packages/mrjob-0.3.1-py2.7.egg/mrjob/runner.py", line 1003, in _get_steps
        stdout, stderr = steps_proc.communicate()
      File "/usr/lib/python2.7/subprocess.py", line 754, in communicate
        return self._communicate(input)
      File "/usr/lib/python2.7/subprocess.py", line 1302, in _communicate
        stdout, stderr = self._communicate_with_poll(input)
      File "/usr/lib/python2.7/subprocess.py", line 1332, in _communicate_with_poll
        poller = select.poll()
    AttributeError: 'module' object has no attribute 'poll'

这似乎是子进程的问题,而不是mrjob。

我挖到/usr/lib/python2.7/subprocess.py并发现在导入过程中它运行:

    if mswindows:
        ... snip ...
    else:
        import select
        _has_poll = hasattr(select, 'poll')

通过编辑,我确认它确实设置了_has_poll == True。这是正确的;在命令行上轻松验证。

然而,当执行过程以某种方式使用Popen._communicate_with_poll时,选择模块已经改变了!这是通过在尝试使用select.poll()之前打印dir(select)生成的。

    ['EPOLLERR', 'EPOLLET', 'EPOLLHUP', 'EPOLLIN', 'EPOLLMSG', 
    'EPOLLONESHOT', 'EPOLLOUT', 'EPOLLPRI', 'EPOLLRDBAND', 
    'EPOLLRDNORM', 'EPOLLWRBAND', 'EPOLLWRNORM', 'PIPE_BUF', 
    'POLLERR', 'POLLHUP', 'POLLIN', 'POLLMSG', 'POLLNVAL', 
    'POLLOUT', 'POLLPRI', 'POLLRDBAND', 'POLLRDNORM',
    'POLLWRBAND', 'POLLWRNORM', '__doc__', '__name__', 
    '__package__', 'error', 'select']

没有名为'民意调查'的属性!?!?它是如何消失的?

所以,我硬编码了_has_poll = False,然后mrjob愉快地继续其工作,在AWS EMR中运行我的工作,子进程使用communic_with_select ...而且我坚持使用手工修改的标准库...

有什么建议吗? : - )

2 个答案:

答案 0 :(得分:3)

我遇到了类似的问题,结果是gevent用select取代了内置的gevent.select.select模块,该模块没有poll方法(因为它是一种阻塞方法) )。 但是出于某些原因,默认情况下,gevent不修补使用subprocess的{​​{1}}。

一个简单的解决方法是将select.poll替换为subprocess

gevent.subprocess

如果在导入mrjob库之前执行此操作,它应该可以正常工作。

答案 1 :(得分:1)

很抱歉写一个完整的答案而非评论,否则我会丢失代码缩进。

我无法直接帮助你,因为某些内容似乎与你的代码紧密相关,但我可以通过依赖Python模块可以成为任意对象的事实来帮助你找到答案,尝试这样的事情:

class FakeModule(dict):
    def __init__(self, origmodule):
        self._origmodule = origmodule
    self.__all__ = dir(origmodule)

    def __getattr__(self, attr):
    return getattr(self._origmodule, attr)


    def __delattr__(self, attr):
        if attr == "poll":
            raise RuntimeError, "Trying to delete poll!"
        self._origmodule.__delattr__(attr)


def replaceSelect():
    import sys
    import select
    fakeselect = FakeModule(select)

    sys.modules["select"] = fakeselect

replaceSelect()

import select
del select.poll

你将获得如下输出:

Traceback (most recent call last):
  File "domy.py", line 27, in <module>
    del select.poll
  File "domy.py", line 14, in __delattr__
    raise RuntimeError, "Trying to delete poll!"
RuntimeError: Trying to delete poll!

通过在代码中调用replaceSelect(),你应该能够获得的追溯有人正在删除poll(),这样你就可以理解为什么了。

我希望我的FakeModule实现足够好,否则你可能需要修改它。