Merge pull request #1283 from Ayrx/entry_points

Added entry_points.
diff --git a/cryptography/hazmat/backends/__init__.py b/cryptography/hazmat/backends/__init__.py
index ae78822..b0f663f 100644
--- a/cryptography/hazmat/backends/__init__.py
+++ b/cryptography/hazmat/backends/__init__.py
@@ -13,13 +13,9 @@
 
 from __future__ import absolute_import, division, print_function
 
+import pkg_resources
+
 from cryptography.hazmat.backends.multibackend import MultiBackend
-from cryptography.hazmat.bindings.commoncrypto.binding import (
-    Binding as CommonCryptoBinding
-)
-from cryptography.hazmat.bindings.openssl.binding import (
-    Binding as OpenSSLBinding
-)
 
 
 _available_backends_list = None
@@ -29,19 +25,15 @@
     global _available_backends_list
 
     if _available_backends_list is None:
-        _available_backends_list = []
-
-        if CommonCryptoBinding.is_available():
-            from cryptography.hazmat.backends import commoncrypto
-            _available_backends_list.append(commoncrypto.backend)
-
-        if OpenSSLBinding.is_available():
-            from cryptography.hazmat.backends import openssl
-            _available_backends_list.append(openssl.backend)
+        _available_backends_list = [
+            backend.load(require=False)
+            for backend in pkg_resources.iter_entry_points(
+                "cryptography.backends"
+            )
+        ]
 
     return _available_backends_list
 
-
 _default_backend = None
 
 
diff --git a/cryptography/hazmat/bindings/commoncrypto/binding.py b/cryptography/hazmat/bindings/commoncrypto/binding.py
index ee7378a..ee09beb 100644
--- a/cryptography/hazmat/bindings/commoncrypto/binding.py
+++ b/cryptography/hazmat/bindings/commoncrypto/binding.py
@@ -13,9 +13,6 @@
 
 from __future__ import absolute_import, division, print_function
 
-import platform
-import sys
-
 from cryptography.hazmat.bindings.utils import build_ffi
 
 
@@ -53,8 +50,3 @@
             modules=cls._modules,
             extra_link_args=["-framework", "Security"]
         )
-
-    @classmethod
-    def is_available(cls):
-        return sys.platform == "darwin" and list(map(
-            int, platform.mac_ver()[0].split("."))) >= [10, 8, 0]
diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py
index 4cbe3c5..37891f6 100644
--- a/cryptography/hazmat/bindings/openssl/binding.py
+++ b/cryptography/hazmat/bindings/openssl/binding.py
@@ -116,12 +116,6 @@
         assert res != 0
 
     @classmethod
-    def is_available(cls):
-        # For now, OpenSSL is considered our "default" binding, so we treat it
-        # as always available.
-        return True
-
-    @classmethod
     def init_static_locks(cls):
         with cls._lock_init_lock:
             cls._ensure_ffi_initialized()
diff --git a/setup.py b/setup.py
index f73394e..6a7642f 100644
--- a/setup.py
+++ b/setup.py
@@ -14,6 +14,7 @@
 from __future__ import absolute_import, division, print_function
 
 import os
+import platform
 import subprocess
 import sys
 from distutils.command.build import build
@@ -32,13 +33,15 @@
     exec(f.read(), about)
 
 
+SETUPTOOLS_DEPENDENCY = "setuptools"
 CFFI_DEPENDENCY = "cffi>=0.8"
 SIX_DEPENDENCY = "six>=1.4.1"
 VECTORS_DEPENDENCY = "cryptography_vectors=={0}".format(about['__version__'])
 
 requirements = [
     CFFI_DEPENDENCY,
-    SIX_DEPENDENCY
+    SIX_DEPENDENCY,
+    SETUPTOOLS_DEPENDENCY
 ]
 
 # If you add a new dep here you probably need to add it in the tox.ini as well
@@ -55,6 +58,21 @@
     test_requirements.append(VECTORS_DEPENDENCY)
 
 
+def cc_is_available():
+    return sys.platform == "darwin" and list(map(
+        int, platform.mac_ver()[0].split("."))) >= [10, 8, 0]
+
+
+backends = [
+    "openssl = cryptography.hazmat.backends.openssl:backend"
+]
+
+if cc_is_available():
+    backends.append(
+        "commoncrypto = cryptography.hazmat.backends.commoncrypto:backend",
+    )
+
+
 def get_ext_modules():
     from cryptography.hazmat.bindings.commoncrypto.binding import (
         Binding as CommonCryptoBinding
@@ -69,7 +87,7 @@
         constant_time._ffi.verifier.get_extension(),
         padding._ffi.verifier.get_extension()
     ]
-    if CommonCryptoBinding.is_available():
+    if cc_is_available():
         ext_modules.append(CommonCryptoBinding().ffi.verifier.get_extension())
     return ext_modules
 
@@ -173,5 +191,9 @@
         "build": CFFIBuild,
         "install": CFFIInstall,
         "test": PyTest,
+    },
+
+    entry_points={
+        "cryptography.backends": backends,
     }
 )
diff --git a/tests/hazmat/backends/test_commoncrypto.py b/tests/hazmat/backends/test_commoncrypto.py
index e2c6f4a..28d1a6c 100644
--- a/tests/hazmat/backends/test_commoncrypto.py
+++ b/tests/hazmat/backends/test_commoncrypto.py
@@ -17,7 +17,7 @@
 
 from cryptography import utils
 from cryptography.exceptions import InternalError, _Reasons
-from cryptography.hazmat.bindings.commoncrypto.binding import Binding
+from cryptography.hazmat.backends import _available_backends
 from cryptography.hazmat.primitives import interfaces
 from cryptography.hazmat.primitives.ciphers.algorithms import AES
 from cryptography.hazmat.primitives.ciphers.base import Cipher
@@ -32,7 +32,8 @@
     block_size = 128
 
 
-@pytest.mark.skipif(not Binding.is_available(),
+@pytest.mark.skipif("commoncrypto" not in
+                    [i.name for i in _available_backends()],
                     reason="CommonCrypto not available")
 class TestCommonCrypto(object):
     def test_supports_cipher(self):
diff --git a/tests/hazmat/bindings/test_commoncrypto.py b/tests/hazmat/bindings/test_commoncrypto.py
index 0332674..71c832e 100644
--- a/tests/hazmat/bindings/test_commoncrypto.py
+++ b/tests/hazmat/bindings/test_commoncrypto.py
@@ -15,10 +15,12 @@
 
 import pytest
 
+from cryptography.hazmat.backends import _available_backends
 from cryptography.hazmat.bindings.commoncrypto.binding import Binding
 
 
-@pytest.mark.skipif(not Binding.is_available(),
+@pytest.mark.skipif("commoncrypto" not in
+                    [i.name for i in _available_backends()],
                     reason="CommonCrypto not available")
 class TestCommonCrypto(object):
     def test_binding_loads(self):
diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py
index d22c4fd..ca6e9ab 100644
--- a/tests/hazmat/bindings/test_openssl.py
+++ b/tests/hazmat/bindings/test_openssl.py
@@ -27,9 +27,6 @@
         assert binding.lib
         assert binding.ffi
 
-    def test_is_available(self):
-        assert Binding.is_available() is True
-
     def test_crypto_lock_init(self):
         b = Binding()
         b.init_static_locks()