2014-01-18 45 views
4

我写了一个简单的程序,打开一个csv文件并将文本中的所有数字。我使用Twilio(twilio-python)作为服务提供商。我的代码工作正常,作为一个Python脚本。但是,当我编译脚本(使用py2exe)时,exe文件错误。这是我从日志文件中收到错误....编译后Twilio Python模块错误

Traceback (most recent call last): 
File "sms.py", line 39, in <module> 
File "twilio\rest\resources\messages.pyc", line 112, in create 
File "twilio\rest\resources\base.pyc", line 352, in create_instance 
File "twilio\rest\resources\base.pyc", line 204, in request 
File "twilio\rest\resources\base.pyc", line 129, in make_twilio_request 
File "twilio\rest\resources\base.pyc", line 101, in make_request 
File "httplib2\__init__.pyc", line 1570, in request 
File "httplib2\__init__.pyc", line 1317, in _request 
File "httplib2\__init__.pyc", line 1252, in _conn_request 
File "httplib2\__init__.pyc", line 1021, in connect 
File "httplib2\__init__.pyc", line 80, in _ssl_wrap_socket 
File "ssl.pyc", line 387, in wrap_socket 
File "ssl.pyc", line 141, in __init__ 
ssl.SSLError: [Errno 185090050] _ssl.c:340: error:0B084002:x509 certificate    
routines:X509_load_cert_crl_file:system lib 

我没有收到,当我使用未编译的代码(下)

import sys #2 params --- /path/to/contact/file --- up to 160 char msg 
    import csv 
    import time 

    from twilio.rest import TwilioRestClient 
    ACCOUNT_SID = "**************************" 
    AUTH_TOKEN = "**************************" 
    client = TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN) 

    sys.argv.pop(0) 
    contactFile = sys.argv[0] 
    sys.argv.pop(0) 
    msg = (' ').join(sys.argv) 

    print contactFile 
    print " " 
    print msg 

    info = [] 
    with open(contactFile,'rb') as csvfile: 
    reader = csv.reader(csvfile, delimiter=',', quotechar='|') 
     for row in reader: 
     info.append(row) 

    contactCount = len(info)-1 

    if contactCount > 0: 
    #remove first item from list because its not a value that is needed.... 
    info.pop(0) 

    for i in info: 
     print " " 
     contactName = i[0] 
     phoneNumber = i[1] 
     print "Texting " + contactName + "... \n" 
     client.messages.create(
     to=phoneNumber, 
     from_="+14782856136", 
     body=msg 
     ) 
     time.sleep(1.5) 
    else: 
    print("SMSify Error \n The contact file doesn't have any contacts in it.") 

任何思考这个错误到底是怎么回事??

编辑:

这里是我的setup.py文件

