diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d450aac1..0ee289de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,3 +52,28 @@ jobs: uses: codecov/codecov-action@v5.4.0 with: token: ${{ secrets.CODECOV_TOKEN }} + typechecking: + name: mypy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: mamba-org/setup-micromamba@v2 + with: + environment-name: ship + environment-file: environment.yml + create-args: >- + python=3.12 + + - run: pip install . --no-deps + - run: conda install lxml # dep for report generation + - name: Typechecking + run: | + mypy --install-types --non-interactive src/virtualship --html-report mypy-report + - name: Upload test results + if: ${{ always() }} # Upload even on mypy error + uses: actions/upload-artifact@v4 + with: + name: Mypy report + path: mypy-report diff --git a/environment.yml b/environment.yml index 38d96dc3..0146e277 100644 --- a/environment.yml +++ b/environment.yml @@ -16,6 +16,7 @@ dependencies: # linting - pre-commit + - mypy # Testing - pytest diff --git a/src/virtualship/expedition/do_expedition.py b/src/virtualship/expedition/do_expedition.py index 97a66f7f..4f6d69b0 100644 --- a/src/virtualship/expedition/do_expedition.py +++ b/src/virtualship/expedition/do_expedition.py @@ -50,7 +50,7 @@ def do_expedition(expedition_dir: str | Path, input_data: Path | None = None) -> checkpoint.verify(schedule) # load fieldsets - input_data = _load_input_data( + loaded_input_data = _load_input_data( expedition_dir=expedition_dir, schedule=schedule, ship_config=ship_config, @@ -58,7 +58,7 @@ def do_expedition(expedition_dir: str | Path, input_data: Path | None = None) -> ) # verify schedule is valid - schedule.verify(ship_config.ship_speed_knots, input_data) + schedule.verify(ship_config.ship_speed_knots, loaded_input_data) # simulate the schedule schedule_results = simulate_schedule( @@ -98,7 +98,7 @@ def do_expedition(expedition_dir: str | Path, input_data: Path | None = None) -> simulate_measurements( expedition_dir, ship_config, - input_data, + loaded_input_data, schedule_results.measurements_to_simulate, ) print("Done simulating measurements.") @@ -131,6 +131,10 @@ def _load_input_data( space_time_region_hash = get_space_time_region_hash(schedule.space_time_region) input_data = get_existing_download(expedition_dir, space_time_region_hash) + assert input_data is not None, ( + "Input data hasn't been found. Have you run the `virtualship fetch` command?" + ) + return InputData.load( directory=input_data, load_adcp=ship_config.adcp_config is not None, diff --git a/src/virtualship/expedition/input_data.py b/src/virtualship/expedition/input_data.py index 554efb78..77598d0b 100644 --- a/src/virtualship/expedition/input_data.py +++ b/src/virtualship/expedition/input_data.py @@ -43,6 +43,7 @@ def load( :param load_ship_underwater_st: Whether to load the ship underwater ST fieldset. :returns: An instance of this class with loaded fieldsets. """ + directory = Path(directory) if load_drifter: drifter_fieldset = cls._load_drifter_fieldset(directory) else: @@ -152,7 +153,7 @@ def _load_drifter_fieldset(cls, directory: Path) -> FieldSet: return fieldset @classmethod - def _load_argo_float_fieldset(cls, directory: str | Path) -> FieldSet: + def _load_argo_float_fieldset(cls, directory: Path) -> FieldSet: filenames = { "U": directory.joinpath("argo_float_uv.nc"), "V": directory.joinpath("argo_float_uv.nc"), diff --git a/src/virtualship/expedition/schedule.py b/src/virtualship/expedition/schedule.py index 79f14758..4ecd5e7c 100644 --- a/src/virtualship/expedition/schedule.py +++ b/src/virtualship/expedition/schedule.py @@ -5,6 +5,7 @@ import itertools from datetime import datetime, timedelta from pathlib import Path +from typing import TYPE_CHECKING import pydantic import pyproj @@ -12,10 +13,11 @@ from parcels import FieldSet from ..location import Location -from .input_data import InputData from .ship_config import InstrumentType from .space_time_region import SpaceTimeRegion +if TYPE_CHECKING: + from .input_data import InputData projection: pyproj.Geod = pyproj.Geod(ellps="WGS84") diff --git a/src/virtualship/expedition/simulate_measurements.py b/src/virtualship/expedition/simulate_measurements.py index bf28c989..7d81d5d6 100644 --- a/src/virtualship/expedition/simulate_measurements.py +++ b/src/virtualship/expedition/simulate_measurements.py @@ -1,7 +1,10 @@ """simulate_measurements function.""" +from __future__ import annotations + from datetime import timedelta from pathlib import Path +from typing import TYPE_CHECKING from ..instruments.adcp import simulate_adcp from ..instruments.argo_float import simulate_argo_floats @@ -9,10 +12,12 @@ from ..instruments.drifter import simulate_drifters from ..instruments.ship_underwater_st import simulate_ship_underwater_st from ..instruments.xbt import simulate_xbt -from .input_data import InputData from .ship_config import ShipConfig from .simulate_schedule import MeasurementsToSimulate +if TYPE_CHECKING: + from .input_data import InputData + def simulate_measurements( expedition_dir: str | Path,