diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3fadc49e..49b535b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.8', '3.x'] + python-version: ['3.10', '3.x'] steps: - uses: actions/checkout@v4 - diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 5473bccb..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,15 +0,0 @@ -include doc/*.rst -include doc/conf.py -include doc/images/*.png -include doc/Makefile - -include README.rst -include LICENSE -include CITATION.cff - -recursive-include contrib *.sh *.py - -prune .github -prune doc/_build -exclude .gitignore -exclude .gitlab-ci.yml diff --git a/contrib/pov-nodes/nodal_points.py b/contrib/pov-nodes/nodal_points.py index fa31b74f..1f3736db 100644 --- a/contrib/pov-nodes/nodal_points.py +++ b/contrib/pov-nodes/nodal_points.py @@ -47,7 +47,7 @@ unit_to_barycentric(mp.warp_and_blend_nodes(3, n, node_tuples)) ).T ] -id_to_node = dict(list(zip(node_tuples, nodes))) +id_to_node = dict(list(zip(node_tuples, nodes, strict=True))) def get_ball_radius(nid): diff --git a/contrib/pov-nodes/pov.py b/contrib/pov-nodes/pov.py index 8f3de37c..e6016597 100644 --- a/contrib/pov-nodes/pov.py +++ b/contrib/pov-nodes/pov.py @@ -72,7 +72,7 @@ def __init__(self, name, args=(), opts=(), **kwargs): args = list(args) for i in range(len(args)): - if isinstance(args[i], (tuple, list, np.ndarray)): + if isinstance(args[i], tuple | list | np.ndarray): args[i] = Vector(args[i]) self.args = args @@ -95,7 +95,7 @@ def write(self, file): for key, val in list(self.kwargs.items()): if val is None: file.writeln(key) - elif isinstance(val, (tuple, list, np.ndarray)): + elif isinstance(val, tuple | list | np.ndarray): val = Vector(*val) file.writeln(f"{key} {val}") else: diff --git a/examples/plot-basis.py b/examples/plot-basis.py index 0ce58065..f3ac0b17 100644 --- a/examples/plot-basis.py +++ b/examples/plot-basis.py @@ -33,6 +33,7 @@ for (i, j), basis_func in zip( gnitstam(p, dims), simplex_onb(dims, p), + strict=True, ): all_nodes.append([*plot_nodes, stretch_factor * i, stretch_factor * j]) diff --git a/modepy/matrices.py b/modepy/matrices.py index 659f9ad1..307697c1 100644 --- a/modepy/matrices.py +++ b/modepy/matrices.py @@ -24,7 +24,7 @@ """ -from typing import Callable, Sequence +from collections.abc import Callable, Sequence from warnings import warn import numpy as np diff --git a/modepy/modal_decay.py b/modepy/modal_decay.py index c8a44be0..d5fe13a6 100644 --- a/modepy/modal_decay.py +++ b/modepy/modal_decay.py @@ -114,7 +114,7 @@ def create_decay_baseline(mode_number_vector: np.ndarray, n: int) -> np.ndarray: modal_coefficients[zeros] = 1 # irrelevant, just keeps log from NaNing # NOTE: mypy seems to be confused by the __itruediv__ argument types - modal_coefficients /= la.norm(modal_coefficients) # type: ignore[misc] + modal_coefficients /= la.norm(modal_coefficients) # type: ignore[arg-type,misc] return modal_coefficients diff --git a/modepy/modes.py b/modepy/modes.py index 34535946..8457220f 100644 --- a/modepy/modes.py +++ b/modepy/modes.py @@ -26,14 +26,10 @@ import math from abc import ABC, abstractmethod +from collections.abc import Callable, Hashable, Iterable, Sequence from functools import partial, singledispatch from typing import ( TYPE_CHECKING, - Callable, - Hashable, - Iterable, - Sequence, - Tuple, TypeVar, ) @@ -134,7 +130,9 @@ def _cse(expr, prefix): def _where(op_a, comp, op_b, then, else_): from pymbolic.primitives import Comparison, Expression, If if isinstance(op_a, Expression) or isinstance(op_b, Expression): - return If(Comparison(op_a, comp, op_b), then, else_) + return If( + Comparison(op_a, Comparison.name_to_operator[comp], op_b), + then, else_) import operator comp_op = getattr(operator, comp) @@ -203,7 +201,7 @@ def jacobi(alpha: float, beta: float, n: int, x: RealValueT) -> RealValueT: bnew = -(alpha*alpha-beta*beta)/(h1*(h1+2.)) pl.append(_cse( - (-aold*pl[i-1] + np.multiply(x-bnew, pl[i]))/anew, + (-aold*pl[i-1] + (x-bnew) * pl[i])/anew, prefix=f"jac_p{i+1}")) aold = anew @@ -577,7 +575,7 @@ def __call__(self, x): # Likely we're evaluating symbolically. result = 1 - for d, function in zip(self.dims_per_function, self.functions): + for d, function in zip(self.dims_per_function, self.functions, strict=True): result *= function(x[n:n + d]) n += d @@ -654,7 +652,7 @@ def __call__(self, x): n = 0 for ider, derivative in enumerate(self.derivatives): f = 0 - for iaxis, function in zip(self.dims_per_function, derivative): + for iaxis, function in zip(self.dims_per_function, derivative, strict=True): components = function(x[f:f + iaxis]) if isinstance(components, tuple): @@ -723,7 +721,7 @@ def symbolicize_function( # {{{ basis interface BasisFunctionType = Callable[[np.ndarray], np.ndarray] -BasisGradientType = Callable[[np.ndarray], Tuple[np.ndarray, ...]] +BasisGradientType = Callable[[np.ndarray], tuple[np.ndarray, ...]] class BasisNotOrthonormal(Exception): @@ -973,7 +971,8 @@ def part_flat_tuple(iterable: Iterable[tuple[bool, Hashable]] part_flat_tuple((flatten, umid[mid_index_i]) for flatten, umid, mid_index_i in zip( is_all_singletons_with_int, - underlying_mode_id_lists, mode_index_tuple)) + underlying_mode_id_lists, mode_index_tuple, + strict=True)) for mode_index_tuple in self._mode_index_tuples) @property @@ -998,7 +997,7 @@ def gradients(self) -> tuple[BasisGradientType, ...]: tuple( tuple(func[is_deriv][ibasis][mid_i] for ibasis, (is_deriv, mid_i) in enumerate( - zip(deriv_indicator_vec, mid))) + zip(deriv_indicator_vec, mid, strict=True))) for deriv_indicator_vec in wandering_element(self._nbases)), dims_per_function=self._dims_per_basis) for mid in self._mode_index_tuples) @@ -1015,7 +1014,7 @@ def _orthonormal_basis_for_tp( raise ValueError("spatial dimensions of shape and space must match") bases = [orthonormal_basis_for_space(b, s) - for b, s in zip(space.bases, shape.bases)] + for b, s in zip(space.bases, shape.bases, strict=True)] return TensorProductBasis( bases, @@ -1030,7 +1029,8 @@ def _basis_for_tp(space: TensorProductSpace, shape: TensorProductShape): if space.spatial_dim != shape.dim: raise ValueError("spatial dimensions of shape and space must match") - bases = [basis_for_space(b, s) for b, s in zip(space.bases, shape.bases)] + bases = [basis_for_space(b, s) + for b, s in zip(space.bases, shape.bases, strict=True)] return TensorProductBasis( bases, dims_per_basis=tuple(b.spatial_dim for b in space.bases)) @@ -1043,7 +1043,7 @@ def _monomial_basis_for_tp(space: TensorProductSpace, shape: TensorProductShape) bases = [ monomial_basis_for_space(b, s) - for b, s in zip(space.bases, shape.bases)] + for b, s in zip(space.bases, shape.bases, strict=True)] return TensorProductBasis( bases, diff --git a/modepy/nodes.py b/modepy/nodes.py index cf8ae08d..2dd8da57 100644 --- a/modepy/nodes.py +++ b/modepy/nodes.py @@ -62,8 +62,8 @@ # }}} +from collections.abc import Sequence from functools import partial, singledispatch -from typing import Sequence import numpy as np import numpy.linalg as la @@ -555,7 +555,7 @@ def _equispaced_nodes_for_tp( return tensor_product_nodes([ equispaced_nodes_for_space(b, s) - for b, s in zip(space.bases, shape.bases) + for b, s in zip(space.bases, shape.bases, strict=True) ]) @@ -571,7 +571,7 @@ def _edge_clustered_nodes_for_tp( return tensor_product_nodes([ edge_clustered_nodes_for_space(b, s) - for b, s in zip(space.bases, shape.bases) + for b, s in zip(space.bases, shape.bases, strict=True) ]) diff --git a/modepy/quadrature/__init__.py b/modepy/quadrature/__init__.py index 29143123..a960fe68 100644 --- a/modepy/quadrature/__init__.py +++ b/modepy/quadrature/__init__.py @@ -50,9 +50,9 @@ THE SOFTWARE. """ +from collections.abc import Callable, Iterable, Sequence from functools import singledispatch from numbers import Number -from typing import Callable, Iterable, Sequence import numpy as np @@ -79,7 +79,7 @@ def __gt__(self, other: object) -> bool: return bool(isinstance(other, Number)) def __ge__(self, other: object) -> bool: - return bool(isinstance(other, (Number, _Inf))) + return bool(isinstance(other, Number | _Inf)) inf = _Inf() @@ -298,7 +298,7 @@ def _quadrature_for_tp( else: quad = TensorProductQuadrature([ quadrature_for_space(sp, shp) - for sp, shp in zip(space.bases, shape.bases) + for sp, shp in zip(space.bases, shape.bases, strict=True) ]) assert all(quad.exact_to >= getattr(s, "order", 0) for s in space.bases) diff --git a/modepy/quadrature/grundmann_moeller.py b/modepy/quadrature/grundmann_moeller.py index 82e50b71..42155465 100644 --- a/modepy/quadrature/grundmann_moeller.py +++ b/modepy/quadrature/grundmann_moeller.py @@ -134,7 +134,8 @@ def __init__(self, order: int, dimension: int) -> None: dim_factor = 2**n for p, w in points_to_weights.items(): - real_p = reduce(add, (a/b * v for (a, b), v in zip(p, vertices))) + real_p = reduce(add, (a/b * v + for (a, b), v in zip(p, vertices, strict=True))) nodes.append(real_p) weights.append(dim_factor * w) diff --git a/modepy/shapes.py b/modepy/shapes.py index 63fa37f9..4a277efd 100644 --- a/modepy/shapes.py +++ b/modepy/shapes.py @@ -217,9 +217,10 @@ import contextlib from abc import ABC, abstractmethod +from collections.abc import Callable, Sequence from dataclasses import dataclass from functools import partial, singledispatch -from typing import Any, Callable, Sequence +from typing import Any import numpy as np @@ -291,7 +292,7 @@ def face_normal(face: Face, normalize: bool = True) -> np.ndarray: from operator import xor as outerprod from pymbolic.geometric_algebra import MultiVector - surface_ps = reduce(outerprod, [ + surface_ps: MultiVector = reduce(outerprod, [ MultiVector(face_vertices[:, i+1] - face_vertices[:, 0]) for i in range(face.dim)]) diff --git a/modepy/test/test_matrices.py b/modepy/test/test_matrices.py index 8d8a2e9c..68bd492f 100644 --- a/modepy/test/test_matrices.py +++ b/modepy/test/test_matrices.py @@ -24,7 +24,7 @@ """ -from typing import Tuple, cast +from typing import cast import numpy as np import numpy.linalg as la @@ -110,8 +110,8 @@ def test_tensor_product_diag_mass_matrix(shape: mp.Shape) -> None: # Note that gll_diag_mass_mat is not a good approximation of gll_ref_mass_mat # in the matrix norm sense! - for mid, func in zip(basis.mode_ids, basis.functions): - if max(cast(Tuple[int, ...], mid)) < order - 1: + for mid, func in zip(basis.mode_ids, basis.functions, strict=True): + if max(cast(tuple[int, ...], mid)) < order - 1: err = np.abs( gll_ref_mass_mat @ func(gll_quad.nodes) - gll_diag_mass_mat @ func(gll_quad.nodes)) diff --git a/modepy/test/test_modes.py b/modepy/test/test_modes.py index 4d7b5a2b..04f8d8f4 100644 --- a/modepy/test/test_modes.py +++ b/modepy/test/test_modes.py @@ -178,7 +178,7 @@ def test_basis_grad(dim, shape_cls, order, basis_getter): from pytools import wandering_element from pytools.convergence import EOCRecorder - for bf, gradbf in zip(basis.functions, basis.gradients): + for bf, gradbf in zip(basis.functions, basis.gradients, strict=True): eoc_rec = EOCRecorder() for h in [1e-2, 1e-3]: r = mp.random_nodes_for_shape(shape, nnodes=1000, rng=rng) @@ -246,7 +246,7 @@ def test_symbolic_basis(shape, order, basis_getter): rng = np.random.Generator(np.random.PCG64(17)) r = mp.random_nodes_for_shape(shape, 10000, rng=rng) - for func, sym_func in zip(basis.functions, sym_basis): + for func, sym_func in zip(basis.functions, sym_basis, strict=True): strmap = MyStringifyMapper() s = strmap(sym_func) for name, val in strmap.cse_name_list: @@ -276,7 +276,7 @@ def test_symbolic_basis(shape, order, basis_getter): sym_grad_basis = [mp.symbolicize_function(f, shape.dim) for f in basis.gradients] - for grad, sym_grad in zip(basis.gradients, sym_grad_basis): + for grad, sym_grad in zip(basis.gradients, sym_grad_basis, strict=True): strmap = MyStringifyMapper() s = strmap(sym_grad) for name, val in strmap.cse_name_list: @@ -290,7 +290,7 @@ def test_symbolic_basis(shape, order, basis_getter): sym_val = (sym_val,) ref_val = (ref_val,) - for sv_i, rv_i in zip(sym_val, ref_val): + for sv_i, rv_i in zip(sym_val, ref_val, strict=True): ref_norm = la.norm(rv_i, np.inf) err = la.norm(sv_i-rv_i, np.inf) if ref_norm: diff --git a/modepy/test/test_tools.py b/modepy/test/test_tools.py index 6c386b37..2ef40c4e 100644 --- a/modepy/test/test_tools.py +++ b/modepy/test/test_tools.py @@ -580,7 +580,8 @@ def test_tensor_product_vdm_dim_by_dim(dim): x_r = reshape_array_for_tensor_product_space(space, x) vdm_dimbydim_x_r = x_r - for i, (subspace, subshape) in enumerate(zip(space.bases, shape.bases)): + for i, (subspace, subshape) in enumerate( + zip(space.bases, shape.bases, strict=True)): subnodes = mp.edge_clustered_nodes_for_space(subspace, subshape) subbasis = mp.basis_for_space(subspace, subshape) subvdm = mp.vandermonde(subbasis.functions, subnodes) diff --git a/pyproject.toml b/pyproject.toml index c9489dcc..f24b5228 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [build-system] -build-backend = "setuptools.build_meta" +build-backend = "hatchling.build" requires = [ - "setuptools>=63", + "hatchling", ] [project] @@ -13,7 +13,7 @@ license = { text = "MIT" } authors = [ { name = "Andreas Kloeckner", email = "inform@tiker.net" }, ] -requires-python = ">=3.8" +requires-python = ">=3.10" classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", @@ -32,7 +32,7 @@ classifiers = [ ] dependencies = [ "numpy", - "pymbolic", + "pymbolic>=2024.1", "pytools", ] @@ -53,20 +53,6 @@ Documentation = "https://documen.tician.de/modepy" Homepage = "https://mathema.tician.de/software/modepy" Repository = "https://github.com/inducer/modepy" -[tool.setuptools.packages.find] -include = [ - "modepy*", -] - -[tool.setuptools.package-dir] -# https://github.com/Infleqtion/client-superstaq/pull/715 -"" = "." - -[tool.setuptools.package-data] -modepy = [ - "py.typed", -] - [tool.ruff] preview = true