Skip to content

Commit

Permalink
chore: drop python 3.8, support 3.13 (#168)
Browse files Browse the repository at this point in the history
Drop Python 3.8 support and add 3.13 to the test matrix. Other changes:

- Ruff's UP check automatically fixes some of the Python code for 3.9+
- Clean-up the `setup.py` wrapper file
- Some of the CI jobs have used `python-version: 3.x` to specify the latest stable version of Python
- Several steps of the CI workflow use conditionals `if: matrix.python != 3.8`, which are removed
- Upgrade ReadTheDocs configuration to use ubuntu-24.04 with python 3.13
  • Loading branch information
mwtoews authored Dec 10, 2024
1 parent 438847c commit 05926fd
Show file tree
Hide file tree
Showing 14 changed files with 41 additions and 44 deletions.
13 changes: 5 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.8
python-version: 3.x
cache: 'pip'
cache-dependency-path: pyproject.toml

Expand All @@ -52,7 +52,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.8
python-version: 3.x

- name: Install Python packages
run: |
Expand All @@ -79,7 +79,7 @@ jobs:
fail-fast: false
matrix:
os: [ ubuntu-22.04, macos-13, windows-2022 ]
python: [ 3.8, 3.9, "3.10", "3.11", "3.12" ]
python: [ 3.9, "3.10", "3.11", "3.12", "3.13" ]
env:
GCC_V: 11
steps:
Expand Down Expand Up @@ -137,26 +137,23 @@ jobs:
run: pip install ".[test]"

- name: Cache modflow6 examples
if: matrix.python != 3.8
id: cache-examples
uses: actions/cache@v3
with:
path: modflow6-examples/examples
key: modflow6-examples-${{ hashFiles('modflow6-examples/data/**') }}

- name: Install extra Python packages
if: matrix.python != 3.8
working-directory: modflow6-examples/etc
run: |
pip install -r requirements.pip.txt
pip install -r requirements.usgs.txt
- name: Update FloPy packages
if: matrix.python != 3.8
run: python -m flopy.mf6.utils.generate_classes --ref develop --no-backup

- name: Build modflow6 example models
if: matrix.python != 3.8 && steps.cache-examples.outputs.cache-hit != 'true'
if: steps.cache-examples.outputs.cache-hit != 'true'
working-directory: modflow6-examples/autotest
run: pytest -v -n auto test_scripts.py --init

Expand All @@ -171,7 +168,7 @@ jobs:
# only invoke the GH API on one OS and Python version
# to avoid rate limits (1000 rqs / hour / repository)
# https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration#usage-limits
if: runner.os == 'Linux' && matrix.python == '3.8'
if: runner.os == 'Linux' && matrix.python == '3.9'
working-directory: modflow-devtools/autotest
env:
REPOS_PATH: ${{ github.workspace }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.8
python-version: 3.x
cache: 'pip'
cache-dependency-path: pyproject.toml

Expand Down Expand Up @@ -177,7 +177,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.8
python-version: 3.x

- name: Install Python dependencies
run: |
Expand Down
4 changes: 2 additions & 2 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
version: 2
build:
os: "ubuntu-22.04"
os: "ubuntu-24.04"
tools:
python: "3.8"
python: "3.13"
sphinx:
configuration: docs/conf.py
formats:
Expand Down
2 changes: 1 addition & 1 deletion DEVELOPER.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This document provides guidance to set up a development environment and discusse

## Requirements

Python3.8+ is currently required. This project supports several recent versions of Python, loosely following [NEP 29](https://numpy.org/neps/nep-0029-deprecation_policy.html#implementation) and aiming to stay synchronized with [FloPy](https://github.com/modflowpy/flopy).
Python3.9+ is currently required. This project supports several recent versions of Python, loosely following [NEP 29](https://numpy.org/neps/nep-0029-deprecation_policy.html#implementation) and aiming to stay synchronized with [FloPy](https://github.com/modflowpy/flopy).

## Installation

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Pytest features include:

## Requirements

Python3.8+, dependency-free, but pairs well with `pytest` and select plugins, e.g.
Python3.9+, dependency-free, but pairs well with `pytest` and select plugins, e.g.

- [`pytest-dotenv`](https://github.com/quiqua/pytest-dotenv)
- [`pytest-xdist`](https://github.com/pytest-dev/pytest-xdist)
Expand Down
5 changes: 2 additions & 3 deletions autotest/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from os import environ
from pathlib import Path
from time import sleep
from typing import List

import pytest

Expand Down Expand Up @@ -122,7 +121,7 @@ def test_has_package():
assert not has_package(namefile_path, "wel")


def get_expected_model_dirs(path, pattern="mfsim.nam") -> List[Path]:
def get_expected_model_dirs(path, pattern="mfsim.nam") -> list[Path]:
folders = []
for root, dirs, _ in os.walk(path):
for d in dirs:
Expand All @@ -132,7 +131,7 @@ def get_expected_model_dirs(path, pattern="mfsim.nam") -> List[Path]:
return sorted(set(folders))


def get_expected_namefiles(path, pattern="mfsim.nam") -> List[Path]:
def get_expected_namefiles(path, pattern="mfsim.nam") -> list[Path]:
folders = []
for root, dirs, _ in os.walk(path):
for d in dirs:
Expand Down
22 changes: 12 additions & 10 deletions modflow_devtools/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import urllib.request
from os import PathLike
from pathlib import Path
from typing import List, Optional, Union
from typing import Optional, Union
from uuid import uuid4
from warnings import warn

Expand Down Expand Up @@ -39,7 +39,7 @@ def get_request(url, params={}):

def get_releases(
repo, per_page=30, max_pages=10, retries=3, verbose=False
) -> List[dict]:
) -> list[dict]:
"""
Get available releases for the given repository.
Expand Down Expand Up @@ -221,7 +221,7 @@ def get_latest_version(repo, retries=3, verbose=False) -> str:

def get_release_assets(
repo, tag="latest", simple=False, retries=3, verbose=False
) -> Union[dict, List[dict]]:
) -> Union[dict, list[dict]]:
"""
Get assets corresponding to the given release.
Expand Down Expand Up @@ -264,7 +264,7 @@ def get_release_assets(

def list_artifacts(
repo, name=None, per_page=30, max_pages=10, retries=3, verbose=False
) -> List[dict]:
) -> list[dict]:
"""
List artifacts for the given repository, optionally filtering by name (exact match).
If more artifacts are available than will fit within the given page size, by default
Expand Down Expand Up @@ -401,9 +401,10 @@ def download_artifact(
while True:
tries += 1
try:
with urllib.request.urlopen(request) as url_file, zip_path.open(
"wb"
) as out_file:
with (
urllib.request.urlopen(request) as url_file,
zip_path.open("wb") as out_file,
):
content = url_file.read()
out_file.write(content)
break
Expand Down Expand Up @@ -479,9 +480,10 @@ def download_and_unzip(
while True:
tries += 1
try:
with urllib.request.urlopen(request) as url_file, file_path.open(
"wb"
) as out_file:
with (
urllib.request.urlopen(request) as url_file,
file_path.open("wb") as out_file,
):
content = url_file.read()
out_file.write(content)

Expand Down
5 changes: 3 additions & 2 deletions modflow_devtools/fixtures.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from collections import OrderedDict
from collections.abc import Generator
from itertools import groupby
from os import PathLike, environ
from pathlib import Path
from shutil import copytree, rmtree
from typing import Dict, Generator, List, Optional
from typing import Optional

from modflow_devtools.imports import import_optional_dependency
from modflow_devtools.misc import get_namefile_paths, get_packages
Expand Down Expand Up @@ -313,7 +314,7 @@ def example_path_from_namfile_path(path: PathLike) -> Path:
def example_name_from_namfile_path(path: PathLike) -> str:
return example_path_from_namfile_path(path).name

def group_examples(namefile_paths) -> Dict[str, List[Path]]:
def group_examples(namefile_paths) -> dict[str, list[Path]]:
d = OrderedDict()
for name, paths in groupby(
namefile_paths, key=example_name_from_namfile_path
Expand Down
3 changes: 2 additions & 1 deletion modflow_devtools/latex.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from collections.abc import Iterable
from os import PathLike
from pathlib import Path
from typing import Iterable, Optional, Union
from typing import Optional, Union


def build_table(
Expand Down
4 changes: 2 additions & 2 deletions modflow_devtools/markers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from os import environ
from platform import python_version, system
from typing import Dict, Optional
from typing import Optional

from packaging.version import Version

Expand Down Expand Up @@ -48,7 +48,7 @@ def requires_python(version, bound="lower"):
)


def requires_pkg(*pkgs, name_map: Optional[Dict[str, str]] = None):
def requires_pkg(*pkgs, name_map: Optional[dict[str, str]] = None):
missing = {pkg for pkg in pkgs if not has_pkg(pkg, strict=True, name_map=name_map)}
return pytest.mark.skipif(
missing,
Expand Down
10 changes: 5 additions & 5 deletions modflow_devtools/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from shutil import which
from subprocess import run
from timeit import timeit
from typing import Dict, List, Optional, Tuple
from typing import Optional
from urllib import request
from urllib.error import URLError

Expand Down Expand Up @@ -67,7 +67,7 @@ def get_ostag() -> str:
raise ValueError(f"platform {sys.platform!r} not supported")


def get_suffixes(ostag) -> Tuple[str, str]:
def get_suffixes(ostag) -> tuple[str, str]:
"""
Returns executable and library suffixes for the
given OS (as returned by sys.platform)
Expand Down Expand Up @@ -144,7 +144,7 @@ def get_current_branch() -> str:
raise ValueError(f"Could not determine current branch: {stderr}")


def get_packages(namefile_path: PathLike) -> List[str]:
def get_packages(namefile_path: PathLike) -> list[str]:
"""
Return a list of packages used by the simulation
or model defined in the given namefile. The namefile
Expand Down Expand Up @@ -273,7 +273,7 @@ def get_model_paths(
excluded=None,
selected=None,
packages=None,
) -> List[Path]:
) -> list[Path]:
"""
Find model directories recursively in the given location.
A model directory is any directory containing one or more
Expand Down Expand Up @@ -378,7 +378,7 @@ def has_exe(exe):


def has_pkg(
pkg: str, strict: bool = False, name_map: Optional[Dict[str, str]] = None
pkg: str, strict: bool = False, name_map: Optional[dict[str, str]] = None
) -> bool:
"""
Determines if the given Python package is installed.
Expand Down
4 changes: 2 additions & 2 deletions modflow_devtools/ostags.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import sys
from platform import processor, system
from typing import Optional, Tuple
from typing import Optional

_system = system()
_processor = processor()
Expand Down Expand Up @@ -42,7 +42,7 @@ def get_ostag(kind: str = "modflow") -> str:
raise ValueError(f"Invalid kind: {kind}")


def get_binary_suffixes(ostag: Optional[str] = None) -> Tuple[str, str]:
def get_binary_suffixes(ostag: Optional[str] = None) -> tuple[str, str]:
"""
Returns executable and library suffixes for the given OS tag, if provided,
otherwise for the current operating system.
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ classifiers = [
"License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3",
"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",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering :: Hydrology"
]
requires-python = ">=3.8"
requires-python = ">=3.9"
dynamic = ["version"]

[project.optional-dependencies]
Expand Down
3 changes: 0 additions & 3 deletions setup.py

This file was deleted.

0 comments on commit 05926fd

Please sign in to comment.