https://github.com/adc-connect/adcc
Tip revision: 75c927f9929309f90ff39fe6fd99f5886ab87891 authored by Michael F. Herbst on 14 February 2019, 22:32:13 UTC
Bump version: 0.6.1 → 0.6.2
Bump version: 0.6.1 → 0.6.2
Tip revision: 75c927f
setup.py
#!/usr/bin/env python3
## vi: tabstop=4 shiftwidth=4 softtabstop=4 expandtab
## ---------------------------------------------------------------------
##
## Copyright (C) 2019 by the adcc authors
##
## This file is part of adcc.
##
## adcc is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published
## by the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## adcc is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with adcc. If not, see <http://www.gnu.org/licenses/>.
##
## ---------------------------------------------------------------------
"""Setup for look4bas"""
from os.path import join
from setuptools.command.build_ext import build_ext as BuildCommand
from setuptools.command.test import test as TestCommand
from setuptools import setup, Extension, find_packages
import glob
import json
import os
import setuptools
import sys
# Version of the python bindings and adcc python package.
__version__ = '0.6.2'
#
# Compile and install adccore library
#
def trigger_adccore_build():
"""
Trigger a build of the adccore library, if it exists in source form.
"""
if os.path.isfile("adccore/build.sh"):
# I.e. this user has access to adccore source code
import subprocess
subprocess.check_call("./adccore/build.sh")
#
# Find AdcCore
#
class AdcCore:
def __init__(self):
this_dir = os.path.dirname(__file__)
self.config_path = join(this_dir, "extension", "adccore",
"adccore_config.json")
@property
def is_config_file_present(self):
"""
Is the config file present on disk
"""
return os.path.isfile(self.config_path)
@property
def config(self):
if not self.is_config_file_present:
raise RuntimeError(
"Did not find adccore_config.json file in the directory tree." +
" Did you download or install adccore properly? See the adcc " +
"documentation for help."
)
else:
with open(self.config_path, "r") as fp:
return json.load(fp)
def __getattr__(self, key):
try:
return self.config[key]
except KeyError:
raise AttributeError
#
# Pybind11 BuildExt
#
class GetPyBindInclude:
"""Helper class to determine the pybind11 include path
The purpose of this class is to postpone importing pybind11
until it is actually installed, so that the ``get_include()``
method can be invoked. """
def __init__(self, user=False):
self.user = user
def __str__(self):
import pybind11
return pybind11.get_include(self.user)
# As of Python 3.6, CCompiler has a `has_flag` method.
# cf http://bugs.python.org/issue26689
def has_flag(compiler, flagname):
"""Return a boolean indicating whether a flag name is supported on
the specified compiler.
"""
import tempfile
with tempfile.NamedTemporaryFile('w', suffix='.cpp') as f:
f.write('int main (int argc, char **argv) { return 0; }')
try:
compiler.compile([f.name], extra_postargs=[flagname])
except setuptools.distutils.errors.CompileError:
return False
return True
def cpp_flag(compiler):
"""Return the -std=c++[11/14] compiler flag.
The c++14 is prefered over c++11 (when it is available).
"""
if has_flag(compiler, '-std=c++14'):
return '-std=c++14'
elif has_flag(compiler, '-std=c++11'):
return '-std=c++11'
else:
raise RuntimeError('Unsupported compiler -- at least C++11 support '
'is needed!')
class BuildExt(BuildCommand):
"""A custom build extension for adding compiler-specific options."""
def build_extensions(self):
trigger_adccore_build()
opts = []
if sys.platform == "darwin":
opts += ['-stdlib=libc++', '-mmacosx-version-min=10.7']
if self.compiler.compiler_type == 'unix':
opts.append(cpp_flag(self.compiler))
potential_opts = [
"-fvisibility=hidden", "-Werror", "-Wall", "-Wextra",
"-pedantic", "-Wnon-virtual-dtor", "-Woverloaded-virtual",
"-Wcast-align", "-Wconversion", "-Wsign-conversion",
"-Wmisleading-indentation", "-Wduplicated-cond",
"-Wduplicated-branches", "-Wlogical-op",
"-Wdouble-promotion", "-Wformat=2",
"-Wno-error=deprecated-declarations",
]
opts.extend([opt for opt in potential_opts
if has_flag(self.compiler, opt)])
for ext in self.extensions:
ext.extra_compile_args = opts
BuildCommand.build_extensions(self)
#
# Pytest integration
#
class PyTest(TestCommand):
def initialize_options(self):
TestCommand.initialize_options(self)
self.pytest_args = ""
def update_testdata(self):
testdata_dir = "adcc/testdata"
if not os.path.isdir(testdata_dir):
raise RuntimeError("Can only test from git repository, "
"not from installation tarball.")
timefile = testdata_dir + "/.last_update"
if not os.path.isfile(timefile):
needs_update = True
else:
import datetime
ts = datetime.datetime.fromtimestamp(os.path.getmtime(timefile))
age = datetime.datetime.utcnow() - ts
needs_update = age > datetime.timedelta(hours=2)
if needs_update:
import subprocess
subprocess.check_call(testdata_dir + "/0_download_testdata.sh")
def run_tests(self):
import shlex
# import here, cause outside the eggs aren't loaded
import pytest
self.update_testdata()
errno = pytest.main(shlex.split(self.pytest_args))
sys.exit(errno)
#
# Main setup code
#
if not os.path.isfile("adcc/__init__.py"):
raise RuntimeError("Running setup.py is only supported "
"from top level of repository as './setup.py <command>'")
adccore = AdcCore()
if not adccore.is_config_file_present:
# Trigger a build of adccore if the source code can be found
trigger_adccore_build()
if adccore.version != __version__:
# Try to see if a simple adccore build solves this issue
trigger_adccore_build()
if adccore.version != __version__:
raise RuntimeError(
"Version mismatch between adcc (== {}) and adccore (== {})"
"".format(__version__, adccore.version)
)
# Setup RPATH on Linux and MacOS
if sys.platform == "darwin":
extra_link_args = ["$ORIGIN", "$ORIGIN/adcc/lib"]
runtime_library_dirs = []
elif sys.platform == "linux":
extra_link_args = []
runtime_library_dirs = ["$ORIGIN", "$ORIGIN/adcc/lib"]
else:
raise OSError("Unsupported platform: {}".format(sys.platform))
# Setup build of the libadcc extension
ext_modules = [
Extension(
'libadcc', glob.glob("extension/*.cc"),
include_dirs=[
# Path to pybind11 headers
GetPyBindInclude(),
GetPyBindInclude(user=True),
"extension/adccore/include"
],
libraries=adccore.libraries,
library_dirs=["adcc/lib"],
extra_link_args=extra_link_args,
runtime_library_dirs=runtime_library_dirs,
language='c++',
),
]
setup(
name='adcc',
description='A python-based framework for running ADC calculations',
long_description='', # TODO
#
url='https://github.com/mfherbst/adcc',
author='adcc developers',
author_email='adcc+developers@michael-herbst.com',
maintainer='Michael F. Herbst',
maintainer_email='info@michael-herbst.com',
license="LGPL v3",
#
version=__version__,
classifiers=[
'Development Status :: 4 - Beta',
'License :: OSI Approved :: '
'GNU Lesser General Public License v3 (LGPLv3)',
'Intended Audience :: Science/Research',
"Topic :: Scientific/Engineering :: Chemistry",
"Topic :: Education",
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Operating System :: Unix',
],
#
packages=find_packages(exclude=["*.test*", "test"]),
package_data={'adcc': ["lib/*.so", "lib/*.dylib"]},
ext_modules=ext_modules,
zip_safe=False,
#
platforms=["Linux", "Mac OS-X", "Unix"],
python_requires='>=3.5',
install_requires=[
'pybind11 (>= 2.2)',
'numpy',
'scipy',
],
tests_require=["pytest", "h5py"],
#
cmdclass={'build_ext': BuildExt, "pytest": PyTest},
)