Skip to content
Snippets Groups Projects
Commit f3733712 authored by Martin Larralde's avatar Martin Larralde
Browse files

Add setuptools configuration files with Cython support

parent 879f437f
No related branches found
No related tags found
No related merge requests found
# https://gist.github.com/althonos/6914b896789d3f2078d1e6237642c35c
# --- Setuptools metadata ---------------------------------------------------
[metadata]
name = pyFastANI
version = attr: pyfastani.__version__
author = Martin Larralde
author_email = martin.larralde@embl.de
url = https://github.com/althonos/pyFastANI
description = Cython bindings and Python interface to FastANI.
long_description = file: README.md
long_description_content_type = text/markdown
license = MIT
platform = posix
keywords = bioinformatics, genomics, average, nucleotide, identity
classifier =
Development Status :: 3 - Alpha
Intended Audience :: Developers
Intended Audience :: Science/Research
License :: OSI Approved :: MIT License
Operating System :: OS Independent
Programming Language :: C++
Programming Language :: Cython
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: Implementation :: PyPy
Topic :: Scientific/Engineering :: Bio-Informatics
Topic :: Scientific/Engineering :: Medical Science Apps.
Typing :: Typed
project_urls =
Documentation = https://pyfastani.readthedocs.io/en/stable/
Bug Tracker = https://github.com/althonos/pyFastANI/issues
Changelog = https://github.com/althonos/pyFastANI/blob/master/CHANGELOG.md
Coverage = https://codecov.io/gh/althonos/pyFastANI/
Builds = https://github.com/althonos/pyFastANI/actions/
Zenodo = https://doi.org/10.5281/zenodo.4270012
PyPI = https://pypi.org/project/pyFastANI
[options]
zip_safe = false
packages = pyfastani
python_requires = >=3.6
test_suite = tests
include_package_data = true
setup_requires =
setuptools >=46.4
cython ~=0.29.16
[options.package_data]
pyfastani = py.typed, *.pyi
# --- Python tools configuration --------------------------------------------
[coverage:run]
plugins = Cython.Coverage
[coverage:report]
include = pyfastani/*.pyx
show_missing = true
exclude_lines =
pragma: no cover
if typing.TYPE_CHECKING:
@abc.abstractmethod
@abc.abstractproperty
raise NotImplementedError
return NotImplemented
raise UnexpectedError
raise AllocationError
[mypy]
disallow_any_decorated = true
disallow_any_generics = true
disallow_any_unimported = false
disallow_subclassing_any = false
disallow_untyped_calls = true
disallow_untyped_defs = true
ignore_missing_imports = true
warn_unused_ignores = true
warn_return_any = true
setup.py 0 → 100644
#!/usr/bin/env python
# coding: utf-8
import collections
import configparser
import glob
import itertools
import os
import platform
import re
import sys
import subprocess
from unittest import mock
import setuptools
from distutils import log
from distutils.command.clean import clean as _clean
from distutils.errors import CompileError
from setuptools.command.build_ext import build_ext as _build_ext
from setuptools.command.sdist import sdist as _sdist
from setuptools.extension import Extension, Library
try:
from Cython.Build import cythonize
except ImportError as err:
cythonize = err
# --- Constants --------------------------------------------------------------
PLATFORM_MACHINE = platform.machine()
SYS_IMPLEMENTATION = sys.implementation.name
# --- Utils ------------------------------------------------------------------
def _split_multiline(value):
value = value.strip()
sep = max('\n,;', key=value.count)
return list(filter(None, map(lambda x: x.strip(), value.split(sep))))
# --- `setup.py` commands ----------------------------------------------------
class sdist(_sdist):
"""A `sdist` that generates a `pyproject.toml` on the fly.
"""
def run(self):
# build `pyproject.toml` from `setup.cfg`
c = configparser.ConfigParser()
c.add_section("build-system")
c.set("build-system", "requires", str(self.distribution.setup_requires))
c.set("build-system", 'build-backend', '"setuptools.build_meta"')
with open("pyproject.toml", "w") as pyproject:
c.write(pyproject)
# run the rest of the packaging
_sdist.run(self)
class build_ext(_build_ext):
"""A `build_ext` that disables optimizations if compiled in debug mode.
"""
def finalize_options(self):
_build_ext.finalize_options(self)
self._clib_cmd = self.get_finalized_command("build_clib")
self._clib_cmd.force = self.force
self._clib_cmd.debug = self.debug
def run(self):
# check `cythonize` is available
if isinstance(cythonize, ImportError):
raise RuntimeError("Cython is required to run `build_ext` command") from cythonize
# use debug directives with Cython if building in debug mode
cython_args = {"include_path": ["include", "pyfastani"], "compiler_directives": {}}
cython_args["compile_time_env"] = {"SYS_IMPLEMENTATION": SYS_IMPLEMENTATION}
if self.force:
cython_args["force"] = True
if self.debug:
cython_args["annotate"] = True
cython_args["compiler_directives"]["warn.undeclared"] = True
cython_args["compiler_directives"]["warn.unreachable"] = True
cython_args["compiler_directives"]["warn.maybe_uninitialized"] = True
cython_args["compiler_directives"]["warn.unused"] = True
cython_args["compiler_directives"]["warn.unused_arg"] = True
cython_args["compiler_directives"]["warn.unused_result"] = True
cython_args["compiler_directives"]["warn.multiple_declarators"] = True
cython_args["compiler_directives"]["profile"] = True
else:
cython_args["compiler_directives"]["boundscheck"] = False
cython_args["compiler_directives"]["wraparound"] = False
cython_args["compiler_directives"]["cdivision"] = True
# cythonize and patch the extensions
self.extensions = cythonize(self.extensions, **cython_args)
for ext in self.extensions:
ext._needs_stub = False
# # update the compiler include and link dirs to use the
# # temporary build folder so that the platform-specific headers
# # and static libs can be found
# check the libraries have been built already
if not self.distribution.have_run["build_clib"]:
self._clib_cmd.run()
# build the extensions as normal
_build_ext.run(self)
def build_extension(self, ext):
# update compile flags if compiling in debug mode
if self.debug:
if self.compiler.compiler_type in {"unix", "cygwin", "mingw32"}:
ext.extra_compile_args.append("-Og")
ext.extra_compile_args.append("--coverage")
ext.extra_link_args.append("--coverage")
elif self.compiler.compiler_type == "msvc":
ext.extra_compile_args.append("/Od")
if sys.implementation.name == "cpython":
ext.define_macros.append(("CYTHON_TRACE_NOGIL", 1))
else:
ext.define_macros.append(("CYTHON_WITHOUT_ASSERTIONS", 1))
# build the rest of the extension as normal
_build_ext.build_extension(self, ext)
class clean(_clean):
def run(self):
source_dir_abs = os.path.join(os.path.dirname(__file__), "pyfastani")
source_dir = os.path.relpath(source_dir_abs)
patterns = ["*.html"]
if self.all:
patterns.extend(["*.so", "*.c"])
for pattern in patterns:
for file in glob.glob(os.path.join(source_dir, pattern)):
log.info("removing {!r}".format(file))
os.remove(file)
_clean.run(self)
# --- Cython extensions ------------------------------------------------------
extensions = [
Extension(
"pyfastani._fastani",
[os.path.join("pyfastani", "_utils.cpp"), os.path.join("pyfastani", "_fastani.pyx")],
language="c++",
libraries=["gsl", "gslcblas", "stdc++", "z", "m"],
include_dirs=["include", "pyfastani", os.path.join("vendor", "FastANI", "src")],
extra_compile_args=["-std=c++11"],
extra_link_args=["-std=c++11"],
)
]
# --- Setup ------------------------------------------------------------------
setuptools.setup(
ext_modules=extensions,
# libraries=libraries,
cmdclass=dict(
build_ext=build_ext,
clean=clean,
sdist=sdist,
),
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment