Skip to content

Commit 0815a2c

Browse files
TYP: Include proper type hints for static type checkers; remove PlottableType and redefinee lower pyvista dependency lower bound.
1 parent 82aebd9 commit 0815a2c

8 files changed

Lines changed: 45 additions & 40 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ classifiers = [
5454
requires-python = ">=3.10"
5555
dependencies = [
5656
"numpy>=2.1.0",
57-
"pyvista>=0.47.0",
57+
"pyvista>=0.46.0",
5858
"psi-io>=2.0.6",
5959
"sunpy>=6.0.3",
6060
"astropy>=6.1.3",

pyvisual/core/_typing.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@
2424
from os import PathLike
2525
from pathlib import Path
2626

27-
from typing import Literal
27+
from typing import Literal, Union, TypeAlias
28+
29+
from pyvista import VectorLike
30+
31+
PlottableType: TypeAlias = Union[
32+
VectorLike[float], 'DataSet', 'MultiBlock', 'PartitionedDataSet', str, Path
33+
]
2834

2935
PathType = str | Path | PathLike[str]
3036
"""Type alias for filesystem path arguments.

pyvisual/core/mesh3d.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def build_point_polydata(d1: np.ndarray,
124124
d2: np.ndarray,
125125
d3: np.ndarray,
126126
axis: int,
127-
frame: Optional[MeshFramesType] = None):
127+
frame: Optional[MeshFramesType] = None) -> pv.PolyData:
128128
"""Build an unconnected :class:`pyvista.PolyData` point cloud from coordinate arrays.
129129
130130
Each element of ``d1``, ``d2``, ``d3`` along ``axis`` defines one point.
@@ -160,7 +160,7 @@ def build_spline_polydata(d1: np.ndarray,
160160
d2: np.ndarray,
161161
d3: np.ndarray,
162162
axis: int,
163-
frame: Optional[MeshFramesType] = None):
163+
frame: Optional[MeshFramesType] = None) -> pv.PolyData:
164164
"""Build a line-connected :class:`pyvista.PolyData` of splines from coordinate arrays.
165165
166166
After moving ``axis`` to the leading dimension, the arrays are reshaped to
@@ -201,7 +201,7 @@ def build_slice_polydata(d1: np.ndarray,
201201
d2: np.ndarray,
202202
d3: np.ndarray,
203203
axis: int,
204-
frame: Optional[MeshFramesType] = None):
204+
frame: Optional[MeshFramesType] = None) -> pv.PolyData:
205205
"""Build a quad-faced :class:`pyvista.PolyData` surface patch from coordinate arrays.
206206
207207
The coordinate arrays are moved so that ``axis`` is the leading dimension,
@@ -260,7 +260,7 @@ def build_surface_polydata(d1: np.ndarray,
260260
axis: int,
261261
method: SurfaceReconstructionType = 'reconstruct_surface',
262262
frame: Optional[MeshFramesType] = None,
263-
**kwargs):
263+
**kwargs) -> pv.PolyData:
264264
"""Build a surface mesh from scattered coordinate arrays using a reconstruction method.
265265
266266
First assembles a point cloud via :func:`build_point_polydata`, then applies
@@ -315,7 +315,7 @@ def build_thompson_sphere(d1: float,
315315
d3: float,
316316
theta_resolution: int = 180,
317317
phi_resolution: int = 360,
318-
frame: Optional[MeshFramesType] = None):
318+
frame: Optional[MeshFramesType] = None) -> pv.PolyData:
319319
"""Build a Thomson sphere centered halfway between the origin and an observer position.
320320
321321
The Thomson sphere for a given observer has:

pyvisual/core/mixins.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -802,9 +802,9 @@ def add_1d_slice(self,
802802
raise ValueError("1D slices requires exactly two fixed scales.")
803803
try:
804804
axis = next(i for i, s in enumerate(mesh_shape) if s > 1)
805-
except StopIteration:
805+
except StopIteration as e:
806806
msg = f"Could not infer slice axis from input shapes: {mesh_shape}"
807-
raise ValueError(msg)
807+
raise ValueError(msg) from e
808808
return self._add_grid_set(r, t, p, data,
809809
axis, dataid,
810810
slice_type='splines',
@@ -899,9 +899,9 @@ def add_2d_slice(self,
899899
raise ValueError("2D slices requires exactly one fixed scale.")
900900
try:
901901
axis = next(i for i, s in enumerate(mesh_shape) if s == 1)
902-
except StopIteration:
902+
except StopIteration as e:
903903
msg = f"Could not infer slice axis from input shapes: {mesh_shape}"
904-
raise ValueError(msg)
904+
raise ValueError(msg) from e
905905
return self._add_grid_set(r, t, p, data,
906906
axis, dataid,
907907
slice_type='slices',
@@ -1309,7 +1309,7 @@ def observer_viewup(self) -> SphericalCoordinate:
13091309

13101310
@observer_viewup.setter
13111311
@render_scene
1312-
def observer_viewup(self, args):
1312+
def observer_viewup(self, args) -> None:
13131313
r, t, p = args
13141314
self.camera.up = spherical_to_cartesian(r, t, p)
13151315

@@ -1344,7 +1344,7 @@ def observer_position(self) -> SphericalCoordinate:
13441344

13451345
@observer_position.setter
13461346
@render_scene
1347-
def observer_position(self, args):
1347+
def observer_position(self, args) -> None:
13481348
r, t, p = args
13491349
self.camera.position = spherical_to_cartesian(r, t, p)
13501350

@@ -1363,7 +1363,7 @@ def observer_focus(self) -> SphericalCoordinate:
13631363

13641364
@observer_focus.setter
13651365
@render_scene
1366-
def observer_focus(self, args):
1366+
def observer_focus(self, args) -> None:
13671367
r, t, p = args
13681368
self.camera.focal_point = spherical_to_cartesian(r, t, p)
13691369

@@ -1401,7 +1401,7 @@ def observer_orientation(self) -> ObserverOrientation:
14011401

14021402
@observer_orientation.setter
14031403
@render_scene
1404-
def observer_orientation(self, arg):
1404+
def observer_orientation(self, arg) -> None:
14051405
p_angle = arg
14061406
current_p_angle = camera_roll_wrt_solar_north(*self.camera_position)
14071407
self.camera.roll += (p_angle - current_p_angle)
@@ -1520,7 +1520,7 @@ def observer_los_view(self) -> tuple[float, float, float, float]:
15201520

15211521
@observer_los_view.setter
15221522
@render_scene
1523-
def observer_los_view(self, args):
1523+
def observer_los_view(self, args) -> None:
15241524
x0, x1, y0, y1 = args
15251525

15261526
elongation = (x0 + x1) / 2
@@ -1604,7 +1604,7 @@ def observer_fov_view(self) -> Optional[float]:
16041604

16051605
@observer_fov_view.setter
16061606
@render_scene
1607-
def observer_fov_view(self, args):
1607+
def observer_fov_view(self, args) -> None:
16081608
rmin = abs(args)
16091609
dobs = self.observer_position.r
16101610
if rmin < dobs:

pyvisual/core/parsers.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
import numpy as np
5252
import pyvista as pv
5353
from pyvista import algorithm_to_mesh_handler
54-
from pyvista.plotting._typing import PlottableType
5554

55+
from pyvisual.core._typing import PlottableType
5656
from pyvisual.core.constants import FRAME_ALIASES
5757
from pyvisual.utils.helpers import atleast_1dnull
5858
from pyvisual.utils.geometry import (
@@ -248,7 +248,8 @@ def decorator(self,
248248
return decorator
249249

250250

251-
def generate_transforms(mframe, pframe):
251+
def generate_transforms(mframe: str,
252+
pframe: str) -> list[Callable]:
252253
"""Return a list of coordinate-conversion functions from ``mframe`` to ``pframe``.
253254
254255
Looks up the ``(canonical_mframe, canonical_pframe)`` pair in
@@ -285,7 +286,7 @@ def generate_transforms(mframe, pframe):
285286
return transforms
286287

287288

288-
def validate_mesh_type(mesh: PlottableType):
289+
def validate_mesh_type(mesh: PlottableType) -> PlottableType:
289290
"""Ensure ``mesh`` is a valid PyVista dataset, wrapping it if necessary.
290291
291292
Resolves any VTK algorithm objects via
@@ -317,7 +318,9 @@ def validate_mesh_type(mesh: PlottableType):
317318
return mesh
318319

319320

320-
def apply_mesh_transform(mesh: PlottableType, mframe, pframe):
321+
def apply_mesh_transform(mesh: PlottableType,
322+
mframe: str,
323+
pframe: str) -> PlottableType:
321324
"""Convert mesh point coordinates from ``mframe`` to ``pframe`` in-place on a copy.
322325
323326
If the mesh stores a ``'MESH_FRAME'`` key in :attr:`pyvista.DataSet.user_dict`
@@ -368,7 +371,7 @@ def apply_mesh_transform(mesh: PlottableType, mframe, pframe):
368371

369372
def parse_stack_mesh(r: np.ndarray,
370373
t: np.ndarray,
371-
p: np.ndarray):
374+
p: np.ndarray) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
372375
"""Validate that three coordinate arrays share an identical shape.
373376
374377
Used by :class:`~pyvisual.core.mixins.StackMeshMixin` methods to confirm that
@@ -402,7 +405,7 @@ def parse_stack_mesh(r: np.ndarray,
402405

403406
def parse_grid_mesh(r: np.ndarray,
404407
t: np.ndarray,
405-
p: np.ndarray):
408+
p: np.ndarray) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
406409
"""Validate and optionally broadcast coordinate arrays for a structured grid.
407410
408411
Accepts two input conventions:

pyvisual/utils/data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ def fetch_datasets(domains: Iterable[str] | str = 'cor',
192192
return Filepaths(*(FETCHER.fetch(f"cr2282-thermo2-{dom}/{var}002.h5") for dom, var in req_pairs))
193193

194194

195-
def fetch_theme():
195+
def fetch_theme() -> Path:
196196
"""Return the path to the bundled PyVisual PyVista theme file.
197197
198198
Resolves ``pyvisual_theme.json`` from the package's ``_assets`` directory

pyvisual/utils/geometry.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ def cartesian_to_spherical_vec(vr: ArrayLike,
298298
vt: ArrayLike,
299299
vp: ArrayLike,
300300
t: ArrayLike,
301-
p: ArrayLike):
301+
p: ArrayLike) -> tuple[ArrayLike, ArrayLike, ArrayLike]:
302302
"""Rotate vector components from the local spherical basis to the Cartesian basis.
303303
304304
Given a vector expressed in the local orthonormal spherical basis
@@ -396,7 +396,7 @@ def spherical_to_cartesian_vec(vx: ArrayLike,
396396
vy: ArrayLike,
397397
vz: ArrayLike,
398398
t: ArrayLike,
399-
p: ArrayLike):
399+
p: ArrayLike) -> tuple[ArrayLike, ArrayLike, ArrayLike]:
400400
"""Rotate vector components from the Cartesian basis to the local spherical basis.
401401
402402
Given a vector expressed in the global Cartesian basis
@@ -493,8 +493,7 @@ def rotate_position_about_x(
493493
x: ArrayLike,
494494
y: ArrayLike,
495495
z: ArrayLike,
496-
angle: float,
497-
) -> tuple[ArrayLike, ArrayLike, ArrayLike]:
496+
angle: float,) -> tuple[ArrayLike, ArrayLike, ArrayLike]:
498497
"""Rotate Cartesian position vectors about the :math:`+x` axis.
499498
500499
Applies a right-handed rotation by ``angle`` degrees about :math:`+x`
@@ -567,8 +566,7 @@ def rotate_position_about_y(
567566
x: ArrayLike,
568567
y: ArrayLike,
569568
z: ArrayLike,
570-
angle: float,
571-
) -> tuple[ArrayLike, ArrayLike, ArrayLike]:
569+
angle: float,) -> tuple[ArrayLike, ArrayLike, ArrayLike]:
572570
"""Rotate Cartesian position vectors about the :math:`+y` axis.
573571
574572
Applies a right-handed rotation by ``angle`` degrees about :math:`+y`
@@ -641,8 +639,7 @@ def rotate_position_about_z(
641639
x: ArrayLike,
642640
y: ArrayLike,
643641
z: ArrayLike,
644-
angle: float,
645-
) -> tuple[ArrayLike, ArrayLike, ArrayLike]:
642+
angle: float,) -> tuple[ArrayLike, ArrayLike, ArrayLike]:
646643
"""Rotate Cartesian position vectors about the :math:`+z` axis.
647644
648645
Applies a right-handed rotation by ``angle`` degrees about :math:`+z`
@@ -712,7 +709,7 @@ def rotate_position_about_z(
712709

713710

714711
def clip_angle(angle: ArrayLike,
715-
max_value: float = 180):
712+
max_value: float = 180) -> np.ndarray | float:
716713
"""Wrap an angle in degrees to a half-open interval of width 360°.
717714
718715
Reduces ``angle`` modulo :math:`360°` and then shifts the result into
@@ -766,7 +763,7 @@ def thompson_sphere(elong: ArrayLike,
766763
obs_lon: ArrayLike,
767764
obs_lat: ArrayLike,
768765
r_obs_rs: ArrayLike,
769-
obs_pangle: ArrayLike = 0.0):
766+
obs_pangle: ArrayLike = 0.0) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
770767
"""Compute the 3-D intersection of a line of sight with the Thompson sphere.
771768
772769
The `Thompson sphere
@@ -911,7 +908,7 @@ def thompson_sphere(elong: ArrayLike,
911908

912909

913910
def los_rmin2angle(rmin_rs: ArrayLike,
914-
d_obs_rs: float):
911+
d_obs_rs: float) -> np.ndarray | float:
915912
"""Convert a LOS impact parameter :math:`r_{min}` to a helioprojective angle.
916913
917914
The *impact parameter* :math:`r_{min}` is the distance of closest approach
@@ -986,7 +983,7 @@ def los_rmin2angle(rmin_rs: ArrayLike,
986983

987984

988985
def los_angle2rmin(angle_deg: ArrayLike,
989-
d_obs_rs: float):
986+
d_obs_rs: float) -> np.ndarray | float:
990987
"""Convert a helioprojective angle to a LOS impact parameter :math:`r_{min}`.
991988
992989
The inverse of :func:`los_rmin2angle`. Given the helioprojective
@@ -1568,7 +1565,7 @@ def spacecraft_trajectory(
15681565
return np.stack(ephemeris, axis=0)
15691566

15701567

1571-
def _norm(x, eps=1e-12):
1568+
def _norm(x: ArrayLike, eps: float = 1e-12):
15721569
"""Normalise a vector, returning ``None`` for near-zero inputs.
15731570
15741571
Parameters
@@ -1596,8 +1593,7 @@ def camera_roll_wrt_solar_north(
15961593
focal_point: tuple[float, float, float],
15971594
view_up: tuple[float, float, float],
15981595
world_up: tuple[float, float, float] = SOLAR_NORTH,
1599-
degrees: bool = True,
1600-
):
1596+
degrees: bool = True,) -> float:
16011597
"""Compute the camera roll angle relative to a world "up” direction.
16021598
16031599
The roll is the signed rotation **about the view axis**

pyvisual/utils/helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212

1313
def atleast_1dnull(*args,
14-
astuple: bool = False):
14+
astuple: bool = False) -> np.ndarray | None | tuple[np.ndarray | None, ...]:
1515
""":func:`numpy.atleast_1d` that passes ``None`` values through unchanged.
1616
1717
A thin wrapper around :func:`numpy.atleast_1d` that treats ``None`` as a

0 commit comments

Comments
 (0)