diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml deleted file mode 100644 index 2d7a6b9..0000000 --- a/.github/workflows/format.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Format - -on: [push, pull_request] - -jobs: - - format: - # We want to run on external PRs, but not on our own internal PRs as they'll be run - # by the push to the branch. Without this if check, checks are duplicated since - # internal PRs match both the push and pull_request events. - if: - github.event_name == 'push' || github.event.pull_request.head.repo.full_name != - github.repository - - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 - - uses: psf/black@stable - with: - args: ". --check" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index cd1822f..0000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Lint - -on: [push, pull_request] - -jobs: - - lint: - # We want to run on external PRs, but not on our own internal PRs as they'll be run - # by the push to the branch. Without this if check, checks are duplicated since - # internal PRs match both the push and pull_request events. - if: - github.event_name == 'push' || github.event.pull_request.head.repo.full_name != - github.repository - - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 - - - name: Lint - run: | - pip install ruff - ruff check . diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f6df638..90eabdd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.9", "3.10", "3.11", "3.12"] + python-version: ["3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v4 @@ -36,17 +36,13 @@ jobs: conda info conda list - - name: Install requirements - run: | - mamba install --file=requirements.txt --file=requirements-testing.txt - - name: Build and install package - run: pip install -e . + run: pip install -e .[testing] - name: Test run: | pytest --cov=heat --cov-report=xml:./coverage.xml -vvv - bmi-test heat:BmiHeat --config-file=./examples/heat.yaml --root-dir=./examples -vvv + bmi-test heat:BmiHeat --config-file=${GITHUB_WORKSPACE}/examples/heat.yaml --root-dir=examples -vvv - name: Coveralls if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..553ebb7 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,55 @@ +repos: +- repo: https://github.com/psf/black + rev: 23.12.1 + hooks: + - id: black + name: black + description: "Black: The uncompromising Python code formatter" + entry: black + language: python + language_version: python3 + minimum_pre_commit_version: 2.9.2 + require_serial: true + types_or: [python, pyi] + +- repo: https://github.com/pycqa/flake8 + rev: 7.0.0 + hooks: + - id: flake8 + additional_dependencies: + - flake8-bugbear + - flake8-comprehensions + - flake8-simplify + args: [--max-line-length=88] + +- repo: https://github.com/asottile/pyupgrade + rev: v3.15.0 + hooks: + - id: pyupgrade + args: [--py310-plus] + +- repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort + +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-builtin-literals + - id: check-added-large-files + - id: check-case-conflict + - id: check-toml + - id: check-yaml + - id: debug-statements + - id: end-of-file-fixer + - id: forbid-new-submodules + - id: mixed-line-ending + - id: trailing-whitespace + +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.8.0 + hooks: + - id: mypy + language_version: python3.12 + files: src/.*\.py$ diff --git a/CHANGES.rst b/CHANGES.rst index 94a262c..4ee2ffa 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -31,7 +31,7 @@ Changelog for bmi-example-python - Match bmipy (#12) - Use GitHub Actions for continuous integration (#15) - Dimensionalize flattened values passed into set_value (#17) -- Update CI (#18) +- Update CI (#18) - Switch from versioneer to zest.releaser - Remove obsolete docs directory @@ -46,4 +46,3 @@ Changelog for bmi-example-python ------------------ - Initial release - diff --git a/LICENSE b/LICENSE index 514dd15..0f18cdf 100644 --- a/LICENSE +++ b/LICENSE @@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/heat/bmi_heat.py b/heat/bmi_heat.py index 310855a..76daf23 100644 --- a/heat/bmi_heat.py +++ b/heat/bmi_heat.py @@ -39,7 +39,7 @@ def initialize(self, filename=None): if filename is None: self._model = Heat() elif isinstance(filename, str): - with open(filename, "r") as file_obj: + with open(filename) as file_obj: self._model = Heat.from_file_like(file_obj.read()) else: self._model = Heat.from_file_like(filename) diff --git a/heat/heat.py b/heat/heat.py index e940511..baa20d8 100644 --- a/heat/heat.py +++ b/heat/heat.py @@ -53,7 +53,7 @@ def solve_2d(temp, spacing, out=None, alpha=1.0, time_step=1.0): return np.add(temp, out, out=out) -class Heat(object): +class Heat: """Solve the Heat equation on a grid. diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 0000000..bcb4d20 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,103 @@ +from __future__ import annotations + +import os +import pathlib +import shutil + +import nox + +PROJECT = "heat" +ROOT = pathlib.Path(__file__).parent + + +@nox.session +def test(session: nox.Session) -> None: + """Run the tests.""" + session.install(".[testing]") + + args = ["--cov", PROJECT, "-vvv"] + session.posargs + + if "CI" in os.environ: + args.append(f"--cov-report=xml:{ROOT.absolute()!s}/coverage.xml") + session.run("pytest", *args) + + if "CI" not in os.environ: + session.run("coverage", "report", "--ignore-errors", "--show-missing") + + +@nox.session +def lint(session: nox.Session) -> None: + """Look for lint.""" + session.install("pre-commit") + session.run("pre-commit", "run", "--all-files") + + +@nox.session +def build(session: nox.Session) -> None: + session.install("pip") + session.install("build") + session.run("python", "--version") + session.run("pip", "--version") + session.run("python", "-m", "build", "--outdir", "./build/wheelhouse") + + +@nox.session(name="publish-testpypi") +def publish_testpypi(session): + """Publish wheelhouse/* to TestPyPI.""" + session.run("twine", "check", "build/wheelhouse/*") + session.run( + "twine", + "upload", + "--skip-existing", + "--repository-url", + "https://test.pypi.org/legacy/", + "build/wheelhouse/*.tar.gz", + ) + + +@nox.session(name="publish-pypi") +def publish_pypi(session): + """Publish wheelhouse/* to PyPI.""" + session.run("twine", "check", "build/wheelhouse/*") + session.run( + "twine", + "upload", + "--skip-existing", + "build/wheelhouse/*.tar.gz", + ) + + +@nox.session(python=False) +def clean(session): + """Remove all .venv's, build files and caches in the directory.""" + folders = ( + (ROOT,) if not session.posargs else (pathlib.Path(f) for f in session.posargs) + ) + for folder in folders: + if not str(folder.resolve()).startswith(str(ROOT.resolve())): + session.log(f"skipping {folder}: folder is outside of repository") + continue + + with session.chdir(folder): + session.log(f"cleaning {folder}") + + shutil.rmtree("build", ignore_errors=True) + shutil.rmtree("dist", ignore_errors=True) + shutil.rmtree(f"src/{PROJECT}.egg-info", ignore_errors=True) + shutil.rmtree(".pytest_cache", ignore_errors=True) + shutil.rmtree(".venv", ignore_errors=True) + + for pattern in ["*.py[co]", "__pycache__"]: + _clean_rglob(pattern) + + +def _clean_rglob(pattern): + nox_dir = pathlib.Path(".nox") + + for p in pathlib.Path(".").rglob(pattern): + if nox_dir in p.parents: + continue + if p.is_dir(): + p.rmdir() + else: + p.unlink()