from distutils.core import setup 
import py2exe, sys, os 
sys.argv.append('py2exe') 
Mydata_files = [('cacert.pem', ['C:\\Python27\\Lib\\site-  
packages\\twilio\\conf\\cacert.pem'])] 

setup(
    console=['sms.py'], 
    data_files = Mydata_files, 
    options={ 
       "py2exe":{ 
        "bundle_files": 1, 
        "compressed": True 
       } 
     } 
) 
+0

一个简单的解决方案是 - 您可以物理放置证书到您的可分发目录中,并明确地通过代码中的认证位置。请参阅http://stackoverflow.com/a/34227183/318700 – HVS

回答

14

因为self-signed certificate文件中捆绑错过它的发生。

此问题与requests和模块相同。

举例来说,如果你有一个名为req_example.py文件,使用request模块:

import requests 
url = 'https://google.com/' 
requests.get(url) 

它,当你运行它python req_example.py工作,但当其捆绑,它不工作。

或者,如果你有一个名为http2_example.py文件,使用http2模块:

import httplib2 
url = 'https://google.com/' 
http = httplib2.Http() 
http.request(url) 

它,当你运行它python http2_example.py工作,但当其捆绑,它不工作。

为了解决这个问题,你有两个选择,一个是bad和一个good

  1. 禁用验证SSL证书:

    要做到这一点为requests模块:

    import requests 
    url = 'https://google.com/' 
    requests.get(url, verify=False) 
    

    而对于模块:

    import httplib2 
    http = httplib2.Http(disable_ssl_certificate_validation=True) 
    http.request(url) 
    
  2. 添加self-signed certificate文件捆绑:

    对于requests模块,文件cacert.pem位于:

    .../PythonXX/lib/site-packages/requests/cacert.pem

    而对于模块是:

    .../PythonXX/lib/site-packages/httplib2/cacerts.txt

    对于他们每个人,你可以把它复制到里面您的项目(或只是地址),

    And config setup.py用于包括它:

    setup(console=['temp.py'], 
        # for `requests` module 
        data_files=['cacert.pem']) # or data_files=['cacerts.txt']) for `httplib2` 
    

    而更改您的代码使用,对于request模块:

    import os 
    import requests 
    url = 'https://google.com/' 
    cert ='cacert.pem' 
    # or os.environ['REQUESTS_CA_BUNDLE'] = cert 
    os.environ['REQUESTS_CA_BUNDLE'] = os.path.join(os.getcwd(), cert) 
    requests.get(url) 
    

    而对于模块:

    import httplib2 
    cert = 'cacerts.txt' 
    http = httplib2.Http(ca_certs=cert) 
    http.request(url) 
    

    或者,如果你版本是0.8 ,你可以创建一个文件 should命名为ca_certs_locater.py,并定义一个get函数, 返回ca_certs文件的路径。

    def get(): 
        return 'cacerts.txt' 
    

好了,现在你的错误,并为twilio模块,它use ,和它cacert.pem是:

.../twilio/conf/cacert.pem

所以,你需要这个文件添加到如上所述的setup.py

twilio本身具有名称get_cert_file的功能,它将ca_cert文件传递给。

我认为,如果你使用上述ca_certs_locater.py,它也将为该, 但如果没有工作,你还没有一个ugly选项,这样你就可以猴子补丁功能twilioget_cert_file

from twilio.rest.resources.base import get_cert_file 
get_cert_file = lambda: 'cacert.pem' 

请注意,这可能是twilio或甚至py2exePyInstaller的问题。

+0

好的。所以我在setup.py文件中添加了twilio cacert.pem文件。我的setup.py文件张贴在上面。我仍然得到同样的错误。 –

+0

这是不行的,因为'twilio'希望从它自己的路径加载它,即'.../twilio/conf/cacert.pem',但是它并不存在于捆绑软件包(在'library.zip'文件中) ,试试'ca_certs_locater.py'的方式,如果不行的话,试试'patch'的方式。 –

+0

好的。所以我创建文件ca_certs_locater.py并添加get函数。现在,我应该将它捆绑在setup.py中吗?答案有点模糊。谢谢你的帮助! –

1

应该可能有py2exe打包非Python文件的方式,比如模板或者存储在cacert.pem中的SSL证书。通常这是使用MANIFEST.in自动完成的,但我不确定该项目如何处理它。查看那里的文档以获取更多信息。

2

我曾与twilio和pyinstaller同样的问题,并能够通过修改twilio \休息\资源base.py模块来解决它:

def get_cert_file(): 
""" Get the cert file location or bail """ 
# XXX - this currently fails test coverage because we don't actually go 
# over the network anywhere. Might be good to have a test that stands up a 
# local server and authenticates against it. 
    try: 
    # Apparently __file__ is not available in all places so wrapping this 
    # in a try/catch 
    current_path = os.path.realpath(__file__) 
    #ca_cert_path = os.path.join(current_path, "..", "..", "..", (old path) 
    #       "conf", "cacert.pem") 
    ca_cert_path = os.getcwd() + '\Config\cacert.pem' (my new path) 

    return os.path.abspath(ca_cert_path) 

(我保存我的cacert.pem文件在我的主脚本目录下的Config文件夹中)