Merge pull request #371 from hynek/move-to-src

Move package into src
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..5bc0e03
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,12 @@
+[run]
+branch = True
+source = OpenSSL
+
+[paths]
+source =
+   src/OpenSSL
+   .tox/*/lib/python*/site-packages/OpenSSL
+   .tox/pypy/site-packages/OpenSSL
+
+[report]
+show_missing = True
diff --git a/.gitignore b/.gitignore
index 11e37b7..2040b80 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,7 @@
 __pycache__
 .tox
 doc/_build/
-.coverage
+.coverage*
 .eggs
 examples/simple/*.cert
 examples/simple/*.pkey
diff --git a/MANIFEST.in b/MANIFEST.in
index 71fbb40..5585068 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,5 +1,6 @@
-include             LICENSE ChangeLog MANIFEST.in *.rst tox.ini memdbg.py runtests.py OpenSSL/test/README docs-requirements.txt
+include             LICENSE ChangeLog MANIFEST.in *.rst tox.ini docs-requirements.txt .coveragerc
 exclude             leakcheck
+recursive-include   tests       *.py
 recursive-include   doc         *
 recursive-include   examples    *
 recursive-include   rpm         *
diff --git a/OpenSSL/test/README b/OpenSSL/test/README
deleted file mode 100644
index 8b3b3ff..0000000
--- a/OpenSSL/test/README
+++ /dev/null
@@ -1,8 +0,0 @@
-These tests are meant to be run using twisted's "trial" command.
-
-See http://twistedmatrix.com/trac/wiki/TwistedTrial
-
-For example...
-
-$ sudo python ./setup install
-$ trial OpenSSL
diff --git a/doc/conf.py b/doc/conf.py
index 7d0fe9c..9eba065 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -78,7 +78,7 @@
 # built documents.
 #
 # The short X.Y version.
-version = find_version("../OpenSSL/version.py")
+version = find_version("..", "src", "OpenSSL", "version.py")
 # The full version, including alpha/beta/rc tags.
 release = version
 
diff --git a/runtests.py b/runtests.py
deleted file mode 100644
index 13f5c4c..0000000
--- a/runtests.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import sys
-sys.modules['ssl'] = None
-sys.modules['_hashlib'] = None
-
-try:
-   import memdbg
-except Exception as e:
-   pass
-
-from twisted.scripts.trial import run
-run()
diff --git a/setup.py b/setup.py
index f742c1e..c7c59ee 100755
--- a/setup.py
+++ b/setup.py
@@ -11,14 +11,12 @@
 import codecs
 import os
 import re
-import sys
 
-from setuptools import setup
-from setuptools.command.test import test as TestCommand
+from setuptools import setup, find_packages
 
 
 HERE = os.path.abspath(os.path.dirname(__file__))
-META_PATH = os.path.join("OpenSSL", "version.py")
+META_PATH = os.path.join("src", "OpenSSL", "version.py")
 
 
 def read_file(*parts):
@@ -46,82 +44,45 @@
     raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta))
 
 
-class PyTest(TestCommand):
-    user_options = [("pytest-args=", "a", "Arguments to pass to py.test")]
+if __name__ == "__main__":
+    setup(
+        name=find_meta("title"),
+        version=find_meta("version"),
+        description=find_meta("summary"),
+        long_description=read_file("README.rst"),
+        author=find_meta("author"),
+        author_email=find_meta("email"),
+        maintainer="Hynek Schlawack",
+        maintainer_email="hs@ox.cx",
+        url=find_meta("uri"),
+        license=find_meta("license"),
+        classifiers=[
+            'Development Status :: 6 - Mature',
+            'Intended Audience :: Developers',
+            'License :: OSI Approved :: Apache Software License',
+            'Operating System :: MacOS :: MacOS X',
+            'Operating System :: Microsoft :: Windows',
+            'Operating System :: POSIX',
 
-    def initialize_options(self):
-        TestCommand.initialize_options(self)
-        self.pytest_args = None
+            'Programming Language :: Python :: 2',
+            'Programming Language :: Python :: 2.6',
+            'Programming Language :: Python :: 2.7',
+            'Programming Language :: Python :: 3',
+            'Programming Language :: Python :: 3.3',
+            'Programming Language :: Python :: 3.4',
+            'Programming Language :: Python :: 3.5',
 
-    def finalize_options(self):
-        TestCommand.finalize_options(self)
-        self.test_args = []
-        self.test_suite = True
+            'Programming Language :: Python :: Implementation :: CPython',
+            'Programming Language :: Python :: Implementation :: PyPy',
+            'Topic :: Security :: Cryptography',
+            'Topic :: Software Development :: Libraries :: Python Modules',
+            'Topic :: System :: Networking',
+        ],
 
-    def run_tests(self):
-        # import here, cause outside the eggs aren't loaded
-        import pytest
-        errno = pytest.main(self.pytest_args or [] +
-                            ["OpenSSL"])
-        sys.exit(errno)
-
-
-setup(
-    name=find_meta("title"),
-    version=find_meta("version"),
-    description=find_meta("summary"),
-    long_description=read_file("README.rst"),
-    author=find_meta("author"),
-    author_email=find_meta("email"),
-    maintainer="Hynek Schlawack",
-    maintainer_email="hs@ox.cx",
-    url=find_meta("uri"),
-    license=find_meta("license"),
-    classifiers=[
-        'Development Status :: 6 - Mature',
-        'Intended Audience :: Developers',
-        'License :: OSI Approved :: Apache Software License',
-        'Operating System :: MacOS :: MacOS X',
-        'Operating System :: Microsoft :: Windows',
-        'Operating System :: POSIX',
-
-        'Programming Language :: Python :: 2',
-        'Programming Language :: Python :: 2.6',
-        'Programming Language :: Python :: 2.7',
-        'Programming Language :: Python :: 3',
-        'Programming Language :: Python :: 3.3',
-
-        'Programming Language :: Python :: Implementation :: CPython',
-        'Programming Language :: Python :: Implementation :: PyPy',
-        'Topic :: Security :: Cryptography',
-        'Topic :: Software Development :: Libraries :: Python Modules',
-        'Topic :: System :: Networking',
-    ],
-
-    packages=['OpenSSL'],
-    package_dir={'OpenSSL': 'OpenSSL'},
-    py_modules=['OpenSSL.__init__',
-                'OpenSSL.tsafe',
-                'OpenSSL.rand',
-                'OpenSSL.crypto',
-                'OpenSSL.SSL',
-                'OpenSSL.version',
-                'OpenSSL.test.__init__',
-                'OpenSSL.test.util',
-                'OpenSSL.test.test_crypto',
-                'OpenSSL.test.test_rand',
-                'OpenSSL.test.test_ssl',
-                'OpenSSL.test.test_tsafe',
-                'OpenSSL.test.test_util',],
-    install_requires=[
-        "cryptography>=0.7",
-        "six>=1.5.2"
-    ],
-    test_suite="OpenSSL",
-    tests_require=[
-        "pytest",
-    ],
-    cmdclass={
-        "test": PyTest,
-    }
-)
+        packages=find_packages(where="src"),
+        package_dir={"": "src"},
+        install_requires=[
+            "cryptography>=0.7",
+            "six>=1.5.2"
+        ],
+    )
diff --git a/OpenSSL/SSL.py b/src/OpenSSL/SSL.py
similarity index 100%
rename from OpenSSL/SSL.py
rename to src/OpenSSL/SSL.py
diff --git a/OpenSSL/__init__.py b/src/OpenSSL/__init__.py
similarity index 100%
rename from OpenSSL/__init__.py
rename to src/OpenSSL/__init__.py
diff --git a/OpenSSL/_util.py b/src/OpenSSL/_util.py
similarity index 100%
rename from OpenSSL/_util.py
rename to src/OpenSSL/_util.py
diff --git a/OpenSSL/crypto.py b/src/OpenSSL/crypto.py
similarity index 100%
rename from OpenSSL/crypto.py
rename to src/OpenSSL/crypto.py
diff --git a/OpenSSL/rand.py b/src/OpenSSL/rand.py
similarity index 100%
rename from OpenSSL/rand.py
rename to src/OpenSSL/rand.py
diff --git a/OpenSSL/tsafe.py b/src/OpenSSL/tsafe.py
similarity index 100%
rename from OpenSSL/tsafe.py
rename to src/OpenSSL/tsafe.py
diff --git a/OpenSSL/version.py b/src/OpenSSL/version.py
similarity index 100%
rename from OpenSSL/version.py
rename to src/OpenSSL/version.py
diff --git a/OpenSSL/test/__init__.py b/tests/__init__.py
similarity index 100%
rename from OpenSSL/test/__init__.py
rename to tests/__init__.py
diff --git a/memdbg.py b/tests/memdbg.py
similarity index 98%
rename from memdbg.py
rename to tests/memdbg.py
index 324d0fd..0deeb9e 100644
--- a/memdbg.py
+++ b/tests/memdbg.py
@@ -18,7 +18,7 @@
     int backtrace(void **buffer, int size);
     char **backtrace_symbols(void *const *buffer, int size);
     void backtrace_symbols_fd(void *const *buffer, int size, int fd);
-    """)
+    """)  # noqa
 _api = _ffi.verify(
     """
     #include <openssl/crypto.h>
@@ -29,10 +29,12 @@
 
 verbose = False
 
+
 def log(s):
     if verbose:
         print(s)
 
+
 def _backtrace():
     buf = _ffi.new("void*[]", 64)
     result = _api.backtrace(buf, len(buf))
diff --git a/tests/runtests.py b/tests/runtests.py
new file mode 100644
index 0000000..aca1d61
--- /dev/null
+++ b/tests/runtests.py
@@ -0,0 +1,17 @@
+"""
+This is a legacy file that no-one currently knows how to use.
+
+Please run your tests using ``py.test tests`` or ``tox``.
+"""
+
+import sys
+sys.modules['ssl'] = None
+sys.modules['_hashlib'] = None
+
+try:
+    from . import memdbg  # noqa
+except Exception as e:
+    pass
+
+from twisted.scripts.trial import run
+run()
diff --git a/OpenSSL/test/test_crypto.py b/tests/test_crypto.py
similarity index 99%
rename from OpenSSL/test/test_crypto.py
rename to tests/test_crypto.py
index 0c906b6..196e490 100644
--- a/OpenSSL/test/test_crypto.py
+++ b/tests/test_crypto.py
@@ -35,10 +35,11 @@
 from OpenSSL.crypto import NetscapeSPKI, NetscapeSPKIType
 from OpenSSL.crypto import (
     sign, verify, get_elliptic_curve, get_elliptic_curves)
-from OpenSSL.test.util import (
+from OpenSSL._util import native, lib
+
+from .util import (
     EqualityTestsMixin, TestCase, WARNING_TYPE_EXPECTED
 )
-from OpenSSL._util import native, lib
 
 
 def normalize_certificate_pem(pem):
diff --git a/OpenSSL/test/test_rand.py b/tests/test_rand.py
similarity index 98%
rename from OpenSSL/test/test_rand.py
rename to tests/test_rand.py
index d5d75cb..8064011 100644
--- a/OpenSSL/test/test_rand.py
+++ b/tests/test_rand.py
@@ -10,9 +10,10 @@
 import stat
 import sys
 
-from OpenSSL.test.util import NON_ASCII, TestCase, b
 from OpenSSL import rand
 
+from .util import NON_ASCII, TestCase, b
+
 
 class RandTests(TestCase):
     def test_bytes_wrong_args(self):
diff --git a/OpenSSL/test/test_ssl.py b/tests/test_ssl.py
similarity index 99%
rename from OpenSSL/test/test_ssl.py
rename to tests/test_ssl.py
index 3db1f8f..4aac429 100644
--- a/OpenSSL/test/test_ssl.py
+++ b/tests/test_ssl.py
@@ -47,12 +47,6 @@
 
 from OpenSSL._util import lib as _lib
 
-from OpenSSL.test.util import WARNING_TYPE_EXPECTED, NON_ASCII, TestCase, b
-from OpenSSL.test.test_crypto import (
-    cleartextCertificatePEM, cleartextPrivateKeyPEM,
-    client_cert_pem, client_key_pem, server_cert_pem, server_key_pem,
-    root_cert_pem)
-
 try:
     from OpenSSL.SSL import OP_NO_QUERY_MTU
 except ImportError:
@@ -89,6 +83,12 @@
     SSL_CB_ACCEPT_EXIT, SSL_CB_CONNECT_LOOP, SSL_CB_CONNECT_EXIT,
     SSL_CB_HANDSHAKE_START, SSL_CB_HANDSHAKE_DONE)
 
+from .util import WARNING_TYPE_EXPECTED, NON_ASCII, TestCase, b
+from .test_crypto import (
+    cleartextCertificatePEM, cleartextPrivateKeyPEM,
+    client_cert_pem, client_key_pem, server_cert_pem, server_key_pem,
+    root_cert_pem)
+
 
 # openssl dhparam 128 -out dh-128.pem (note that 128 is a small number of bits
 # to use)
diff --git a/OpenSSL/test/test_tsafe.py b/tests/test_tsafe.py
similarity index 94%
rename from OpenSSL/test/test_tsafe.py
rename to tests/test_tsafe.py
index 0456957..97045ce 100644
--- a/OpenSSL/test/test_tsafe.py
+++ b/tests/test_tsafe.py
@@ -7,7 +7,8 @@
 
 from OpenSSL.SSL import TLSv1_METHOD, Context
 from OpenSSL.tsafe import Connection
-from OpenSSL.test.util import TestCase
+
+from .util import TestCase
 
 
 class ConnectionTest(TestCase):
diff --git a/OpenSSL/test/test_util.py b/tests/test_util.py
similarity index 93%
rename from OpenSSL/test/test_util.py
rename to tests/test_util.py
index 24ccc1d..2aaded2 100644
--- a/OpenSSL/test/test_util.py
+++ b/tests/test_util.py
@@ -1,5 +1,6 @@
 from OpenSSL._util import exception_from_error_queue, lib
-from OpenSSL.test.util import TestCase
+
+from .util import TestCase
 
 
 class ErrorTests(TestCase):
diff --git a/OpenSSL/test/util.py b/tests/util.py
similarity index 99%
rename from OpenSSL/test/util.py
rename to tests/util.py
index b0a5d62..5b53dc2 100644
--- a/OpenSSL/test/util.py
+++ b/tests/util.py
@@ -22,7 +22,7 @@
 from OpenSSL.crypto import Error
 
 
-import memdbg
+from . import memdbg
 
 from OpenSSL._util import ffi, lib, byte_string as b
 
diff --git a/tox.ini b/tox.ini
index 7a40309..4657168 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,36 +1,29 @@
 [tox]
-envlist = {pypy,py26,py27,py33,py34,py35}{,-cryptographyMaster},pypi-readme,check-manifest,flake8,pyroma,docs
+envlist = coverage-clean,{pypy,py26,py27,py33,py34,py35}{,-cryptographyMaster},pypi-readme,check-manifest,flake8,pyroma,docs,coverage-report
 
 [testenv]
 whitelist_externals =
     openssl
 passenv = ARCHFLAGS CFLAGS LC_ALL LDFLAGS PATH LD_LIBRARY_PATH
 deps =
-    setuptools>=7.0  # older setuptools pollute CWD with egg files of dependencies
     coverage
+    pytest
     cryptographyMaster: git+https://github.com/pyca/cryptography.git
 setenv =
-    # Do not allowed the executing environment to pollute the test environment
+    # Do not allow the executing environment to pollute the test environment
     # with extra packages.
     PYTHONPATH=
 commands =
     openssl version
     python -c "import OpenSSL.SSL; print(OpenSSL.SSL.SSLeay_version(OpenSSL.SSL.SSLEAY_VERSION))"
     python -c "import cryptography; print(cryptography.__version__)"
-    coverage run --branch --source=OpenSSL setup.py test
-    coverage report -m
+    coverage run --parallel -m pytest tests
 
 [testenv:flake8]
 deps =
      flake8
 commands =
-     flake8 OpenSSL
-
-[testenv:pyroma]
-deps =
-     pyroma>=1.6 # <1.6 had bogus return values.
-commands =
-     pyroma -d .
+     flake8 src tests setup.py
 
 [testenv:pypi-readme]
 deps =
@@ -49,3 +42,15 @@
 basepython = python2.7
 commands =
      sphinx-build -W -b html doc doc/_build/html
+
+[testenv:coverage-clean]
+deps = coverage
+skip_install = true
+commands = coverage erase
+
+[testenv:coverage-report]
+deps = coverage
+skip_install = true
+commands =
+    coverage combine
+    coverage report