diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d39769f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: + push: + branches: [master, main] + pull_request: + branches: [master, main] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - run: pip install ruff + - run: ruff check atropos/ + + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.11", "3.12"] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install --upgrade pip wheel + pip install Cython + pip install -e ".[test]" + - name: Run tests + run: pytest tests/ diff --git a/atropos/__init__.py b/atropos/__init__.py index 96be2e2..8c7bf21 100644 --- a/atropos/__init__.py +++ b/atropos/__init__.py @@ -4,9 +4,11 @@ import os import sys -from atropos._version import get_versions -__version__ = get_versions()['version'] -del get_versions +try: + from importlib.metadata import version as _get_version + __version__ = _get_version("atropos") +except Exception: + __version__ = "0.0.0" class AtroposError(Exception): """Base class for Atropos-specific errors. diff --git a/atropos/commands/__init__.py b/atropos/commands/__init__.py index 3b0f5bf..c707ad0 100644 --- a/atropos/commands/__init__.py +++ b/atropos/commands/__init__.py @@ -225,6 +225,15 @@ def parse_command(args): "Error executing command: %s", command_name, exc_info=err) return 2 +def execute_cli_main(): + """Entry point for console_scripts. + + Calls execute_cli with sys.argv and exits with the return code. + """ + import sys + sys.exit(execute_cli(sys.argv[1:])) + + def print_subcommands(): """Prints usage message listing the available subcommands. """ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..89bdd58 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,60 @@ +[build-system] +requires = ["setuptools>=64", "Cython>=0.25.2"] +build-backend = "setuptools.build_meta" + +[project] +name = "atropos" +version = "1.1.29" +description = "trim adapters from high-throughput sequencing reads" +readme = {file = "README.md", content-type = "text/markdown"} +license = {text = "MIT"} +requires-python = ">=3.10" +authors = [ + {name = "John Didion", email = "john.didion@nih.gov"}, +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering :: Bio-Informatics", + "License :: OSI Approved :: MIT License", + "License :: Public Domain", + "Natural Language :: English", + "Programming Language :: Cython", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] + +[project.urls] +Homepage = "https://atropos.readthedocs.org/" +Repository = "https://github.com/jdidion/atropos" + +[project.scripts] +atropos = "atropos.commands:execute_cli_main" + +[project.optional-dependencies] +progressbar = ["progressbar2"] +tqdm = ["tqdm"] +khmer = ["khmer"] +pysam = ["pysam"] +jinja = ["jinja2"] +sra = ["srastream>=0.1.3"] +test = ["pytest", "pytest-timeout"] + +[tool.setuptools.packages.find] +include = ["atropos*"] + +[tool.setuptools.package-data] +atropos = ["adapters/*.fa", "commands/**/templates/*"] + +[tool.ruff] +target-version = "py310" +line-length = 100 + +[tool.ruff.lint] +select = ["E", "F", "W", "I"] +ignore = ["E501"] + +[tool.pytest.ini_options] +testpaths = ["tests"] diff --git a/setup.cfg b/setup.cfg index 7b014fa..b88034e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,10 +1,2 @@ [metadata] -description-file = README - -[versioneer] -VCS = git -style = pep440 -versionfile_source = atropos/_version.py -versionfile_build = atropos/_version.py -tag_prefix = -parentdir_prefix = atropos- +description-file = README.md diff --git a/setup.py b/setup.py index 2ec4bea..fa11718 100644 --- a/setup.py +++ b/setup.py @@ -1,30 +1,24 @@ """ -Build atropos. +Build Cython extensions for atropos. -Cython is run when +This setup.py is retained solely for building C extensions from .pyx files. +All project metadata lives in pyproject.toml. + +Cython is run when: * no pre-generated C sources are found, * or the pre-generated C sources are out of date, * or when --cython is given on the command line. """ -import codecs -import os.path -import sys +import os -from setuptools import setup, Extension, find_packages -from distutils.version import LooseVersion -from distutils.command.sdist import sdist as _sdist -from distutils.command.build_ext import build_ext as _build_ext +from setuptools import setup, Extension +from setuptools.command.build_ext import build_ext as _build_ext +from setuptools.command.sdist import sdist as _sdist -import versioneer MIN_CYTHON_VERSION = "0.25.2" -if sys.version_info < (3, 3): - sys.stdout.write("At least Python 3.3 is required.\n") - sys.exit(1) - - def out_of_date(_extensions): """ Check whether any pyx source is newer than the corresponding generated @@ -71,22 +65,22 @@ def no_cythonize(_extensions, **_ignore): def check_cython_version(): - """Exit if Cython was not found or is too old""" + """Exit if Cython was not found or is too old.""" + from packaging.version import Version + try: from Cython import __version__ as cyversion except ImportError: - sys.stdout.write( - "ERROR: Cython is not installed. Install at least Cython version " + raise RuntimeError( + "Cython is not installed. Install at least Cython version " + str(MIN_CYTHON_VERSION) - + " to continue.\n" + + " to continue." ) - sys.exit(1) - if LooseVersion(cyversion) < LooseVersion(MIN_CYTHON_VERSION): - sys.stdout.write( - "ERROR: Your Cython is at version '{}' but at least version '{}' " - "is required.\n".format(cyversion, MIN_CYTHON_VERSION) + if Version(cyversion) < Version(MIN_CYTHON_VERSION): + raise RuntimeError( + "Your Cython is at version '{}' but at least version '{}' " + "is required.".format(cyversion, MIN_CYTHON_VERSION) ) - sys.exit(1) extensions = [ @@ -98,12 +92,8 @@ def check_cython_version(): Extension("atropos.io._seqio", sources=["atropos/io/_seqio.pyx"]), ] -cmdclass = versioneer.get_cmdclass() -versioneer_build_ext = cmdclass.get("build_ext", _build_ext) -versioneer_sdist = cmdclass.get("sdist", _sdist) - -class BuildExt(versioneer_build_ext): +class BuildExt(_build_ext): def run(self): # If we encounter a PKG-INFO file, then this is likely a .tar.gz/.zip # file retrieved from PyPI that already includes the pre-cythonized @@ -120,67 +110,17 @@ def run(self): _build_ext.run(self) -cmdclass["build_ext"] = BuildExt - - -class SDist(versioneer_sdist): +class SDist(_sdist): def run(self): # Make sure the compiled Cython files in the distribution are up-to-date from Cython.Build import cythonize check_cython_version() cythonize(extensions) - versioneer_sdist.run(self) - - -cmdclass["sdist"] = SDist + _sdist.run(self) setup( - name="atropos", - version=versioneer.get_version(), - cmdclass=cmdclass, - author="John Didion", - author_email="john.didion@nih.gov", - url="https://atropos.readthedocs.org/", - description="trim adapters from high-throughput sequencing reads", - long_description=codecs.open( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "README.md"), - "rb", - "utf-8", - ).read(), - long_description_content_type="text/markdown", - license="MIT", ext_modules=extensions, - packages=find_packages(), - scripts=["bin/atropos"], - package_data={"atropos": ["adapters/*.fa", "commands/**/templates/*"]}, - tests_require=["pytest", "pytest-timeout"], # , "jinja2", "pysam"], - extras_require={ - "progressbar": ["progressbar2"], - "tqdm": ["tqdm"], - "khmer": ["khmer"], - "pysam": ["pysam"], - "jinja": ["jinja2"], - "sra": ["srastream>=0.1.3"], - }, - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "Intended Audience :: Science/Research", - "Topic :: Scientific/Engineering :: Bio-Informatics", - "License :: OSI Approved :: MIT License", - "License :: Public Domain", - "Natural Language :: English", - "Programming Language :: Cython", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - ], + cmdclass={"build_ext": BuildExt, "sdist": SDist}, )