From 4ae677ef0be2484bd2cf2b5c18e9d0a0deee4bf4 Mon Sep 17 00:00:00 2001 From: Luthaf Date: Wed, 24 Aug 2022 16:18:14 +0200 Subject: [PATCH] Remove dependency on skbuild and switch to a src layout --- doc/conf.py | 42 +++++----- pyproject.toml | 14 ++-- scripts/check-used-functions.py | 8 +- setup.cfg | 6 ++ setup.py | 92 ++++++++++++++++------ {chemfiles => src/chemfiles}/.gitignore | 0 {chemfiles => src/chemfiles}/__init__.py | 0 {chemfiles => src/chemfiles}/_c_api.py | 0 {chemfiles => src/chemfiles}/_c_lib.py | 0 {chemfiles => src/chemfiles}/atom.py | 0 {chemfiles => src/chemfiles}/cell.py | 0 {chemfiles => src/chemfiles}/frame.py | 0 {chemfiles => src/chemfiles}/misc.py | 0 {chemfiles => src/chemfiles}/property.py | 0 {chemfiles => src/chemfiles}/residue.py | 0 {chemfiles => src/chemfiles}/selection.py | 0 {chemfiles => src/chemfiles}/topology.py | 0 {chemfiles => src/chemfiles}/trajectory.py | 0 {chemfiles => src/chemfiles}/utils.py | 0 19 files changed, 107 insertions(+), 55 deletions(-) rename {chemfiles => src/chemfiles}/.gitignore (100%) rename {chemfiles => src/chemfiles}/__init__.py (100%) rename {chemfiles => src/chemfiles}/_c_api.py (100%) rename {chemfiles => src/chemfiles}/_c_lib.py (100%) rename {chemfiles => src/chemfiles}/atom.py (100%) rename {chemfiles => src/chemfiles}/cell.py (100%) rename {chemfiles => src/chemfiles}/frame.py (100%) rename {chemfiles => src/chemfiles}/misc.py (100%) rename {chemfiles => src/chemfiles}/property.py (100%) rename {chemfiles => src/chemfiles}/residue.py (100%) rename {chemfiles => src/chemfiles}/selection.py (100%) rename {chemfiles => src/chemfiles}/topology.py (100%) rename {chemfiles => src/chemfiles}/trajectory.py (100%) rename {chemfiles => src/chemfiles}/utils.py (100%) diff --git a/doc/conf.py b/doc/conf.py index ffec1b9b..691a3921 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -5,35 +5,33 @@ ROOT = os.path.abspath(os.path.dirname(__file__)) sys.path.insert(1, ROOT) -sys.path.insert(1, os.path.join(ROOT, "..")) +sys.path.insert(1, os.path.join(ROOT, "..", "src")) # -- General configuration ------------------------------------------------ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [ - 'sphinx.ext.autodoc', - 'htmlhidden' -] -autoclass_content = 'both' +extensions = ["sphinx.ext.autodoc", "htmlhidden"] +autoclass_content = "both" # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'Python interface to chemfiles' -copyright = u'2015-2017, Guillaume Fraux — BSD license' +project = "Python interface to chemfiles" +copyright = "2015-2017, Guillaume Fraux — BSD license" def version(): import chemfiles - full_version = chemfiles.__version__.split('-') + + full_version = chemfiles.__version__.split("-") release = full_version[0] - version = '.'.join(release.split('.')[0:2]) + version = ".".join(release.split(".")[0:2]) if len(full_version) > 1: # Developement release release += "-dev" @@ -48,29 +46,27 @@ def version(): exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'bootstrap' +html_theme = "bootstrap" html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() # Add any paths that contain templates here, relative to this directory. templates_path = [os.path.join(ROOT, "templates")] html_theme_options = { - 'navbar_site_name': "Navigation", - 'navbar_pagenav': False, - 'source_link_position': None, - 'bootswatch_theme': "flatly", - 'bootstrap_version': "3", + "navbar_site_name": "Navigation", + "navbar_pagenav": False, + "source_link_position": None, + "bootswatch_theme": "flatly", + "bootstrap_version": "3", } -html_sidebars = { - '**': ['sidebar-toc.html', 'searchbox.html'] -} +html_sidebars = {"**": ["sidebar-toc.html", "searchbox.html"]} # Output file base name for HTML help builder. -htmlhelp_basename = 'chemfiles.py' +htmlhelp_basename = "chemfiles.py" diff --git a/pyproject.toml b/pyproject.toml index 245b4e96..ace23419 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,8 @@ requires = [ "setuptools >=44", "wheel >=0.36", - "scikit-build >=0.11" + "ninja", + "cmake", ] build-backend = "setuptools.build_meta" @@ -17,12 +18,15 @@ skipsdist = True passenv = LIB INCLUDE LIBPATH setenv = CHFL_PY_INTERNAL_CHEMFILES = 1 + commands = - pip install -e . --verbose - coverage run -m unittest discover -s tests -p "*.py" - coverage xml --include="chemfiles/*" -o .tox/coverage.xml + python setup.py install + coverage run --source=chemfiles -m unittest discover -s tests -p "*.py" + coverage xml -o .tox/coverage.xml + deps = - discover + ninja + cmake coverage numpy """ diff --git a/scripts/check-used-functions.py b/scripts/check-used-functions.py index 37f9ea33..eb9a7d76 100755 --- a/scripts/check-used-functions.py +++ b/scripts/check-used-functions.py @@ -4,8 +4,8 @@ effectively used in the chemfiles binding. """ import os -import sys import re +import sys IGNORED = ["chfl_version", "chfl_trajectory_open"] ERROR = False @@ -20,7 +20,7 @@ def error(message): def functions_list(): functions = [] - with open(os.path.join(ROOT, "chemfiles", "ffi.py")) as fd: + with open(os.path.join(ROOT, "src", "chemfiles", "_c_api.py")) as fd: for line in fd: line = line.strip() if line.startswith("# Function"): @@ -31,9 +31,9 @@ def functions_list(): def read_all_binding_functions(): binding_functions = set() - for (dirpath, _, paths) in os.walk(os.path.join(ROOT, "chemfiles")): + for (dirpath, _, paths) in os.walk(os.path.join(ROOT, "src", "chemfiles")): for path in paths: - if path != "ffi.py" and path.endswith(".py"): + if path != "_c_api.py" and path.endswith(".py"): with open(os.path.join(ROOT, dirpath, path)) as fd: file_functions = re.findall(r"(chfl_[a-z A-Z 0-9 _]*)\(", fd.read()) binding_functions.update(file_functions) diff --git a/setup.cfg b/setup.cfg index a028c24a..71b824fd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,6 +26,12 @@ classifiers = [options] zip_safe = False +packages=find: +package_dir= + =src + +[options.packages.find] +where = src [bdist_wheel] universal = 1 diff --git a/setup.py b/setup.py index 0d4bb433..a395ca92 100644 --- a/setup.py +++ b/setup.py @@ -1,18 +1,25 @@ # -*- coding=utf-8 -*- -from wheel.bdist_wheel import bdist_wheel -from skbuild import setup - -import site -import sys import os import re +import site +import subprocess +import sys + +import cmake +import ninja +from setuptools import Extension, setup +from wheel.bdist_wheel import bdist_wheel + +from distutils.command.build_ext import build_ext # type: ignore isort: skip +from distutils.command.install import install as distutils_install # type: ignore isort: skip # workaround https://github.com/pypa/pip/issues/7953 site.ENABLE_USER_SITE = "--user" in sys.argv[1:] # Read the version from chemfiles/__init__.py without importing chemfiles +ROOT = os.path.realpath(os.path.dirname(__file__)) __version__ = re.search( - r'__version__\s*=\s*[\'"]([^\'"]*)[\'"]', open("chemfiles/__init__.py").read() + r'__version__\s*=\s*[\'"]([^\'"]*)[\'"]', open("src/chemfiles/__init__.py").read() ).group(1) @@ -23,18 +30,53 @@ def get_tag(self): return ("py2.py3", "none") + tag[2:] -install_requires = ["numpy"] -if sys.hexversion < 0x03040000: - install_requires.append("enum34") +class cmake_ext(build_ext): + """ + Build the native library using cmake + """ + def run(self): + source_dir = ROOT + build_dir = os.path.join(ROOT, "build", "cmake-build") + install_dir = os.path.join(os.path.realpath(self.build_lib)) -# scikit-build options -cmake_args = [] -if sys.platform.startswith("darwin"): - cmake_args.append("-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.9") + try: + os.makedirs(build_dir) + except OSError: + pass + + cmake_executable = os.path.join(cmake.CMAKE_BIN_DIR, "cmake") + ninja_executable = os.path.join(ninja.BIN_DIR, "ninja") + cmake_options = [ + "-GNinja", + f"-DCMAKE_MAKE_PROGRAM={ninja_executable}", + f"-DCMAKE_INSTALL_PREFIX={install_dir}", + "-DCMAKE_BUILD_TYPE=Release", + "-DBUILD_SHARED_LIBS=ON", + ] + + if sys.platform.startswith("darwin"): + cmake_options.append("-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.9") + + if os.getenv("CHFL_PY_INTERNAL_CHEMFILES"): + cmake_options.append("-DCHFL_PY_INTERNAL_CHEMFILES=ON") + + ninja_args = [] + + subprocess.run( + [cmake_executable, source_dir, *cmake_options], + cwd=build_dir, + check=True, + ) + subprocess.run( + [cmake_executable, "--build", build_dir, "--target", "install"], + check=True, + ) -if os.getenv("CHFL_PY_INTERNAL_CHEMFILES"): - cmake_args.append("-DCHFL_PY_INTERNAL_CHEMFILES=ON") + +install_requires = ["numpy"] +if sys.hexversion < 0x03040000: + install_requires.append("enum34") def _get_lib_ext(): @@ -52,14 +94,18 @@ def _get_lib_ext(): setup( version=__version__, install_requires=install_requires, - cmdclass={"bdist_wheel": universal_wheel}, - cmake_args=cmake_args, - packages=["chemfiles"], - package_data={ - "chemfiles": [ - "*" + _get_lib_ext(), - "bin/*" + _get_lib_ext(), - ] + ext_modules=[ + # only declare the extension, it is built & copied as required by cmake + # in the build_ext command + Extension(name="chemfiles", sources=[]), + ], + cmdclass={ + "build_ext": cmake_ext, + "bdist_wheel": universal_wheel, + # HACK: do not use the new setuptools install implementation, it tries + # to install the package with `easy_install`, which fails to resolve the + # freshly installed package and tries to load it from pypi. + "install": distutils_install, }, exclude_package_data={ "chemfiles": [ diff --git a/chemfiles/.gitignore b/src/chemfiles/.gitignore similarity index 100% rename from chemfiles/.gitignore rename to src/chemfiles/.gitignore diff --git a/chemfiles/__init__.py b/src/chemfiles/__init__.py similarity index 100% rename from chemfiles/__init__.py rename to src/chemfiles/__init__.py diff --git a/chemfiles/_c_api.py b/src/chemfiles/_c_api.py similarity index 100% rename from chemfiles/_c_api.py rename to src/chemfiles/_c_api.py diff --git a/chemfiles/_c_lib.py b/src/chemfiles/_c_lib.py similarity index 100% rename from chemfiles/_c_lib.py rename to src/chemfiles/_c_lib.py diff --git a/chemfiles/atom.py b/src/chemfiles/atom.py similarity index 100% rename from chemfiles/atom.py rename to src/chemfiles/atom.py diff --git a/chemfiles/cell.py b/src/chemfiles/cell.py similarity index 100% rename from chemfiles/cell.py rename to src/chemfiles/cell.py diff --git a/chemfiles/frame.py b/src/chemfiles/frame.py similarity index 100% rename from chemfiles/frame.py rename to src/chemfiles/frame.py diff --git a/chemfiles/misc.py b/src/chemfiles/misc.py similarity index 100% rename from chemfiles/misc.py rename to src/chemfiles/misc.py diff --git a/chemfiles/property.py b/src/chemfiles/property.py similarity index 100% rename from chemfiles/property.py rename to src/chemfiles/property.py diff --git a/chemfiles/residue.py b/src/chemfiles/residue.py similarity index 100% rename from chemfiles/residue.py rename to src/chemfiles/residue.py diff --git a/chemfiles/selection.py b/src/chemfiles/selection.py similarity index 100% rename from chemfiles/selection.py rename to src/chemfiles/selection.py diff --git a/chemfiles/topology.py b/src/chemfiles/topology.py similarity index 100% rename from chemfiles/topology.py rename to src/chemfiles/topology.py diff --git a/chemfiles/trajectory.py b/src/chemfiles/trajectory.py similarity index 100% rename from chemfiles/trajectory.py rename to src/chemfiles/trajectory.py diff --git a/chemfiles/utils.py b/src/chemfiles/utils.py similarity index 100% rename from chemfiles/utils.py rename to src/chemfiles/utils.py