From a61a743b90948eea7cd8a7e1571176bb9c4d60c6 Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Fri, 3 Feb 2023 16:01:55 +0100 Subject: [PATCH] DevOps: adopt PEP 621 and move build spec to `pyproject.toml` (#18) Following PEP 621 it is now possible to fully define the build procedure of your package in `pyproject.toml`. Since this PEP is now well supported, and for example `pip` can use it, we migrate to it since it provides a bunch of benefits: * No longer need the deprecated `setup.py` to install the package, nor the custom `setup.json`. * Version number and description are now dynamically fetched from the package. So there is no need to manually update the `setup.json` and there is no need for the custom version validation utility script. * The `MANIFEST.in` is no longer necessary. The `flit` build tool will automatically include anything. The `pyproject.toml` has a tool section for `flit` that excludes the `tests` and `docs` folders. * All configuration of tools are consolidated in `pyproject.toml`. This allows to remove `.style.yapf` and configuration options in the `.pre-commit-config.yaml`. Also the `LICENSE` file is renamed to `LICENSE.txt` to use a correct file extension. --- .pre-commit-config.yaml | 26 ++------ .style.yapf | 8 --- LICENSE => LICENSE.txt | 0 MANIFEST.in | 2 - pyproject.toml | 108 ++++++++++++++++++++++++++++--- setup.json | 56 ---------------- setup.py | 35 ---------- utils/validate_version_number.py | 53 --------------- 8 files changed, 104 insertions(+), 184 deletions(-) delete mode 100644 .style.yapf rename LICENSE => LICENSE.txt (100%) delete mode 100644 MANIFEST.in delete mode 100644 setup.json delete mode 100755 setup.py delete mode 100644 utils/validate_version_number.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1876aeb..f2a46d4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,15 +17,12 @@ repos: rev: '0.55' hooks: - id: flynt - args: [ - '--line-length=120', - '--fail-on-change', - ] - repo: https://github.com/PyCQA/pydocstyle - rev: 5.0.2 + rev: 6.1.1 hooks: - id: pydocstyle + additional_dependencies: ['toml'] exclude: &exclude_files > (?x)^( aiida_abinit/parsers/.*| @@ -33,15 +30,15 @@ repos: tests/.*(?- - (?x)^( - setup.json| - aiida_abinit/__init__.py| - ./utils/validate_version_number.py| - )$ - pass_filenames: false diff --git a/.style.yapf b/.style.yapf deleted file mode 100644 index 4d6bfc7..0000000 --- a/.style.yapf +++ /dev/null @@ -1,8 +0,0 @@ -[style] -based_on_style = google -align_closing_bracket_with_visual_indent = true -coalesce_brackets = true -column_limit = 120 -dedent_closing_brackets = true -indent_dictionary_value = false -split_arguments_when_comma_terminated = true diff --git a/LICENSE b/LICENSE.txt similarity index 100% rename from LICENSE rename to LICENSE.txt diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 2862132..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -include setup.json -include LICENSE diff --git a/pyproject.toml b/pyproject.toml index 55dc586..59c079f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,88 @@ [build-system] -requires = ['setuptools>=40.8.0', 'wheel', 'reentry~=1.3', 'fastentrypoints~=0.12'] -build-backend = 'setuptools.build_meta:__legacy__' +requires = ['flit_core >=3.4,<4'] +build-backend = 'flit_core.buildapi' + +[project] +name = 'aiida-abinit' +dynamic = ['description', 'version'] +authors = [{name = 'Samuel Ponce', email = 'samuel.pon@gmail.com'}] +readme = 'README.md' +license = {file = 'LICENSE.txt'} +classifiers = [ + 'Development Status :: 4 - Beta', + 'Framework :: AiiDA', + 'License :: OSI Approved :: MIT License', + 'Operating System :: POSIX :: Linux', + 'Operating System :: MacOS :: MacOS X', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', +] +keywords = ['aiida', 'abinit'] +requires-python = '>=3.8' +dependencies = [ + 'aiida_core[atomic_tools]~=1.6.3,<3.0.0', + 'aiida-pseudo~=0.6.1', + 'abipy>=0.8.0', + 'packaging', + 'psycopg2-binary~=2.8.3', + 'pymatgen>=2022.1.20', + 'numpy', + 'importlib_resources' +] + +[project.urls] +Home = 'https://github.com/sponce24/aiida-abinit' +Source = 'https://github.com/sponce24/aiida-abinit' + +[project.optional-dependencies] +docs = [ + 'sphinx', + 'docutils', + 'sphinx-copybutton~=0.3.0', + 'sphinx-book-theme~=0.1.0', + 'sphinx-click~=2.7.1' +] +pre-commit = [ + 'pre-commit~=2.2', + 'pylint==2.6.0' +] +tests = [ + 'pgtest~=1.3', + 'pytest~=6.0', + 'pytest-regressions~=1.0' +] + +[project.entry-points.'aiida.calculations'] +'abinit' = 'aiida_abinit.calculations:AbinitCalculation' + +[project.entry-points.'aiida.parsers'] +'abinit' = 'aiida_abinit.parsers:AbinitParser' + +[project.entry-points.'aiida.workflows'] +'abinit.base' = 'aiida_abinit.workflows.base:AbinitBaseWorkChain' + +[tool.flit.module] +name = 'aiida_abinit' + +[tool.flit.sdist] +exclude = [ + '.github/', + 'docs/', + 'tests/', +] + +[tool.flynt] +line-length = 120 +fail-on-change = true + +[tool.pydocstyle] +ignore = [ + 'D104', + 'D202', + 'D203', + 'D213' +] [tool.pylint.format] max-line-length = 120 @@ -37,26 +119,36 @@ good-names = [ ] [tool.pytest.ini_options] -minversion = '6.0' -testpaths = [ - 'tests', -] filterwarnings = [ + 'ignore:Creating AiiDA configuration folder.*:UserWarning', 'ignore::DeprecationWarning:frozendict:', 'ignore::DeprecationWarning:pkg_resources:', 'ignore::DeprecationWarning:reentry:', 'ignore::DeprecationWarning:sqlalchemy_utils:', ] +minversion = '6.0' +testpaths = [ + 'tests', +] + +[tool.yapf] +align_closing_bracket_with_visual_indent = true +based_on_style = 'google' +coalesce_brackets = true +column_limit = 120 +dedent_closing_brackets = true +indent_dictionary_value = false +split_arguments_when_comma_terminated = true [tool.tox] legacy_tox_ini = """ [tox] -envlist = py37 +envlist = py38 [testenv] usedevelop=True -[testenv:py{36,37,38,39}] +[testenv:py{38,39}] extras = tests commands = pytest {posargs} diff --git a/setup.json b/setup.json deleted file mode 100644 index 3dfb15c..0000000 --- a/setup.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "author": "Samuel Ponce", - "author_email": "samuel.pon@gmail.com", - "classifiers": [ - "Framework :: AiiDA", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Development Status :: 4 - Beta" - ], - "description": "An AiiDA plugin for ABINIT.", - "entry_points": { - "aiida.calculations": [ - "abinit = aiida_abinit.calculations:AbinitCalculation" - ], - "aiida.parsers": [ - "abinit = aiida_abinit.parsers:AbinitParser" - ], - "aiida.workflows": [ - "abinit.base = aiida_abinit.workflows.base:AbinitBaseWorkChain" - ] - }, - "extras_require": { - "pre-commit": [ - "pre-commit~=2.2", - "pylint==2.6.0" - ], - "tests": [ - "pgtest~=1.3", - "pytest~=6.0", - "pytest-regressions~=1.0" - ], - "docs": [ - "sphinx", - "docutils", - "sphinx-copybutton~=0.3.0", - "sphinx-book-theme~=0.1.0", - "sphinx-click~=2.7.1" - ] - }, - "install_requires": [ - "aiida_core[atomic_tools]~=1.6.3,<3.0.0", - "aiida-pseudo~=0.6.1", - "abipy>=0.8.0", - "packaging", - "psycopg2-binary~=2.8.3", - "pymatgen>=2022.1.20", - "numpy", - "importlib_resources" - ], - "license": "MIT License", - "name": "aiida-abinit", - "python_requires": ">=3.8", - "url": "https://github.com/sponce24/aiida-abinit", - "version": "0.3.0" -} diff --git a/setup.py b/setup.py deleted file mode 100755 index a7d7596..0000000 --- a/setup.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -"""Setup for the `aiida-abinit` plugin which provides an interface to ABINIT for `aiida-core`.""" -try: - import fastentrypoints # pylint: disable=unused-import -except ImportError: - # This should only occur when building the package, i.e. for `python setup.py sdist/bdist_wheel` - pass - - -def setup_package(): - """Set up the package.""" - import json - from setuptools import setup, find_packages - - filename_setup_json = 'setup.json' - filename_description = 'README.md' - - with open(filename_setup_json, 'r') as handle: - setup_json = json.load(handle) - - with open(filename_description, 'r') as handle: - description = handle.read() - - setup( - include_package_data=True, - packages=find_packages(), - reentry_register=True, - long_description=description, - long_description_content_type='text/markdown', - **setup_json - ) - - -if __name__ == '__main__': - setup_package() diff --git a/utils/validate_version_number.py b/utils/validate_version_number.py deleted file mode 100644 index 17e8bbb..0000000 --- a/utils/validate_version_number.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -"""Pre-commit script to ensure that version numbers in `setup.json` and `aiida_abinit/__init__.py` match.""" -import os -import json -import sys - -import click - -FILEPATH_SCRIPT = os.path.split(os.path.realpath(__file__))[0] -FILEPATH_ROOT = os.path.join(FILEPATH_SCRIPT, os.pardir) -FILENAME_SETUP_JSON = 'setup.json' -FILEPATH_SETUP_JSON = os.path.join(FILEPATH_ROOT, FILENAME_SETUP_JSON) - - -def get_setup_json(): - """Return the `setup.json` as a python dictionary.""" - with open(FILEPATH_SETUP_JSON, 'r') as handle: - setup_json = json.load(handle) - - return setup_json - - -@click.group() -def cli(): - """Define the main CLI group.""" - - -@cli.command('version') -def validate_version(): - """Check that version numbers in `setup.json` and `aiida_abinit/__init__.py` match.""" - sys.path.insert(0, FILEPATH_ROOT) - import aiida_abinit # pylint: disable=wrong-import-position - version = aiida_abinit.__version__ - - setup_content = get_setup_json() - - if version != setup_content['version']: - click.echo('Version number mismatch detected:') - click.echo(f"Version number in '{FILENAME_SETUP_JSON}': {setup_content['version']}") - click.echo(f"Version number in 'aiida_abinit/__init__.py': {version}") - click.echo(f"Updating version in '{FILENAME_SETUP_JSON}' to: {version}") - - setup_content['version'] = version - with open(FILEPATH_SETUP_JSON, 'w') as handle: - # Write with indentation of two spaces and explicitly define separators to not have spaces at end of lines - json.dump(setup_content, handle, indent=4, separators=(',', ': ')) - - sys.exit(1) - - -if __name__ == '__main__': - cli() # pylint: disable=no-value-for-parameter