alekstorm / backports.ssl

UNMAINTAINED - The Python 3.4 standard `ssl` module API implemented on top of pyOpenSSL

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

import fails: 'module' object has no attribute 'SSLContext'

arnisoph opened this issue · comments

$ pip freeze
backports.ssl==0.0.7
PyYAML==3.11
six==1.9.0
wheel==0.24.0
$ python
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 23 2015, 02:52:03)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import backports.ssl as ssl
>>> import socket
>>> context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'SSLContext'
>>>

Any ideas?

I've also seen a report of this from an IMAPClient user (IMAPClient depends on the backports.ssl).

https://bitbucket.org/mjs0/imapclient/issues/196/attributeerror-module-object-has-no

backports.ssl depends on pyOpenSSL. If pyOpenSSL fails to import then SSLContext and a few other names are removed from the backports.ssl package (see https://github.com/alekstorm/backports.ssl/blob/master/backports/ssl/core.py#L699). It seems that pyOpenSSL isn't installed in your environment.

To help confirm, please try the following from a Python shell in the same environment:

from OpenSSL import crypto
from OpenSSL import SSL

the issue is somehow fixed. thanks!

aaaand I had it again, but brew install libffi on Mac OS fixed the issue for me.

thanks to technomancy/grenchman#21

Great! The IMAPClient user who was having this problem was missing libffi-dev from his Ubuntu Linux system, so it was the same root cause.

Hmm, I have the same issue on Mac OS X El Capitan. I don't use homebrew...

Okay, so the reason for this is:

>>> from OpenSSL import SSL
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "python2.7/site-packages/OpenSSL/__init__.py", line 8, in <module>
    from OpenSSL import rand, crypto, SSL
  File "python2.7/site-packages/OpenSSL/rand.py", line 11, in <module>
    from OpenSSL._util import (
  File "python2.7/site-packages/OpenSSL/_util.py", line 6, in <module>
    from cryptography.hazmat.bindings.openssl.binding import Binding
  File "python2.7/site-packages/cryptography/hazmat/bindings/openssl/binding.py", line 13, in <module>
    from cryptography.hazmat.bindings._openssl import ffi, lib
ImportError: dlopen(python2.7/site-packages/cryptography/hazmat/bindings/_openssl.so, 2): Library not loaded: libssl.1.0.0.dylib
  Referenced from: python2.7/site-packages/cryptography/hazmat/bindings/_openssl.so
  Reason: image not found

This is very similar to this old chestnut that I hit every time I install psycopg2 on OSX:

psycopg/psycopg2#385

This Stack Overflow thread has a bunch of related stuff:

http://stackoverflow.com/questions/32978365/how-do-i-run-psycopg2-on-el-capitan-without-hitting-a-libssl-error

So, is this a problem with how backports.ssl and psycopg2 and structured, or is the problem lower down in the Python stack?

So, here's an interesting difference between Python's included _ssl:

$ otool -L .../lib/python2.7/lib-dynload/_ssl.so
.../lib/python2.7/lib-dynload/_ssl.so:
    @loader_path/../../libssl.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
    @loader_path/../../libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.0.0)

Compare that with the problematic one in backports:

$ otool -L lib/python2.7/site-packages/cryptography/hazmat/bindings/_openssl.so
lib/python2.7/site-packages/cryptography/hazmat/bindings/_openssl.so:
    libssl.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
    libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1225.1.1)
    /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 913.0.0)

If I manually replace libssl.1.0.0.dylib with an absolute path to libssl.1.0.0.dylib (and the others like it) using the following, everything works:

install_name_tool -change libssl.1.0.0.dylib /Library/PostgreSQL/9.4/lib/libssl.1.0.0.dylib lib/python2.7/site-packages/cryptography/hazmat/bindings/_openssl.so
install_name_tool -change libcrypto.1.0.0.dylib /Library/PostgreSQL/9.4/lib/libcrypto.1.0.0.dylib

So, how come _ssl.so that ships with Python uses @loader_path and it works, but extensions built locally do not? What can we change in the source distribution to cause local compilation to build usable binaries?