1#!/usr/bin/env python
2import os
3import subprocess
4import sys
5from distutils.core import Command
6from glob import glob
7try:
8    from setuptools import setup, Extension
9except ImportError:
10    from distutils.core import setup
11    from distutils.extension import Extension
12
13
14class TestCommand(Command):
15    """Hack for setup.py with implicit build_ext -i
16    """
17    user_options = []
18
19    def initialize_options(self):
20        self.rootdir = os.getcwd()
21
22    def finalize_options(self):
23        pass
24
25    def remove_ext(self):
26        """Remove extensions
27
28        All Python 2.x versions share the same library name. Remove the
29        file to fix version mismatch errors.
30        """
31        for fname in os.listdir(self.rootdir):
32            if fname.endswith(("so", "dylib", "pyd", "sl")):
33                os.unlink(os.path.join(self.rootdir, fname))
34
35    def get_lib_dirs(self):
36        """Get version, platform and configuration dependend lib dirs
37
38        Distutils caches the build command object on the distribution object.
39        We can retrieve the object to retrieve the paths to the directories
40        inside the build directory.
41        """
42        build = self.distribution.command_obj["build"]
43        builddirs = set()
44        for attrname in 'build_platlib', 'build_lib', 'build_purelib':
45            builddir = getattr(build, attrname, None)
46            if not builddir:
47                continue
48            builddir = os.path.abspath(os.path.join(self.rootdir, builddir))
49            if not os.path.isdir(builddir):
50                continue
51            builddirs.add(builddir)
52        return builddirs
53
54    def run(self):
55        self.remove_ext()
56        # force a build with build_ext
57        self.run_command("build")
58        # get lib dirs from build object
59        libdirs = self.get_lib_dirs()
60        # add lib dirs to Python's search path
61        env = os.environ.copy()
62        env["PYTHONPATH"] = os.pathsep.join(libdirs)
63        # and finally run the test command
64        errno = subprocess.check_call([sys.executable, "tests.py"], env=env)
65        raise SystemExit(errno)
66
67
68exts = []
69sha3_depends = ["setup.py", "Modules/hashlib.h", "Modules/pymemsets.h"]
70sha3_depends.extend(glob("Modules/_sha3/kcp/*"))
71exts.append(
72    Extension(
73        "_pysha3",
74        ["Modules/_sha3/sha3module.c", "Modules/pymemsets.c"],
75        depends=sha3_depends,
76        define_macros=[("PY_WITH_KECCAK", "1")]
77    )
78)
79
80long_description = []
81
82with open("README.txt") as f:
83    long_description.append(f.read())
84
85with open("CHANGES.txt") as f:
86    long_description.append(f.read())
87
88
89setup(
90    name="pysha3",
91    version="1.0.2",
92    ext_modules=exts,
93    py_modules=["sha3"],
94    cmdclass={"test": TestCommand},
95    author="Christian Heimes",
96    author_email="christian@python.org",
97    maintainer="Christian Heimes",
98    maintainer_email="christian@python.org",
99    url="https://github.com/tiran/pysha3",
100    keywords="sha3 sha-3 keccak hash",
101    platforms="POSIX, Windows",
102    license="PSFL (Keccak: CC0 1.0 Universal)",
103    description="SHA-3 (Keccak) for Python 2.7 - 3.5",
104    long_description="\n".join(long_description),
105    classifiers=[
106        "Development Status :: 4 - Beta",
107        "Intended Audience :: Developers",
108        "License :: OSI Approved :: Python Software Foundation License",
109        "License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication",
110        "Natural Language :: English",
111        "Operating System :: MacOS :: MacOS X",
112        "Operating System :: POSIX",
113        "Operating System :: POSIX :: BSD",
114        "Operating System :: POSIX :: Linux",
115        "Operating System :: Microsoft :: Windows",
116        "Programming Language :: C",
117        "Programming Language :: Python",
118        "Programming Language :: Python :: 2",
119        "Programming Language :: Python :: 2.7",
120        "Programming Language :: Python :: 3",
121        "Programming Language :: Python :: 3.4",
122        "Programming Language :: Python :: 3.5",
123        "Topic :: Security :: Cryptography",
124    ],
125)
126