From bb7d9925ff480da5fbac7b5ae67a09d70b20fe27 Mon Sep 17 00:00:00 2001 From: mcflugen Date: Mon, 29 Jan 2024 18:47:58 -0700 Subject: [PATCH 01/20] clean up pyproject.toml --- pyproject.toml | 129 ++++++++++++++++++++++++++++--------------------- 1 file changed, 74 insertions(+), 55 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index dddcf85..8039749 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,25 +1,21 @@ -[build-system] -requires = ["setuptools", "wheel"] -build-backend = "setuptools.build_meta" - [project] -name = "bmi-heat" +name = "bmi_heat" +requires-python = ">=3.10" description = "BMI Python example" +keywords = [ + "bmi", + "component modeling", + "csdms", + "earth science", +] authors = [ - {email = "eric.hutton@colorado.edu"}, - {name = "Eric Hutton"} + { email = "eric.hutton@colorado.edu" }, + { name = "Eric Hutton" }, ] maintainers = [ - {name = "Mark Piper", email = "mark.piper@colorado.edu"}, - {name = "Eric Hutton", email = "eric.hutton@colorado.edu"}, -] -keywords = [ - "bmi", - "component modeling", - "csdms", - "earth science", + { name = "Mark Piper", email = "mark.piper@colorado.edu" }, + { name = "Eric Hutton", email = "eric.hutton@colorado.edu" }, ] -license = {file = "LICENSE"} classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Science/Research", @@ -35,72 +31,95 @@ classifiers = [ ] requires-python = ">=3.10" dependencies = [ + "bmipy", "numpy", - "scipy", "pyyaml", - "bmipy", + "scipy", +] +dynamic = [ + "readme", + "version", ] -dynamic = ["readme", "version"] + +[project.license] +text = "MIT" [project.urls] -Homepage = "https://csdms.colorado.edu" +Changelog = "https://github.com/csdms/bmi-example-python/blob/master/CHANGES.rst" Documentation = "https://bmi.readthedocs.io" +Homepage = "https://csdms.colorado.edu" Repository = "https://github.com/csdms/bmi-example-python" -Changelog = "https://github.com/csdms/bmi-example-python/blob/master/CHANGES.rst" [project.optional-dependencies] +dev = [ + "nox", +] testing = [ + "bmi-tester", "coveralls", "pytest", "pytest-cov", - "black", - "isort", - "ruff", - "bmi-tester", ] -[tool.setuptools.dynamic] -readme = {file = ["README.rst", "AUTHORS.rst", "CHANGES.rst"]} -version = {attr = "heat._version.__version__"} +[build-system] +requires = [ + "setuptools", + "wheel", +] +build-backend = "setuptools.build_meta" + +[tool.setuptools.dynamic.readme] +file = "README.rst" +content-type = "text/x-rst" + +[tool.setuptools.dynamic.version] +attr = "heat._version.__version__" [tool.setuptools.packages.find] -where = ["."] +where = [ + ".", +] + +[tool.coverage.run] +relative_files = true + +[tool.isort] +profile = "black" +force_single_line = "true" [tool.pytest.ini_options] minversion = "6.0" -testpaths = ["heat", "tests"] -norecursedirs = [".*", "*.egg*", "build", "dist"] -addopts = """ - --ignore setup.py - --tb native - --strict-markers - --durations 16 - --doctest-modules - -vvv -""" +testpaths = [ + "heat", + "tests", +] +norecursedirs = [ + ".*", + "*.egg*", + "build", + "dist", +] +addopts = [ + "--ignore=setup.py", + "--tb=native", + "--strict-markers", + "--durations=16", + "--doctest-modules", + "-vvv", +] doctest_optionflags = [ - "NORMALIZE_WHITESPACE", - "IGNORE_EXCEPTION_DETAIL", - "ALLOW_UNICODE" + "NORMALIZE_WHITESPACE", + "IGNORE_EXCEPTION_DETAIL", + "ALLOW_UNICODE", ] -[tool.isort] -multi_line_output = 3 -include_trailing_comma = true -force_grid_wrap = 0 -combine_as_imports = true -line_length = 88 - [tool.ruff] line-length = 88 -lint.ignore = [ - "E203", - "E501", +ignore = [ + "E203", + "E501", ] -[tool.coverage.run] -relative_files = true - [tool.zest-releaser] tag-format = "v{version}" python-file-with-version = "heat/_version.py" From 671bb5dc0618e9eba55f4293b6c9191a683b848f Mon Sep 17 00:00:00 2001 From: mcflugen Date: Mon, 29 Jan 2024 18:49:45 -0700 Subject: [PATCH 02/20] remove the manifest --- MANIFEST.in | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 625a716..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,7 +0,0 @@ -recursive-include main_directory * -include LICENSE -include *.rst -include *.txt -include Makefile -global-exclude *.pyc -recursive-exclude examples * From dc50dc7276d31915dae15ee11635628a4e2098a7 Mon Sep 17 00:00:00 2001 From: mcflugen Date: Mon, 29 Jan 2024 18:50:06 -0700 Subject: [PATCH 03/20] remove the makefile --- Makefile | 92 -------------------------------------------------------- 1 file changed, 92 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 1510d24..0000000 --- a/Makefile +++ /dev/null @@ -1,92 +0,0 @@ -.PHONY: clean clean-test clean-pyc clean-build docs help -.DEFAULT_GOAL := help - -define BROWSER_PYSCRIPT -import os, webbrowser, sys - -try: - from urllib import pathname2url -except: - from urllib.request import pathname2url - -webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) -endef -export BROWSER_PYSCRIPT - -define PRINT_HELP_PYSCRIPT -import re, sys - -for line in sys.stdin: - match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) - if match: - target, help = match.groups() - print("%-20s %s" % (target, help)) -endef -export PRINT_HELP_PYSCRIPT - -BROWSER := python -c "$$BROWSER_PYSCRIPT" - -help: - @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) - -clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts - -clean-build: ## remove build artifacts - rm -fr build/ - rm -fr dist/ - rm -fr .eggs/ - find . -name '*.egg-info' -exec rm -fr {} + - find . -name '*.egg' -exec rm -f {} + - -clean-pyc: ## remove Python file artifacts - find . -name '*.pyc' -exec rm -f {} + - find . -name '*.pyo' -exec rm -f {} + - find . -name '*~' -exec rm -f {} + - find . -name '__pycache__' -exec rm -fr {} + - -clean-test: ## remove test and coverage artifacts - rm -fr .tox/ - rm -f .coverage - rm -f coverage.xml - rm -fr htmlcov/ - rm -fr .pytest_cache - -lint: ## check style with ruff - ruff check . --fix - -pretty: - find heat -name '*.py' | xargs isort - black tests heat - -test: ## run tests quickly with the default Python - pytest - -test-all: ## run tests on every Python version with tox - tox - -coverage: ## check code coverage quickly with the default Python - coverage run --source heat -m pytest - coverage report -m - coverage html - $(BROWSER) htmlcov/index.html - -docs: ## generate Sphinx HTML documentation, including API docs - rm -f docs/source/heat.rst - rm -f docs/source/modules.rst - sphinx-apidoc -o docs/source heat - $(MAKE) -C docs clean - $(MAKE) -C docs html - $(BROWSER) docs/build/html/index.html - -servedocs: docs ## compile the docs watching for changes - watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D . - -release: dist ## package and upload a release - twine upload dist/* - -dist: clean ## builds source and wheel package - python -m build - ls -l dist - -install: clean ## install the package to the active Python's site-packages - pip install -e . From 5bc5a1596a4514ebacb97304a55887756647580a Mon Sep 17 00:00:00 2001 From: mcflugen Date: Mon, 29 Jan 2024 19:51:46 -0700 Subject: [PATCH 04/20] remove some lint --- heat/__init__.py | 3 ++- noxfile.py | 2 +- requirements-testing.txt | 1 - tests/get_value_test.py | 3 ++- tests/irf_test.py | 4 +++- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/heat/__init__.py b/heat/__init__.py index 18a6399..90e390a 100644 --- a/heat/__init__.py +++ b/heat/__init__.py @@ -2,6 +2,7 @@ from ._version import __version__ from .bmi_heat import BmiHeat -from .heat import Heat, solve_2d +from .heat import Heat +from .heat import solve_2d __all__ = ["__version__", "BmiHeat", "solve_2d", "Heat"] diff --git a/noxfile.py b/noxfile.py index bcb4d20..d288524 100644 --- a/noxfile.py +++ b/noxfile.py @@ -83,7 +83,7 @@ def clean(session): shutil.rmtree("build", ignore_errors=True) shutil.rmtree("dist", ignore_errors=True) - shutil.rmtree(f"src/{PROJECT}.egg-info", ignore_errors=True) + shutil.rmtree(f"{PROJECT}.egg-info", ignore_errors=True) shutil.rmtree(".pytest_cache", ignore_errors=True) shutil.rmtree(".venv", ignore_errors=True) diff --git a/requirements-testing.txt b/requirements-testing.txt index d817a46..461a782 100644 --- a/requirements-testing.txt +++ b/requirements-testing.txt @@ -4,4 +4,3 @@ coveralls isort pytest pytest-cov -ruff diff --git a/tests/get_value_test.py b/tests/get_value_test.py index 117525a..de265a2 100644 --- a/tests/get_value_test.py +++ b/tests/get_value_test.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import numpy as np -from numpy.testing import assert_array_almost_equal, assert_array_less +from numpy.testing import assert_array_almost_equal +from numpy.testing import assert_array_less from heat import BmiHeat diff --git a/tests/irf_test.py b/tests/irf_test.py index bfe2dc3..869309f 100644 --- a/tests/irf_test.py +++ b/tests/irf_test.py @@ -3,7 +3,9 @@ import numpy as np import yaml -from numpy.testing import assert_almost_equal, assert_array_equal, assert_array_less +from numpy.testing import assert_almost_equal +from numpy.testing import assert_array_equal +from numpy.testing import assert_array_less from heat import BmiHeat From 99d9d528a02e36843b43be9a31d123f796ff0380 Mon Sep 17 00:00:00 2001 From: mcflugen Date: Mon, 29 Jan 2024 23:10:44 -0700 Subject: [PATCH 05/20] add type annotations and test with mypy --- heat/bmi_heat.py | 120 +++++++++++++++++++++++++++-------------------- heat/heat.py | 40 +++++++++++----- pyproject.toml | 8 ++++ 3 files changed, 103 insertions(+), 65 deletions(-) diff --git a/heat/bmi_heat.py b/heat/bmi_heat.py index 15dd531..c554b76 100644 --- a/heat/bmi_heat.py +++ b/heat/bmi_heat.py @@ -1,8 +1,11 @@ #! /usr/bin/env python """Basic Model Interface implementation for the 2D heat model.""" +from typing import Any + import numpy as np from bmipy import Bmi +from numpy.typing import NDArray from .heat import Heat @@ -14,20 +17,21 @@ class BmiHeat(Bmi): _input_var_names = ("plate_surface__temperature",) _output_var_names = ("plate_surface__temperature",) - def __init__(self): + def __init__(self) -> None: """Create a BmiHeat model that is ready for initialization.""" - self._model = None - self._values = {} - self._var_units = {} - self._var_loc = {} - self._grids = {} - self._grid_type = {} + # self._model: Heat | None = None + self._model: Heat + self._values: dict[str, NDArray[Any]] = {} + self._var_units: dict[str, str] = {} + self._var_loc: dict[str, str] = {} + self._grids: dict[int, list[str]] = {} + self._grid_type: dict[int, str] = {} self._start_time = 0.0 - self._end_time = np.finfo("d").max + self._end_time = float(np.finfo("d").max) self._time_units = "s" - def initialize(self, filename=None): + def initialize(self, filename: str | None = None) -> None: """Initialize the Heat model. Parameters @@ -39,7 +43,7 @@ def initialize(self, filename=None): self._model = Heat() elif isinstance(filename, str): with open(filename) as file_obj: - self._model = Heat.from_file_like(file_obj.read()) + self._model = Heat.from_file_like(file_obj) else: self._model = Heat.from_file_like(filename) @@ -49,11 +53,11 @@ def initialize(self, filename=None): self._grids = {0: ["plate_surface__temperature"]} self._grid_type = {0: "uniform_rectilinear"} - def update(self): + def update(self) -> None: """Advance model by one time step.""" self._model.advance_in_time() - def update_frac(self, time_frac): + def update_frac(self, time_frac: float) -> None: """Update model by a fraction of a time step. Parameters @@ -66,7 +70,7 @@ def update_frac(self, time_frac): self.update() self._model.time_step = time_step - def update_until(self, then): + def update_until(self, then: float) -> None: """Update model until a particular time. Parameters @@ -80,11 +84,12 @@ def update_until(self, then): self.update() self.update_frac(n_steps - int(n_steps)) - def finalize(self): + def finalize(self) -> None: """Finalize model.""" - self._model = None + del self._model + # self._model = None - def get_var_type(self, var_name): + def get_var_type(self, var_name: str) -> str: """Data type of variable. Parameters @@ -99,7 +104,7 @@ def get_var_type(self, var_name): """ return str(self.get_value_ptr(var_name).dtype) - def get_var_units(self, var_name): + def get_var_units(self, var_name: str) -> str: """Get units of variable. Parameters @@ -114,7 +119,7 @@ def get_var_units(self, var_name): """ return self._var_units[var_name] - def get_var_nbytes(self, var_name): + def get_var_nbytes(self, var_name: str) -> int: """Get units of variable. Parameters @@ -129,13 +134,13 @@ def get_var_nbytes(self, var_name): """ return self.get_value_ptr(var_name).nbytes - def get_var_itemsize(self, name): + def get_var_itemsize(self, name: str) -> int: return np.dtype(self.get_var_type(name)).itemsize - def get_var_location(self, name): + def get_var_location(self, name: str) -> str: return self._var_loc[name] - def get_var_grid(self, var_name): + def get_var_grid(self, var_name: str) -> int | None: """Grid id for a variable. Parameters @@ -151,8 +156,9 @@ def get_var_grid(self, var_name): for grid_id, var_name_list in self._grids.items(): if var_name in var_name_list: return grid_id + return None - def get_grid_rank(self, grid_id): + def get_grid_rank(self, grid_id: int) -> int: """Rank of grid. Parameters @@ -167,7 +173,7 @@ def get_grid_rank(self, grid_id): """ return len(self._model.shape) - def get_grid_size(self, grid_id): + def get_grid_size(self, grid_id: int) -> int: """Size of grid. Parameters @@ -182,7 +188,7 @@ def get_grid_size(self, grid_id): """ return int(np.prod(self._model.shape)) - def get_value_ptr(self, var_name): + def get_value_ptr(self, var_name: str) -> NDArray[Any]: """Reference to values. Parameters @@ -197,7 +203,7 @@ def get_value_ptr(self, var_name): """ return self._values[var_name] - def get_value(self, var_name, dest): + def get_value(self, var_name: str, dest: NDArray[Any]) -> NDArray[Any]: """Copy of values. Parameters @@ -215,7 +221,9 @@ def get_value(self, var_name, dest): dest[:] = self.get_value_ptr(var_name).flatten() return dest - def get_value_at_indices(self, var_name, dest, indices): + def get_value_at_indices( + self, var_name: str, dest: NDArray[Any], indices: NDArray[np.int_] + ) -> NDArray[Any]: """Get values at particular indices. Parameters @@ -235,7 +243,7 @@ def get_value_at_indices(self, var_name, dest, indices): dest[:] = self.get_value_ptr(var_name).take(indices) return dest - def set_value(self, var_name, src): + def set_value(self, var_name: str, src: NDArray[Any]) -> None: """Set model values. Parameters @@ -248,7 +256,9 @@ def set_value(self, var_name, src): val = self.get_value_ptr(var_name) val[:] = src.reshape(val.shape) - def set_value_at_indices(self, name, inds, src): + def set_value_at_indices( + self, name: str, inds: NDArray[np.int_], src: NDArray[Any] + ) -> None: """Set model values at particular indices. Parameters @@ -263,76 +273,80 @@ def set_value_at_indices(self, name, inds, src): val = self.get_value_ptr(name) val.flat[inds] = src - def get_component_name(self): + def get_component_name(self) -> str: """Name of the component.""" return self._name - def get_input_item_count(self): + def get_input_item_count(self) -> int: """Get names of input variables.""" return len(self._input_var_names) - def get_output_item_count(self): + def get_output_item_count(self) -> int: """Get names of output variables.""" return len(self._output_var_names) - def get_input_var_names(self): + def get_input_var_names(self) -> tuple[str, ...]: """Get names of input variables.""" return self._input_var_names - def get_output_var_names(self): + def get_output_var_names(self) -> tuple[str, ...]: """Get names of output variables.""" return self._output_var_names - def get_grid_shape(self, grid_id, shape): + def get_grid_shape(self, grid_id: int, shape: NDArray[np.int_]) -> NDArray[np.int_]: """Number of rows and columns of uniform rectilinear grid.""" var_name = self._grids[grid_id][0] shape[:] = self.get_value_ptr(var_name).shape return shape - def get_grid_spacing(self, grid_id, spacing): + def get_grid_spacing( + self, grid_id: int, spacing: NDArray[np.float_] + ) -> NDArray[np.float_]: """Spacing of rows and columns of uniform rectilinear grid.""" spacing[:] = self._model.spacing return spacing - def get_grid_origin(self, grid_id, origin): + def get_grid_origin( + self, grid_id: int, origin: NDArray[np.float_] + ) -> NDArray[np.float_]: """Origin of uniform rectilinear grid.""" origin[:] = self._model.origin return origin - def get_grid_type(self, grid_id): + def get_grid_type(self, grid_id: int) -> str: """Type of grid.""" return self._grid_type[grid_id] - def get_start_time(self): + def get_start_time(self) -> float: """Start time of model.""" return self._start_time - def get_end_time(self): + def get_end_time(self) -> float: """End time of model.""" return self._end_time - def get_current_time(self): + def get_current_time(self) -> float: return self._model.time - def get_time_step(self): + def get_time_step(self) -> float: return self._model.time_step - def get_time_units(self): + def get_time_units(self) -> str: return self._time_units - def get_grid_edge_count(self, grid): + def get_grid_edge_count(self, grid: int) -> int: raise NotImplementedError("get_grid_edge_count") - def get_grid_edge_nodes(self, grid, edge_nodes): + def get_grid_edge_nodes(self, grid: int, edge_nodes: NDArray[np.int_]) -> None: raise NotImplementedError("get_grid_edge_nodes") - def get_grid_face_count(self, grid): + def get_grid_face_count(self, grid: int) -> None: raise NotImplementedError("get_grid_face_count") - def get_grid_face_nodes(self, grid, face_nodes): + def get_grid_face_nodes(self, grid: int, face_nodes: NDArray[np.int_]) -> None: raise NotImplementedError("get_grid_face_nodes") - def get_grid_node_count(self, grid): + def get_grid_node_count(self, grid: int) -> int: """Number of grid nodes. Parameters @@ -347,17 +361,19 @@ def get_grid_node_count(self, grid): """ return self.get_grid_size(grid) - def get_grid_nodes_per_face(self, grid, nodes_per_face): + def get_grid_nodes_per_face( + self, grid: int, nodes_per_face: NDArray[np.int_] + ) -> None: raise NotImplementedError("get_grid_nodes_per_face") - def get_grid_face_edges(self, grid, face_edges): + def get_grid_face_edges(self, grid: int, face_edges: NDArray[np.int_]) -> None: raise NotImplementedError("get_grid_face_edges") - def get_grid_x(self, grid, x): + def get_grid_x(self, grid: int, x: NDArray[np.float_]) -> None: raise NotImplementedError("get_grid_x") - def get_grid_y(self, grid, y): + def get_grid_y(self, grid: int, y: NDArray[np.float_]) -> None: raise NotImplementedError("get_grid_y") - def get_grid_z(self, grid, z): + def get_grid_z(self, grid: int, z: NDArray[np.float_]) -> None: raise NotImplementedError("get_grid_z") diff --git a/heat/heat.py b/heat/heat.py index baa20d8..fa31bc1 100644 --- a/heat/heat.py +++ b/heat/heat.py @@ -1,11 +1,21 @@ """The 2D heat model.""" +from __future__ import annotations + +from io import TextIOBase import numpy as np import yaml +from numpy.typing import NDArray from scipy import ndimage -def solve_2d(temp, spacing, out=None, alpha=1.0, time_step=1.0): +def solve_2d( + temp: NDArray[np.float_], + spacing: tuple[float, ...], + out: NDArray[np.float_] | None = None, + alpha: float = 1.0, + time_step: float = 1.0, +) -> NDArray[np.float_]: """Solve the 2D Heat Equation on a uniform mesh. Parameters @@ -82,8 +92,12 @@ class Heat: """ def __init__( - self, shape=(10, 20), spacing=(1.0, 1.0), origin=(0.0, 0.0), alpha=1.0 - ): + self, + shape: tuple[int, int] = (10, 20), + spacing: tuple[float, float] = (1.0, 1.0), + origin: tuple[float, float] = (0.0, 0.0), + alpha: float = 1.0, + ) -> None: """Create a new heat model. Parameters @@ -108,17 +122,17 @@ def __init__( self._next_temperature = np.empty_like(self._temperature) @property - def time(self): + def time(self) -> float: """Current model time.""" return self._time @property - def temperature(self): + def temperature(self) -> NDArray[np.float_]: """Temperature of the plate.""" return self._temperature @temperature.setter - def temperature(self, new_temp): + def temperature(self, new_temp: float) -> None: """Set the temperature of the plate. Parameters @@ -129,32 +143,32 @@ def temperature(self, new_temp): self._temperature[:] = new_temp @property - def time_step(self): + def time_step(self) -> float: """Model time step.""" return self._time_step @time_step.setter - def time_step(self, time_step): + def time_step(self, time_step: float) -> None: """Set model time step.""" self._time_step = time_step @property - def shape(self): + def shape(self) -> tuple[int, int]: """Shape of the model grid.""" return self._shape @property - def spacing(self): + def spacing(self) -> tuple[float, float]: """Spacing between nodes of the model grid.""" return self._spacing @property - def origin(self): + def origin(self) -> tuple[float, float]: """Origin coordinates of the model grid.""" return self._origin @classmethod - def from_file_like(cls, file_like): + def from_file_like(cls: type[Heat], file_like: TextIOBase) -> Heat: """Create a Heat object from a file-like object. Parameters @@ -170,7 +184,7 @@ def from_file_like(cls, file_like): config = yaml.safe_load(file_like) return cls(**config) - def advance_in_time(self): + def advance_in_time(self) -> None: """Calculate new temperatures for the next time step.""" solve_2d( self._temperature, diff --git a/pyproject.toml b/pyproject.toml index 8039749..04691df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,6 +87,14 @@ relative_files = true profile = "black" force_single_line = "true" +[tool.mypy] +check_untyped_defs = true +disallow_any_generics = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +warn_redundant_casts = true +warn_unused_ignores = true + [tool.pytest.ini_options] minversion = "6.0" testpaths = [ From b906ec2d18cb55c9c319ba9a74c19216680ea576 Mon Sep 17 00:00:00 2001 From: mcflugen Date: Tue, 30 Jan 2024 09:57:47 -0700 Subject: [PATCH 06/20] require bmi-tester >=0.5.7 --- pyproject.toml | 2 +- requirements-testing.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 04691df..ca41f6a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ dev = [ "nox", ] testing = [ - "bmi-tester", + "bmi-tester>=0.5.7", "coveralls", "pytest", "pytest-cov", diff --git a/requirements-testing.txt b/requirements-testing.txt index 461a782..05a66d3 100644 --- a/requirements-testing.txt +++ b/requirements-testing.txt @@ -1,5 +1,5 @@ black -bmi-tester +bmi-tester>=0.5.7 coveralls isort pytest From c9adfac6ee2b4b25c816951721cadc1c0391f63d Mon Sep 17 00:00:00 2001 From: mcflugen Date: Tue, 30 Jan 2024 10:28:10 -0700 Subject: [PATCH 07/20] need to install bmi-tester from conda --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b1bf29d..6725cd3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,11 +32,12 @@ jobs: - name: Show conda installation info run: | + const install --file=requirements-testing.txt conda info conda list - name: Build and install package - run: pip install -e .[testing] + run: pip install . - name: Test run: | From 2025983f0cd9fd1ac0978529f856258f0685d414 Mon Sep 17 00:00:00 2001 From: mcflugen Date: Tue, 30 Jan 2024 10:37:20 -0700 Subject: [PATCH 08/20] fix typo --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6725cd3..202d137 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,7 @@ jobs: - name: Show conda installation info run: | - const install --file=requirements-testing.txt + conda install --file=requirements-testing.txt conda info conda list From 6e323f0a6f4c8e91cd7105afb098687f41848cff Mon Sep 17 00:00:00 2001 From: mcflugen Date: Wed, 31 Jan 2024 09:50:45 -0700 Subject: [PATCH 09/20] run tests with nox, run bmi-test outside of virtualenv --- .github/workflows/test.yml | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 202d137..1951c14 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,6 +21,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: ["3.10", "3.11", "3.12", "3.13"] + fail-fast: false steps: - uses: actions/checkout@v4 @@ -32,18 +33,36 @@ jobs: - name: Show conda installation info run: | - conda install --file=requirements-testing.txt conda info conda list - - name: Build and install package - run: pip install . - - name: Test run: | - pytest --cov=heat --cov-report=xml:./coverage.xml -vvv + pip install nox + nox -s test --force-pythons="${{ matrix.python-version }}" + + - name: Run bmi-test + run: | + pip install model-metadata + conda install gimli.units pymt_hydrotrend -c conda-forge + pip install . 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' + if: matrix.os == 'ubuntu-latest' uses: AndreMiras/coveralls-python-action@develop + with: + parallel: true + flag-name: py${{ matrix.python-version }}-${{ matrix.os }} + + debug: true + + coveralls_finish: + needs: build-and-test + runs-on: ubuntu-latest + steps: + - name: Coveralls Finished + uses: AndreMiras/coveralls-python-action@develop + with: + parallel-finished: true + debug: true From 7d0e1f531eaec92e9c17020da15e580b85b022c0 Mon Sep 17 00:00:00 2001 From: mcflugen Date: Wed, 31 Jan 2024 10:04:10 -0700 Subject: [PATCH 10/20] don't need to force a python version --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1951c14..4cd3600 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,7 +39,7 @@ jobs: - name: Test run: | pip install nox - nox -s test --force-pythons="${{ matrix.python-version }}" + nox -s test - name: Run bmi-test run: | From b2f931dbfaf4f12e1689704018fa5e5f4007e417 Mon Sep 17 00:00:00 2001 From: mcflugen Date: Wed, 31 Jan 2024 10:12:39 -0700 Subject: [PATCH 11/20] remove bmi-tester as a testing requirement --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ca41f6a..f156413 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ dev = [ "nox", ] testing = [ - "bmi-tester>=0.5.7", + # "bmi-tester>=0.5.7", "coveralls", "pytest", "pytest-cov", From 56fe16e78d1b8e7e4665f41ece69ea373541a277 Mon Sep 17 00:00:00 2001 From: mcflugen Date: Wed, 31 Jan 2024 10:16:09 -0700 Subject: [PATCH 12/20] pip install bmi-tester --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4cd3600..b7b5dee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,7 +44,8 @@ jobs: - name: Run bmi-test run: | pip install model-metadata - conda install gimli.units pymt_hydrotrend -c conda-forge + conda install gimli.units -c conda-forge + pip install bmi-tester pip install . bmi-test heat:BmiHeat --config-file=${GITHUB_WORKSPACE}/examples/heat.yaml --root-dir=examples -vvv From 2cd5b400b0489427c9f5ff6c5af824261703eb10 Mon Sep 17 00:00:00 2001 From: mcflugen Date: Thu, 22 Feb 2024 12:57:51 -0700 Subject: [PATCH 13/20] pip install gimli.units; fix path to heat.yaml --- .github/workflows/test.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b7b5dee..53c2989 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -43,9 +43,7 @@ jobs: - name: Run bmi-test run: | - pip install model-metadata - conda install gimli.units -c conda-forge - pip install bmi-tester + pip install model-metadata gimli.units bmi-tester pip install . bmi-test heat:BmiHeat --config-file=${GITHUB_WORKSPACE}/examples/heat.yaml --root-dir=examples -vvv From 142d34273e701e396f85292f8ed6ee3a4e283afe Mon Sep 17 00:00:00 2001 From: mcflugen Date: Thu, 22 Feb 2024 14:05:17 -0700 Subject: [PATCH 14/20] use setup-python instead of mambaforge --- .github/workflows/test.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 53c2989..c6383ae 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,17 +25,11 @@ jobs: steps: - uses: actions/checkout@v4 - - - uses: conda-incubator/setup-miniconda@v3 + - name: Set up Python + uses: actions/setup-python@v5 with: - miniforge-version: latest python-version: ${{ matrix.python-version }} - - name: Show conda installation info - run: | - conda info - conda list - - name: Test run: | pip install nox From 5e72611b964932dffe3d2879c4a081960e7852df Mon Sep 17 00:00:00 2001 From: mcflugen Date: Thu, 17 Oct 2024 20:30:43 -0600 Subject: [PATCH 15/20] use np.float64 instead of np.float_ --- heat/bmi_heat.py | 14 +++++++------- heat/heat.py | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/heat/bmi_heat.py b/heat/bmi_heat.py index c554b76..027fed3 100644 --- a/heat/bmi_heat.py +++ b/heat/bmi_heat.py @@ -300,15 +300,15 @@ def get_grid_shape(self, grid_id: int, shape: NDArray[np.int_]) -> NDArray[np.in return shape def get_grid_spacing( - self, grid_id: int, spacing: NDArray[np.float_] - ) -> NDArray[np.float_]: + self, grid_id: int, spacing: NDArray[np.float64] + ) -> NDArray[np.float64]: """Spacing of rows and columns of uniform rectilinear grid.""" spacing[:] = self._model.spacing return spacing def get_grid_origin( - self, grid_id: int, origin: NDArray[np.float_] - ) -> NDArray[np.float_]: + self, grid_id: int, origin: NDArray[np.float64] + ) -> NDArray[np.float64]: """Origin of uniform rectilinear grid.""" origin[:] = self._model.origin return origin @@ -369,11 +369,11 @@ def get_grid_nodes_per_face( def get_grid_face_edges(self, grid: int, face_edges: NDArray[np.int_]) -> None: raise NotImplementedError("get_grid_face_edges") - def get_grid_x(self, grid: int, x: NDArray[np.float_]) -> None: + def get_grid_x(self, grid: int, x: NDArray[np.float64]) -> None: raise NotImplementedError("get_grid_x") - def get_grid_y(self, grid: int, y: NDArray[np.float_]) -> None: + def get_grid_y(self, grid: int, y: NDArray[np.float64]) -> None: raise NotImplementedError("get_grid_y") - def get_grid_z(self, grid: int, z: NDArray[np.float_]) -> None: + def get_grid_z(self, grid: int, z: NDArray[np.float64]) -> None: raise NotImplementedError("get_grid_z") diff --git a/heat/heat.py b/heat/heat.py index fa31bc1..3d4496d 100644 --- a/heat/heat.py +++ b/heat/heat.py @@ -10,12 +10,12 @@ def solve_2d( - temp: NDArray[np.float_], + temp: NDArray[np.float64], spacing: tuple[float, ...], - out: NDArray[np.float_] | None = None, + out: NDArray[np.float64] | None = None, alpha: float = 1.0, time_step: float = 1.0, -) -> NDArray[np.float_]: +) -> NDArray[np.float64]: """Solve the 2D Heat Equation on a uniform mesh. Parameters @@ -127,7 +127,7 @@ def time(self) -> float: return self._time @property - def temperature(self) -> NDArray[np.float_]: + def temperature(self) -> NDArray[np.float64]: """Temperature of the plate.""" return self._temperature From 69a5205c859b0bd2f5e297294ea4ccc3e0b26e68 Mon Sep 17 00:00:00 2001 From: mcflugen Date: Fri, 18 Oct 2024 16:09:31 -0600 Subject: [PATCH 16/20] pip-install testing requirements and gimli.units --- .github/workflows/test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c6383ae..d3734ed 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,8 +37,7 @@ jobs: - name: Run bmi-test run: | - pip install model-metadata gimli.units bmi-tester - pip install . + pip install .[testing] gimli.units bmi-test heat:BmiHeat --config-file=${GITHUB_WORKSPACE}/examples/heat.yaml --root-dir=examples -vvv - name: Coveralls From af7ba89502f838ca0fc8d6084a31867aa28aa4f5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 22:09:47 +0000 Subject: [PATCH 17/20] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- heat/__init__.py | 3 +-- tests/get_value_test.py | 3 +-- tests/irf_test.py | 5 ++--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/heat/__init__.py b/heat/__init__.py index 90e390a..18a6399 100644 --- a/heat/__init__.py +++ b/heat/__init__.py @@ -2,7 +2,6 @@ from ._version import __version__ from .bmi_heat import BmiHeat -from .heat import Heat -from .heat import solve_2d +from .heat import Heat, solve_2d __all__ = ["__version__", "BmiHeat", "solve_2d", "Heat"] diff --git a/tests/get_value_test.py b/tests/get_value_test.py index de265a2..117525a 100644 --- a/tests/get_value_test.py +++ b/tests/get_value_test.py @@ -1,7 +1,6 @@ #!/usr/bin/env python import numpy as np -from numpy.testing import assert_array_almost_equal -from numpy.testing import assert_array_less +from numpy.testing import assert_array_almost_equal, assert_array_less from heat import BmiHeat diff --git a/tests/irf_test.py b/tests/irf_test.py index 869309f..90a1210 100644 --- a/tests/irf_test.py +++ b/tests/irf_test.py @@ -3,9 +3,8 @@ import numpy as np import yaml -from numpy.testing import assert_almost_equal -from numpy.testing import assert_array_equal -from numpy.testing import assert_array_less +from numpy.testing import (assert_almost_equal, assert_array_equal, + assert_array_less) from heat import BmiHeat From 32375aee2e4683ec9ab55725d9826668ea935072 Mon Sep 17 00:00:00 2001 From: mcflugen Date: Fri, 18 Oct 2024 16:22:33 -0600 Subject: [PATCH 18/20] remove extra requires_python from pyproject.toml --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f156413..cce4b6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,6 @@ classifiers = [ "Programming Language :: Python :: Implementation :: CPython", "Topic :: Scientific/Engineering :: Physics", ] -requires-python = ">=3.10" dependencies = [ "bmipy", "numpy", From 6b8936dee7abd3703f442dd6e77bda10c39e0ff5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 22:23:07 +0000 Subject: [PATCH 19/20] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- heat/__init__.py | 3 ++- tests/get_value_test.py | 3 ++- tests/irf_test.py | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/heat/__init__.py b/heat/__init__.py index 18a6399..90e390a 100644 --- a/heat/__init__.py +++ b/heat/__init__.py @@ -2,6 +2,7 @@ from ._version import __version__ from .bmi_heat import BmiHeat -from .heat import Heat, solve_2d +from .heat import Heat +from .heat import solve_2d __all__ = ["__version__", "BmiHeat", "solve_2d", "Heat"] diff --git a/tests/get_value_test.py b/tests/get_value_test.py index 117525a..de265a2 100644 --- a/tests/get_value_test.py +++ b/tests/get_value_test.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import numpy as np -from numpy.testing import assert_array_almost_equal, assert_array_less +from numpy.testing import assert_array_almost_equal +from numpy.testing import assert_array_less from heat import BmiHeat diff --git a/tests/irf_test.py b/tests/irf_test.py index 90a1210..869309f 100644 --- a/tests/irf_test.py +++ b/tests/irf_test.py @@ -3,8 +3,9 @@ import numpy as np import yaml -from numpy.testing import (assert_almost_equal, assert_array_equal, - assert_array_less) +from numpy.testing import assert_almost_equal +from numpy.testing import assert_array_equal +from numpy.testing import assert_array_less from heat import BmiHeat From 62bc66a8f2aa265cbb999903ed52dca2e0fe58e3 Mon Sep 17 00:00:00 2001 From: mcflugen Date: Fri, 18 Oct 2024 16:25:01 -0600 Subject: [PATCH 20/20] add bmi-tester to testing requirements --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index cce4b6e..52f50ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,7 +54,7 @@ dev = [ "nox", ] testing = [ - # "bmi-tester>=0.5.7", + "bmi-tester>=0.5.7", "coveralls", "pytest", "pytest-cov",