2012年5月18日金曜日

pip searchがproxyを通さない

会社でプロキシ使っていると色々困ること多いですよね。
pythonの便利なパッケージ管理システムのpip
会社で使っていたら、searchするとエラーを吐くことが判明。
pipのバージョンは1.1。


調べてみると、pip searchがプロキシを通さないという問題があるらしい
The search command ignore proxy settings
多分こんな感じのエラーが出る。
  File "/usr/lib/python2.6/httplib.py", line 776, in _send_output
    self.send(msg)
  File "/usr/lib/python2.6/httplib.py", line 735, in send
    self.connect()
  File "/usr/lib/python2.6/httplib.py", line 716, in connect
    self.timeout)
  File "/usr/lib/python2.6/socket.py", line 500, in create_connection
    for res in getaddrinfo(host, port, 0, SOCK_STREAM):
gaierror: [Errno -2] Name or service not known

どうやらxmlrpcがproxyを使わないらしい。
解決方法が示されているが、違うチケットに投げられ、放置されているくさい

そこでリンク先の上の方に書いてあるパッチを当てる。
リンク先ではlstripを使って「http://」を削除しているが、
実はこれだと、host名の先頭にhttpのいずれかの文字があるとそれも消されてしまう。

以下修正版のdiff。

*** download.py 2012-05-17 14:58:47.800679029 +0900
--- download.py.mod20120517 2012-05-17 14:58:01.300737662 +0900
***************
*** 6,11 ****
--- 6,12 ----
  import shutil
  import sys
  import tempfile
+ import httplib
  from pip.backwardcompat import (md5, copytree, xmlrpclib, urllib, urllib2,
                                  urlparse, string_types, HTTPError)
  from pip.exceptions import InstallationError
***************
*** 22,28 ****
             'unpack_file_url', 'is_vcs_url', 'is_file_url', 'unpack_http_url']
  
  
! xmlrpclib_transport = xmlrpclib.Transport()
  
  
  def get_file_content(url, comes_from=None):
--- 23,44 ----
             'unpack_file_url', 'is_vcs_url', 'is_file_url', 'unpack_http_url']
  
  
! class ProxiedTransport(xmlrpclib.Transport):
!     def make_connection(self, host):
!         self.realhost = host
!         proxy = urlopen.get_proxy()
!         if proxy: 
!             if proxy.startswith("http://"):
!                 proxy =proxy[len('http://'):]
!             h = httplib.HTTP(proxy)
!         else: 
!             h = httplib.HTTP(host)
!         return h
!     def send_request(self, connection, handler, request_body):
!         connection.putrequest("POST", 'http://%s%s' % (self.realhost, handler))
!     def send_host(self, connection, host):
!         connection.putheader('Host', self.realhost)
! xmlrpclib_transport = ProxiedTransport()
  
  
  def get_file_content(url, comes_from=None):


上記の通りに、pipの中のdownload.pyを変更すればOK.
間違った変更を加えると、動かなくなるので注意。

ちなみに、download.pyはわたしの環境では、
/usr/local/lib/python2.6/dist-packages/pip-1.1-py2.6.egg/pip/download.py
とかにある。

これがベストなやり方ではないかもしれないが、とりあえず動く。

6 件のコメント:

  1. このコメントは投稿者によって削除されました。

    返信削除
  2. 同様の問題が pip 1.2.1 でも起きるようです。

    なお、Python 2.7 で動かすために、h = httplib.HTTP(...) の部分を h = httplib.HTTPConnection(...) に変えて動きました。

    download.py の中では環境変数も見ていますね(proxystr = os.environ.get('HTTP_PROXY', ''))。

    返信削除
    返信
    1. zyxさん、2.7での情報ありがとうございます。

      削除
    2. 環境変数にHTTP_PROXYを設定しても通してもだめだったのでソースを修正することにしたような記憶があります。

      削除
  3. こんにちは
    pip-1.4.1 でも同様の問題が起き、download.py を見ているのですが、そのソース内容はかなり様変わりしていて、よく分からないです。相変わらず proxystr = os.environ.get('HTTP_PROXY', '')
    の部分は、存在していても役に立っていないようです。

    返信削除
  4. こんにちは
    pip-1.4.1-py2.7.egg/pip/commands/search.py を見ていて,xmlrpclib.ServerProxy(index_url)の箇所(下記)がそのままでは proxy 非対応のようです.したがって下記のような変更が必要のようです.
    def search(self, query, index_url):
    + if proxy:
    + p = ProxiedTransport()
    + pypi = xmlrpclib.ServerProxy(index_url, transport=p)
    + else:
    + pypi = xmlrpclib.ServerProxy(index_url)
    - pypi = xmlrpclib.ServerProxy(index_url)

    この情報も参考にしました:https://github.com/mjmac/brew-pip/commit/7527f3ab51945749831f8e96cd2064863fb62353

    返信削除