From fecade8a4eb56e89211fe3ca701b8d67ad56f13f Mon Sep 17 00:00:00 2001 From: jdhughes-usgs Date: Fri, 7 Jul 2023 13:05:33 -0500 Subject: [PATCH] build: update pyproject.toml to replace setup.cfg (#134) ]* update README.md * update version to 1.2.9.dev0 * add pytest conftest.py * install test requirements for CI from pyproject.toml --- .flake8 | 29 ++++++++ .github/common/install-python.sh | 9 --- .github/workflows/main.yml | 3 +- .github/workflows/pymake-gcc.yml | 10 ++- .github/workflows/pymake-requests.yml | 3 +- README.md | 19 +++-- autotest/conftest.py | 101 ++++++++++++++++++++++++++ pymake/config.py | 2 +- pyproject.toml | 90 ++++++++++++++++++++++- setup.cfg | 72 ------------------ setup.py | 2 +- 11 files changed, 243 insertions(+), 97 deletions(-) create mode 100644 .flake8 delete mode 100755 .github/common/install-python.sh create mode 100644 autotest/conftest.py delete mode 100644 setup.cfg diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..fdfc7cc5 --- /dev/null +++ b/.flake8 @@ -0,0 +1,29 @@ +[flake8] +exclude = + .git + __pycache__ + build + dist + examples + autotest +ignore = + # https://flake8.pycqa.org/en/latest/user/error-codes.html + F401, + # https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes + # Indentation + E121, E122, E126, E127, E128, + # Whitespace + E203, E221, E222, E226, E231, E241, + # Import + E402, + # Line length + E501, E502, + # Statement + E722, E741, + # Whitespace warning + W291, W292, W293, + # Blank line warning + W391, + # Line break warning + W503, W504 +statistics = True \ No newline at end of file diff --git a/.github/common/install-python.sh b/.github/common/install-python.sh deleted file mode 100755 index 80d8a92c..00000000 --- a/.github/common/install-python.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -python -m pip install --upgrade pip -pip install wheel -pip install pytest pytest-cov pytest-xdist pytest-dependency flaky coverage -pip install appdirs matplotlib -pip install https://github.com/modflowpy/flopy/zipball/develop -pip install . - diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2273bb09..b76d9b0a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -39,7 +39,8 @@ jobs: - name: Install python packages run: | - .github/common/install-python.sh + pip install --upgrade pip + pip install ".[test]" - name: Download examples for pytest runs run: | diff --git a/.github/workflows/pymake-gcc.yml b/.github/workflows/pymake-gcc.yml index 0f6bdc4b..5d645120 100644 --- a/.github/workflows/pymake-gcc.yml +++ b/.github/workflows/pymake-gcc.yml @@ -36,7 +36,8 @@ jobs: - name: Install python packages run: | - .github/common/install-python.sh + pip install --upgrade pip + pip install ".[test]" - name: Install GNU Fortran uses: modflowpy/install-gfortran-action@v1 @@ -85,7 +86,8 @@ jobs: - name: Install python packages run: | - .github/common/install-python.sh + pip install --upgrade pip + pip install ".[test]" - name: Setup symbolic link to gfortran on Linux run: | @@ -140,7 +142,8 @@ jobs: - name: Install python packages run: | - .github/common/install-python.sh + pip install --upgrade pip + pip install ".[test]" - name: Install GNU Fortran uses: modflowpy/install-gfortran-action@v1 @@ -150,5 +153,6 @@ jobs: .github/common/download-examples.sh - name: Run pytest + working-directory: ./autotest run: | pytest -v --dist=loadfile -n=auto -m="base" --durations=0 diff --git a/.github/workflows/pymake-requests.yml b/.github/workflows/pymake-requests.yml index 26ad0d8b..870871e9 100644 --- a/.github/workflows/pymake-requests.yml +++ b/.github/workflows/pymake-requests.yml @@ -28,7 +28,8 @@ jobs: - name: Install python packages run: | - .github/common/install-python.sh + pip install --upgrade pip + pip install ".[test]" - name: Run pytest working-directory: ./autotest diff --git a/README.md b/README.md index 6b95bf47..0ff5041e 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,20 @@ Python package for building MODFLOW-based programs from source files. -### Version 1.2.8 +### Version 1.2.9.dev0 -![pymake continuous integration](https://github.com/modflowpy/pymake/workflows/pymake%20continuous%20integration/badge.svg) +[![PyPI Version](https://img.shields.io/pypi/v/mfpymake.png)](https://pypi.python.org/pypi/mfpymake) +[![Anaconda Version](https://anaconda.org/conda-forge/mfpymake/badges/version.svg)](https://anaconda.org/conda-forge/mfpymake) +[![pymake continuous integration](https://github.com/modflowpy/pymake/workflows/pymake%20continuous%20integration/badge.svg)](https://github.com/modflowpy/pymake/actions/workflows/main.yml) [![codecov](https://codecov.io/gh/modflowpy/pymake/branch/master/graph/badge.svg)](https://codecov.io/gh/modflowpy/pymake) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/fe4275a3cfb84acf9c84aba7b4ae2086)](https://www.codacy.com/gh/modflowpy/pymake/dashboard?utm_source=github.com&utm_medium=referral&utm_content=modflowpy/pymake&utm_campaign=Badge_Grade) -[![Documentation Status](https://readthedocs.org/projects/mfpymake/badge/?version=latest)](https://mfpymake.readthedocs.io/en/latest/?badge=latest) -[![PyPI Version](https://img.shields.io/pypi/v/mfpymake.png)](https://pypi.python.org/pypi/mfpymake) +[![Documentation Status](https://readthedocs.org/projects/mfpymake/badge/?version=latest)](https://mfpymake.readthedocs.io/en/latest/?badge=latest) This is a python package for compiling MODFLOW-based and other Fortran, C, and C++ programs. The package determines the build order using a directed acyclic graph and then compiles the source files using GNU compilers (`gcc`, `g++`, -`gfortran`), Clang compilers (`clang`, `clang++`), Intel compilers (`ifort`, -`icl`, `icc`, `mpiifort`), or the CRAY Fortran compiler (`ftn`). +`gfortran`), Clang compilers (`clang`, `clang++`), or the Intel compilers (`ifort`, +`icl`, `icc`, `mpiifort`). pymake can be run from the command line or it can be called from within python. By default, pymake sets the optimization level, Fortran flags, C/C++ flags, and @@ -233,6 +234,12 @@ To install pymake using pip type: pip install mfpymake ``` +To install pymake using conda type: + +``` +conda install -c conda-forge mfpymake +``` + To install pymake directly from the git repository type: ``` diff --git a/autotest/conftest.py b/autotest/conftest.py new file mode 100644 index 00000000..5df2876b --- /dev/null +++ b/autotest/conftest.py @@ -0,0 +1,101 @@ +import contextlib +import os +import re +from importlib import metadata +from pathlib import Path + +import pytest + +# import modflow-devtools fixtures + +pytest_plugins = ["modflow_devtools.fixtures"] + + +# constants + + +# misc utilities +@contextlib.contextmanager +def working_directory(path): + """Changes working directory and returns to previous on exit.""" + prev_cwd = os.getcwd() + os.chdir(path) + try: + yield + finally: + os.chdir(prev_cwd) + + +def get_pymake_appdir(): + appdir = Path.home() / ".pymake" + appdir.mkdir(parents=True, exist_ok=True) + return appdir + + +def get_project_root_path() -> Path: + return Path(__file__).parent.parent + + +# path fixtures + + +# pytest configuration hooks + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_makereport(item, call): + # this is necessary so temp dir fixtures can + # inspect test results and check for failure + # (see https://doc.pytest.org/en/latest/example/simple.html#making-test-result-information-available-in-fixtures) + + outcome = yield + rep = outcome.get_result() + + # report attribute for each phase (setup, call, teardown) + # we're only interested in result of the function call + setattr(item, "rep_" + rep.when, rep) + + +def pytest_report_header(config): + """Header for pytest to show versions of packages.""" + + required = [] + extra = {} + for item in metadata.requires("flopy"): + pkg_name = re.findall(r"[a-z0-9_\-]+", item, re.IGNORECASE)[0] + if res := re.findall("extra == ['\"](.+)['\"]", item): + assert len(res) == 1, item + pkg_extra = res[0] + if pkg_extra not in extra: + extra[pkg_extra] = [] + extra[pkg_extra].append(pkg_name) + else: + required.append(pkg_name) + + processed = set() + lines = [] + items = [] + for name in required: + processed.add(name) + try: + version = metadata.version(name) + items.append(f"{name}-{version}") + except metadata.PackageNotFoundError: + items.append(f"{name} (not found)") + lines.append("required packages: " + ", ".join(items)) + installed = [] + not_found = [] + for name in extra["optional"]: + if name in processed: + continue + processed.add(name) + try: + version = metadata.version(name) + installed.append(f"{name}-{version}") + except metadata.PackageNotFoundError: + not_found.append(name) + if installed: + lines.append("optional packages: " + ", ".join(installed)) + if not_found: + lines.append("optional packages not found: " + ", ".join(not_found)) + return "\n".join(lines) diff --git a/pymake/config.py b/pymake/config.py index e238ccc4..c558bcf5 100644 --- a/pymake/config.py +++ b/pymake/config.py @@ -1,6 +1,6 @@ __author__ = "Joseph D. Hughes" __date__ = "July 5, 2023" -__version__ = "1.2.8" +__version__ = "1.2.9.dev0" __maintainer__ = "Joseph D. Hughes" __email__ = "jdhughes@usgs.gov" __status__ = "Production" diff --git a/pyproject.toml b/pyproject.toml index ec9f1edd..a10b6c6d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,14 +1,98 @@ [build-system] # Minimum requirements for the build system to execute requires = [ - "setuptools>=45", + "setuptools>=61", "wheel", ] build-backend = "setuptools.build_meta" +[project] +name = "mfpymake" +description = "pymake is a Python package to compile MODFLOW-based models." +authors = [ + { name = "mfpymake Team", email = "modflow@usgs.gov" }, +] +maintainers = [ + { name = "Joseph D. Hughes", email = "jdhughes@usgs.gov" }, +] +keywords = ["MODFLOW", "groundwater", "hydrogeology"] +license = { text = "CC0" } +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Science/Research", + "License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: Scientific/Engineering :: Hydrology", +] +requires-python = ">=3.8" +dependencies = [ + "numpy", + "requests", + "networkx >= 2.6.3", + "meson", + "ninja", + "pydotplus", +] +dynamic = ["version", "readme"] +[project.optional-dependencies] +lint = [ + "black", + "cffconvert", + "flake8", + "isort", + "pylint", +] +test = [ + "mfpymake[lint]", + "coverage", + "flaky", + "filelock", + "pytest", + "pytest-benchmark", + "pytest-cases", + "pytest-cov", + "pytest-dotenv", + "pytest-virtualenv", + "pytest-xdist", + "appdirs", + "matplotlib", + "modflow-devtools", + "flopy", +] +[project.scripts] +mfpymake = "pymake.cmds.mfpymakecli:main" +make-program = "pymake.cmds.build:main" +make-code-json = "pymake.cmds.createjson:main" + + +[project.urls] +Documentation = "https://mfpymake.readthedocs.io" +"Release Notes" = "https://github.com/modflowpy/flopy/blob/develop/docs/version_changes.md" +"Bug Tracker" = "https://github.com/modflowpy/pymake/issues" +"Source Code" = "https://github.com/modflowpy/pymake" + + +[tool.setuptools] +include-package-data = true +zip-safe = false + +[tool.setuptools.dynamic] +version = { attr = "pymake.config.__version__" } +readme = { file = ["README.md"], content-type = "text/markdown" } + +[tool.setuptools.packages.find] +include = ["pymake", "pymake.*"] + +[tool.setuptools.package-data] +"pymake.utils" = ["usgsprograms.txt"] + [tool.black] line-length = 79 -target_version = ["py37"] +target_version = ["py38"] [tool.flynt] line-length = 79 @@ -20,4 +104,4 @@ src_paths = ["pymake", "autotest", "examples"] line_length = 79 [tool.setuptools_scm] -fallback_version = "999" \ No newline at end of file +fallback_version = "999" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 8e67a95c..00000000 --- a/setup.cfg +++ /dev/null @@ -1,72 +0,0 @@ -[metadata] -name = mfpymake -version = attr: pymake.config.__version__ -description = pymake is a Python package to compile MODFLOW-based models. -long_description = file: README.md -long_description_content_type = text/markdown -author = Joseph D. Hughes -author_email = modflow@usgs.gov -maintainer = Joseph D. Hughes -maintainer_email = jdhughes@usgs.gov -license = CC0 -license_files = LICENSE.md -platform = Windows, Mac OS-X, Linux -keywords = MODFLOW, groundwater, hydrogeology -classifiers = - Development Status :: 5 - Production/Stable - Intended Audience :: Science/Research - License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication - Programming Language :: Python - Programming Language :: Python :: 3 :: Only - Topic :: Scientific/Engineering :: Hydrology -url = https://github.com/modflowpy/pymake -download_url = https://pypi.org/project/mfpymake -project_urls = - Documentation = https://mfpymake.readthedocs.io - Bug Tracker = https://github.com/modflowpy/pymake/issues - Source Code = https://github.com/modflowpy/pymake - -[options] -include_package_data = True # includes files listed in MANIFEST.in -zip_safe = False -packages = find: -python_requires = >=3.8 -install_requires = - numpy - requests - networkx >= 2.6.3 - meson - ninja - pydotplus - -[options.package_data] -pymake = utils/usgsprograms.txt - -[options.entry_points] -console_scripts = - mfpymake = pymake.cmds.mfpymakecli:main - make-program = pymake.cmds.build:main - make-code-json = pymake.cmds.createjson:main - -[flake8] -exclude = - .git - __pycache__ - build - dist - examples - autotest -ignore = -# https://flake8.pycqa.org/en/latest/user/error-codes.html - # 'module' imported but unused - F401 - # https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes - # do not use bare 'except' - E722 - # ambiguous variable name - E741 - # whitespace before ':' - E203 - # line break before binary operator - W503 -statistics = True diff --git a/setup.py b/setup.py index 60684932..bb7a18ce 100755 --- a/setup.py +++ b/setup.py @@ -1,3 +1,3 @@ from setuptools import setup -setup() +setup(name="mfpymake")