11

Amazon の Elastic Map Reduce で Python プログラムを実行するために、Yelpの (素晴らしい) mrjobライブラリを使用しています。標準の python ライブラリの subprocess に依存します。python2.7.2を実行している私のMacから、すべてが期待どおりに機能します

ただし、Ubuntu LTS 11.04 で python2.7.2 とまったく同じコードを使用するように切り替えたとき、奇妙なことに遭遇しました。

mrjob はジョブをロードし、subprocess を使用してその子プロセスとの通信を試み、次のエラーを生成します。

      ファイル "/usr/local/lib/python2.7/dist-packages/mrjob-0.3.1-py2.7.egg/mrjob/emr.py"、1212 行目、_build_steps
        steps = self._get_steps()
      ファイル "/usr/local/lib/python2.7/dist-packages/mrjob-0.3.1-py2.7.egg/mrjob/runner.py"、1003 行目、_get_steps 内
        stdout、stderr = steps_proc.communicate()
      ファイル「/usr/lib/python2.7/subprocess.py」、754行目、通信中
        return self._communicate(入力)
      ファイル「/usr/lib/python2.7/subprocess.py」、1302行目、_communicate
        stdout, stderr = self._communicate_with_poll(input)
      ファイル "/usr/lib/python2.7/subprocess.py"、1332 行目、_communicate_with_poll
        ポーラー = select.poll()
    AttributeError: 'module' オブジェクトに属性 'poll' がありません

これは、mrjob ではなくサブプロセスの問題のようです。

/usr/lib/python2.7/subprocess.py を掘り下げたところ、インポート中に次のように実行されることがわかりました。

    mswindows の場合:
        ... をちょきちょきと切る ...
    そうしないと:
        選択をインポート
        _has_poll = hasattr(選択、「投票」)

それを編集して、実際に _has_poll==True が設定されていることを確認しました。これは正しいです。コマンドラインで簡単に確認できます。

しかし、実行が進んで Popen._communicate_with_poll を使用すると、select モジュールが変更されました。これは、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__'、
    「__パッケージ__」、「エラー」、「選択」]

「投票」と呼ばれる属性がありません!?!? どうやって消えたの?

そのため、_has_poll=False をハードコードすると、mrjob は喜んで作業を続行し、AWS EMR で自分のジョブを実行し、サブプロセスで communicate_with_select を使用しています...そして手作業で変更された標準ライブラリで立ち往生しています...

何かアドバイス?:-)

4

2 に答える 2

2

コメントの代わりに完全な回答を書いて申し訳ありません。そうしないと、コードのインデントが失われます。

何かがあなたのコードに非常に厳密に結びついているように見えるので、私はあなたを直接助けることはできませんが、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 実装が十分に優れていることを願っています。

于 2013-01-25T18:25:34.530 に答える