diff --git a/.github/workflows/install-and-test.yml b/.github/workflows/install-and-test.yml index 0ea43dc8..5d571af0 100644 --- a/.github/workflows/install-and-test.yml +++ b/.github/workflows/install-and-test.yml @@ -67,6 +67,11 @@ jobs: run: | python -c "import torch; assert torch.__version__.endswith('+cu130')" + - name: Type check with ty + if: matrix.device == 'cpu' + run: | + uv run ty check neural_lam + - name: Load cache data uses: actions/cache/restore@v4 with: diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 58085b24..a6a3f24a 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -21,3 +21,5 @@ jobs: with: python-version: ${{ matrix.python-version }} - uses: pre-commit/action@v3.0.1 + env: + SKIP: ty diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 229326ea..af1d16ed 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -43,12 +43,16 @@ repos: description: Ensure documentation coverage stays perfect pass_filenames: false args: ["-c", "pyproject.toml", "neural_lam"] - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.19.0 + - repo: local hooks: - - id: mypy - additional_dependencies: [types-PyYAML, types-Pillow, types-tqdm] + - id: ty + name: ty description: Check for type errors + entry: uv run ty check neural_lam + language: system + pass_filenames: false + files: ^neural_lam/ + types: [python] - repo: local hooks: diff --git a/CHANGELOG.md b/CHANGELOG.md index 62dcb764..0f204948 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Allow `graph_lam` training and checkpoint reloads to accept the full set of + GNN type CLI options without passing hierarchical-only options to unsupported + constructors ([#686](https://github.com/mllam/neural-lam/issues/686)). + - Fix `RuntimeError` in `HiLAMParallel` forward pass on hierarchical graphs by offsetting edge indices into the global mesh node index space ([#679](https://github.com/mllam/neural-lam/issues/679)) - Fix `IndexError` in HiLAM forward pass by offsetting grid nodes in `zero_index_g2m`/`zero_index_m2g` by the total mesh-node count across all levels ([#642](https://github.com/mllam/neural-lam/issues/642)) @Sir-Sloth-The-Lazy @@ -81,6 +85,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Maintenance +- Add 100% type-hint coverage across `neural_lam/`, align all type annotations with PEP 585 and PEP 604, and adopt `ty` (astral-sh) for type checking [\#673](https://github.com/mllam/neural-lam/pull/673) @GiGiKoneti + - Split the monolithic `neural_lam/utils.py` into a `neural_lam/utils/` package with one module per concern (`buffer_list`, `graph`, `networks`, `plot`, `logging`, `tensor`, `time`); `utils/__init__.py` re-exports the full public API so existing imports are unaffected. Pure code movement, no behavioural change. [\#682](https://github.com/mllam/neural-lam/pull/682) @Sir-Sloth-The-Lazy - Add comprehensive type hints to GraphLAM in `neural_lam/models/step_predictors/graph/graph_lam.py` [\#669](https://github.com/mllam/neural-lam/pull/669) @GiGiKoneti diff --git a/neural_lam/config.py b/neural_lam/config.py index 1da43fff..a449085a 100644 --- a/neural_lam/config.py +++ b/neural_lam/config.py @@ -3,7 +3,7 @@ # Standard library import dataclasses from pathlib import Path -from typing import Dict, Union +from typing import cast # Third-party import dataclass_wizard @@ -35,7 +35,7 @@ class DatastoreSelection: kind: str config_path: str - def __post_init__(self): + def __post_init__(self) -> None: """ Validate that the selected datastore kind is implemented. @@ -56,11 +56,11 @@ class ManualStateFeatureWeighting: Attributes ---------- - weights : Dict[str, float] + weights : dict[str, float] Manual weights for the state features. """ - weights: Dict[str, float] + weights: dict[str, float] @dataclasses.dataclass @@ -80,14 +80,14 @@ class OutputClamping: Attributes ---------- - lower : Dict[str, float] + lower : dict[str, float] The minimum value to clamp each output feature to. - upper : Dict[str, float] + upper : dict[str, float] The maximum value to clamp each output feature to. """ - lower: Dict[str, float] = dataclasses.field(default_factory=dict) - upper: Dict[str, float] = dataclasses.field(default_factory=dict) + lower: dict[str, float] = dataclasses.field(default_factory=dict) + upper: dict[str, float] = dataclasses.field(default_factory=dict) @dataclasses.dataclass @@ -97,8 +97,8 @@ class TrainingConfig: Attributes ---------- - state_feature_weighting : Union[ManualStateFeatureWeighting, - UniformFeatureWeighting] + state_feature_weighting : + ManualStateFeatureWeighting | UniformFeatureWeighting The method to use for weighting the state features in the loss function. Defaults to uniform weighting (`UniformFeatureWeighting`, i.e. all features are weighted equally). @@ -107,9 +107,9 @@ class TrainingConfig: Defaults to an empty ``OutputClamping`` (no clamping). """ - state_feature_weighting: Union[ - ManualStateFeatureWeighting, UniformFeatureWeighting - ] = dataclasses.field(default_factory=UniformFeatureWeighting) + state_feature_weighting: ( + ManualStateFeatureWeighting | UniformFeatureWeighting + ) = dataclasses.field(default_factory=UniformFeatureWeighting) output_clamping: OutputClamping = dataclasses.field( default_factory=OutputClamping @@ -174,7 +174,7 @@ class InvalidConfigError(Exception): def load_config_and_datastore( config_path: str, -) -> tuple[NeuralLAMConfig, Union[MDPDatastore, NpyFilesDatastoreMEPS]]: +) -> tuple[NeuralLAMConfig, MDPDatastore | NpyFilesDatastoreMEPS]: """ Load the neural-lam configuration and the datastore specified in the configuration. @@ -186,7 +186,7 @@ def load_config_and_datastore( Returns ------- - tuple[NeuralLAMConfig, Union[MDPDatastore, NpyFilesDatastoreMEPS]] + tuple[NeuralLAMConfig, MDPDatastore | NpyFilesDatastoreMEPS] The Neural-LAM configuration and the loaded datastore. """ try: @@ -204,4 +204,4 @@ def load_config_and_datastore( datastore_kind=config.datastore.kind, config_path=datastore_config_path ) - return config, datastore + return config, cast(MDPDatastore | NpyFilesDatastoreMEPS, datastore) diff --git a/neural_lam/create_graph.py b/neural_lam/create_graph.py index 19734d72..75b31f33 100644 --- a/neural_lam/create_graph.py +++ b/neural_lam/create_graph.py @@ -3,7 +3,6 @@ # Standard library import os from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser -from typing import Optional # Third-party import matplotlib @@ -27,7 +26,7 @@ def plot_graph( - graph: pyg.data.Data, title: Optional[str] = None + graph: pyg.data.Data, title: str | None = None ) -> tuple[matplotlib.figure.Figure, matplotlib.axes.Axes]: """ Render a PyTorch Geometric graph using stored node coordinates. @@ -357,10 +356,10 @@ def prepend_node_index(graph: networkx.Graph, new_index: int) -> networkx.Graph: def create_graph( graph_dir_path: str, xy: np.ndarray, - n_max_levels: Optional[int] = None, - hierarchical: Optional[bool] = False, - create_plot: Optional[bool] = False, -): + n_max_levels: int | None = None, + hierarchical: bool = False, + create_plot: bool = False, +) -> None: """ Create graph components from `xy` grid coordinates and store in `graph_dir_path`. @@ -653,8 +652,10 @@ def create_graph( .reshape((n, n, 2))[1::nx, 1::nx, :] .reshape(int(n / nx) ** 2, 2) ) - ij = [tuple(x) for x in ij] - G[lev] = networkx.relabel_nodes(G[lev], dict(zip(G[lev].nodes, ij))) + ij_tuples = [tuple(x) for x in ij] + G[lev] = networkx.relabel_nodes( + G[lev], dict(zip(G[lev].nodes, ij_tuples)) + ) G_tot = networkx.compose(G_tot, G[lev]) # Relabel mesh nodes to start with 0 @@ -864,10 +865,10 @@ def create_graph( def create_graph_from_datastore( datastore: BaseRegularGridDatastore, output_root_path: str, - n_max_levels: Optional[int] = None, + n_max_levels: int | None = None, hierarchical: bool = False, create_plot: bool = False, -): +) -> None: """ Generate graph components for ``datastore`` and persist them on disk. @@ -900,7 +901,7 @@ def create_graph_from_datastore( ) -def cli(input_args: Optional[list[str]] = None) -> None: +def cli(input_args: list[str] | None = None) -> None: """ Parse CLI arguments and call :func:`create_graph_from_datastore`. diff --git a/neural_lam/custom_loggers.py b/neural_lam/custom_loggers.py index 5b6000e6..1d5ff9f3 100644 --- a/neural_lam/custom_loggers.py +++ b/neural_lam/custom_loggers.py @@ -2,7 +2,6 @@ # Standard library import os -from typing import Optional # Third-party import matplotlib.pyplot as plt @@ -74,7 +73,7 @@ def log_image( self, key: str, images: list[plt.Figure], - step: Optional[int] = None, + step: int | None = None, ) -> None: """ Log one or more matplotlib figures as images to MLFlow. diff --git a/neural_lam/datastore/__init__.py b/neural_lam/datastore/__init__.py index e2117217..dece5259 100644 --- a/neural_lam/datastore/__init__.py +++ b/neural_lam/datastore/__init__.py @@ -1,5 +1,8 @@ """Datastore backends for loading and serving weather model data.""" +# Standard library +from pathlib import Path + # Local from .base import BaseDatastore # noqa from .mdp import MDPDatastore # noqa @@ -11,12 +14,13 @@ ] DATASTORES = { - datastore.SHORT_NAME: datastore # type: ignore - for datastore in DATASTORE_CLASSES + datastore.SHORT_NAME: datastore for datastore in DATASTORE_CLASSES } -def init_datastore(datastore_kind, config_path): +def init_datastore( + datastore_kind: str, config_path: str | Path +) -> BaseDatastore: """ Instantiate a datastore based on its short-name identifier. diff --git a/neural_lam/datastore/base.py b/neural_lam/datastore/base.py index 8376d38d..1abe3ac9 100644 --- a/neural_lam/datastore/base.py +++ b/neural_lam/datastore/base.py @@ -111,7 +111,7 @@ def get_vars_units(self, category: str) -> list[str]: Returns ------- - List[str] + list[str] The units of the variables. """ @@ -127,7 +127,7 @@ def get_vars_names(self, category: str) -> list[str]: Returns ------- - List[str] + list[str] The names of the variables. """ @@ -143,7 +143,7 @@ def get_vars_long_names(self, category: str) -> list[str]: Returns ------- - List[str] + list[str] The long names of the variables. """ @@ -333,7 +333,7 @@ def get_xy_extent(self, category: str) -> list[float]: Returns ------- - List[float] + list[float] The extent of the x, y coordinates. """ @@ -423,7 +423,7 @@ def expected_dim_order( The category of the dataset (state/forcing/static). Returns ------- - List[str] + list[str] The expected dimension order for the dataarray or dataset. """ @@ -496,7 +496,7 @@ class BaseRegularGridDatastore(BaseDatastore): `stack_grid_coords` and `unstack_grid_coords` respectively). """ - spatial_coordinates = ("x", "y") + spatial_coordinates: tuple[str, str] = ("x", "y") @cached_property @abc.abstractmethod @@ -562,7 +562,7 @@ def unstack_grid_coords( da_or_ds_unstacked = da_or_ds.unstack("grid_index") # Ensure that the x, y dimensions are in the correct order - dims = da_or_ds_unstacked.dims + dims = list(da_or_ds_unstacked.dims) xy_dim_order = [d for d in dims if d in self.spatial_coordinates] if xy_dim_order != self.spatial_coordinates: @@ -615,7 +615,7 @@ def stack_grid_coords( # dimension named in the format `{category}_feature` category = None for dim in da_or_ds_stacked.dims: - if dim.endswith("_feature"): + if isinstance(dim, str) and dim.endswith("_feature"): if category is not None: raise ValueError( "Multiple dimensions ending with '_feature' found in " diff --git a/neural_lam/datastore/mdp.py b/neural_lam/datastore/mdp.py index 7cad45d7..860f1af3 100644 --- a/neural_lam/datastore/mdp.py +++ b/neural_lam/datastore/mdp.py @@ -7,7 +7,6 @@ from datetime import timedelta from functools import cached_property from pathlib import Path -from typing import List, Optional, Union # Third-party import cartopy.crs as ccrs @@ -36,7 +35,7 @@ class MDPDatastore(BaseRegularGridDatastore): def __init__( self, - config_path: Union[str, Path], + config_path: str | Path, n_boundary_points: int = 30, reuse_existing: bool = True, ) -> None: @@ -176,7 +175,7 @@ def step_length(self) -> timedelta: total_sec = da_dt.dt.total_seconds().isel(time=0).astype(int) return timedelta(seconds=int(total_sec.item())) - def get_vars_units(self, category: str) -> List[str]: + def get_vars_units(self, category: str) -> list[str]: """Return the units of the variables in the given category. Parameters @@ -186,7 +185,7 @@ def get_vars_units(self, category: str) -> List[str]: Returns ------- - List[str] + list[str] The units of the variables in the given category. """ @@ -195,7 +194,7 @@ def get_vars_units(self, category: str) -> List[str]: return [] return self._ds[f"{category}_feature_units"].values.tolist() - def get_vars_names(self, category: str) -> List[str]: + def get_vars_names(self, category: str) -> list[str]: """Return the names of the variables in the given category. Parameters @@ -205,7 +204,7 @@ def get_vars_names(self, category: str) -> List[str]: Returns ------- - List[str] + list[str] The names of the variables in the given category. """ @@ -214,7 +213,7 @@ def get_vars_names(self, category: str) -> List[str]: return [] return self._ds[f"{category}_feature"].values.tolist() - def get_vars_long_names(self, category: str) -> List[str]: + def get_vars_long_names(self, category: str) -> list[str]: """ Return the long names of the variables in the given category. @@ -225,7 +224,7 @@ def get_vars_long_names(self, category: str) -> List[str]: Returns ------- - List[str] + list[str] The long names of the variables in the given category. """ @@ -253,9 +252,9 @@ def get_num_data_vars(self, category: str) -> int: def get_dataarray( self, category: str, - split: Optional[str], + split: str | None, standardize: bool = False, - ) -> Union[xr.DataArray, None]: + ) -> xr.DataArray | None: """ Return the processed data (as a single `xr.DataArray`) for the given category of data and test/train/val-split that covers all the data (in @@ -364,7 +363,7 @@ def get_standardization_dataarray(self, category: str) -> xr.Dataset: # Add standardized state diff stats if category == "state": ds_stats = ds_stats.assign( - **{ + { f"state_diff_{op}_standardized": self._ds[ f"state__{split}__diff_{op}" ] @@ -404,7 +403,11 @@ def boundary_mask(self) -> xr.DataArray: ds_unstacked["boundary_mask"] = ds_unstacked.boundary_mask.fillna( 1 ).astype(int) - return self.stack_grid_coords(da_or_ds=ds_unstacked.boundary_mask) + boundary_mask = self.stack_grid_coords( + da_or_ds=ds_unstacked.boundary_mask + ) + assert isinstance(boundary_mask, xr.DataArray) + return boundary_mask @property def coords_projection(self) -> ccrs.Projection: diff --git a/neural_lam/datastore/npyfilesmeps/compute_standardization_stats.py b/neural_lam/datastore/npyfilesmeps/compute_standardization_stats.py index 9e694f14..84c5b808 100644 --- a/neural_lam/datastore/npyfilesmeps/compute_standardization_stats.py +++ b/neural_lam/datastore/npyfilesmeps/compute_standardization_stats.py @@ -6,6 +6,7 @@ from argparse import ArgumentParser from datetime import timedelta from pathlib import Path +from typing import Any, cast # Third-party import torch @@ -22,7 +23,12 @@ class PaddedWeatherDataset(torch.utils.data.Dataset): """Wrap :class:`WeatherDataset` to pad samples for distributed runners.""" - def __init__(self, base_dataset, world_size, batch_size): + def __init__( + self, + base_dataset: WeatherDataset, + world_size: int, + batch_size: int, + ) -> None: """ Parameters ---------- @@ -46,7 +52,9 @@ def __init__(self, base_dataset, world_size, batch_size): range(self.total_samples, self.total_samples + self.padded_samples) ) - def __getitem__(self, idx): + def __getitem__( # ty: ignore[invalid-method-override] + self, idx: int + ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: """Return an item, repeating the final sample for padded indices.""" return self.base_dataset[ ( @@ -56,16 +64,16 @@ def __getitem__(self, idx): ) ] - def __len__(self): + def __len__(self) -> int: """Return the padded dataset length.""" return self.total_samples + self.padded_samples - def get_original_indices(self): + def get_original_indices(self) -> list[int]: """Return indices of the non-padded samples.""" return self.original_indices -def get_rank(): +def get_rank() -> int: """ Return the rank inferred from SLURM or default to 0. @@ -77,7 +85,7 @@ def get_rank(): return int(os.environ.get("SLURM_PROCID", 0)) -def get_world_size(): +def get_world_size() -> int: """ Return the world size inferred from SLURM or default to 1. @@ -89,7 +97,9 @@ def get_world_size(): return int(os.environ.get("SLURM_NTASKS", 1)) -def setup(rank, world_size): # pylint: disable=redefined-outer-name +def setup( + rank: int, world_size: int +) -> None: # pylint: disable=redefined-outer-name """ Initialize the distributed group. @@ -140,8 +150,13 @@ def setup(rank, world_size): # pylint: disable=redefined-outer-name def save_stats( - static_dir_path, means, squares, flux_means, flux_squares, filename_prefix -): + static_dir_path: str | Path, + means: list[torch.Tensor], + squares: list[torch.Tensor], + flux_means: list[torch.Tensor], + flux_squares: list[torch.Tensor], + filename_prefix: str, +) -> None: """ Aggregate running statistics and persist them to ``static_dir_path``. @@ -174,14 +189,14 @@ def save_stats( filename_prefix : str Prefix (e.g., ``"parameter"`` or ``"diff"``) for saved tensors. """ - means = ( - torch.stack(means) if len(means) > 1 else means[0] + means_tensor = ( + torch.stack(list(means)) if len(means) > 1 else means[0] ) # (B, d_features,) - squares = ( - torch.stack(squares) if len(squares) > 1 else squares[0] + squares_tensor = ( + torch.stack(list(squares)) if len(squares) > 1 else squares[0] ) # (B, d_features,) - mean = torch.mean(means, dim=0) # (d_features,) - second_moment = torch.mean(squares, dim=0) # (d_features,) + mean = torch.mean(means_tensor, dim=0) # (d_features,) + second_moment = torch.mean(squares_tensor, dim=0) # (d_features,) std = torch.sqrt(second_moment - mean**2) # (d_features,) print( f"Saving {filename_prefix} mean and std.-dev. to " @@ -196,14 +211,16 @@ def save_stats( if len(flux_means) == 0: return - flux_means = ( - torch.stack(flux_means) if len(flux_means) > 1 else flux_means[0] + flux_means_tensor = ( + torch.stack(list(flux_means)) if len(flux_means) > 1 else flux_means[0] ) # (B,) - flux_squares = ( - torch.stack(flux_squares) if len(flux_squares) > 1 else flux_squares[0] + flux_squares_tensor = ( + torch.stack(list(flux_squares)) + if len(flux_squares) > 1 + else flux_squares[0] ) # (B,) - flux_mean = torch.mean(flux_means) # (,) - flux_second_moment = torch.mean(flux_squares) # (,) + flux_mean = torch.mean(flux_means_tensor) # (,) + flux_second_moment = torch.mean(flux_squares_tensor) # (,) flux_std = torch.sqrt(flux_second_moment - flux_mean**2) # (,) print("Saving flux mean and std.-dev. to flux_stats.pt") torch.save( @@ -213,8 +230,12 @@ def save_stats( def main( - datastore_config_path, batch_size, step_length, n_workers, distributed -): + datastore_config_path: str | Path, + batch_size: int, + step_length: timedelta, + n_workers: int, + distributed: bool, +) -> None: """ Pre-compute and persist standardization statistics from the datastore. @@ -252,16 +273,18 @@ def main( # 65 forecast steps - 2 initial steps = 63 ar_steps = 63 # Raw (non-standardized) data for computing mean/std - ds = WeatherDataset( + ds_base = WeatherDataset( datastore=datastore, split="train", ar_steps=ar_steps, num_past_forcing_steps=0, num_future_forcing_steps=0, ) + sampler: DistributedSampler | None + ds: torch.utils.data.Dataset if distributed: ds = PaddedWeatherDataset( - ds, + ds_base, world_size, batch_size, ) @@ -269,6 +292,7 @@ def main( ds, num_replicas=world_size, rank=rank, shuffle=False ) else: + ds = ds_base sampler = None loader = torch.utils.data.DataLoader( ds, @@ -302,33 +326,33 @@ def main( flux_squares.append(torch.mean(flux_batch**2).cpu()) # (,) if distributed and world_size > 1: - means_gathered, squares_gathered = [None] * world_size, [ - None - ] * world_size - flux_means_gathered, flux_squares_gathered = ( - [None] * world_size, - [None] * world_size, - ) + means_gathered: list[Any] = [None] * world_size + squares_gathered: list[Any] = [None] * world_size + flux_means_gathered: list[Any] = [None] * world_size + flux_squares_gathered: list[Any] = [None] * world_size dist.all_gather_object(means_gathered, torch.cat(means, dim=0)) dist.all_gather_object(squares_gathered, torch.cat(squares, dim=0)) dist.all_gather_object(flux_means_gathered, flux_means) dist.all_gather_object(flux_squares_gathered, flux_squares) if rank == 0: - means_gathered, squares_gathered = ( - torch.cat(means_gathered, dim=0), - torch.cat(squares_gathered, dim=0), + means_gathered_tensor = torch.cat( + cast(list[torch.Tensor], means_gathered), dim=0 + ) + squares_gathered_tensor = torch.cat( + cast(list[torch.Tensor], squares_gathered), dim=0 ) + assert isinstance(ds, PaddedWeatherDataset) original_indices = ds.get_original_indices() means, squares = ( - [means_gathered[i] for i in original_indices], - [squares_gathered[i] for i in original_indices], + [means_gathered_tensor[i] for i in original_indices], + [squares_gathered_tensor[i] for i in original_indices], ) flux_means = [ torch.cat( [ - torch.stack(rank_flux) + torch.stack(cast(list[torch.Tensor], rank_flux)) for rank_flux in flux_means_gathered ] ) @@ -336,7 +360,7 @@ def main( flux_squares = [ torch.cat( [ - torch.stack(rank_flux) + torch.stack(cast(list[torch.Tensor], rank_flux)) for rank_flux in flux_squares_gathered ] ) @@ -362,16 +386,18 @@ def main( if rank == 0: print("Computing mean and std.-dev. for one-step differences...") - ds_standard = WeatherDataset( + ds_standard_base = WeatherDataset( datastore=datastore, split="train", ar_steps=ar_steps, num_past_forcing_steps=0, num_future_forcing_steps=0, ) + sampler_standard: DistributedSampler | None + ds_standard: torch.utils.data.Dataset if distributed: ds_standard = PaddedWeatherDataset( - ds_standard, + ds_standard_base, world_size, batch_size, ) @@ -379,6 +405,7 @@ def main( ds_standard, num_replicas=world_size, rank=rank, shuffle=False ) else: + ds_standard = ds_standard_base sampler_standard = None loader_standard = torch.utils.data.DataLoader( ds_standard, @@ -438,10 +465,8 @@ def main( if distributed and world_size > 1: dist.barrier() - diff_means_gathered, diff_squares_gathered = ( - [None] * world_size, - [None] * world_size, - ) + diff_means_gathered: list[Any] = [None] * world_size + diff_squares_gathered: list[Any] = [None] * world_size dist.all_gather_object( diff_means_gathered, torch.cat(diff_means, dim=0) ) @@ -450,13 +475,18 @@ def main( ) if rank == 0: - diff_means_gathered = torch.cat(diff_means_gathered, dim=0) - diff_squares_gathered = torch.cat(diff_squares_gathered, dim=0) + diff_means_gathered_tensor = torch.cat( + cast(list[torch.Tensor], diff_means_gathered), dim=0 + ) + diff_squares_gathered_tensor = torch.cat( + cast(list[torch.Tensor], diff_squares_gathered), dim=0 + ) + assert isinstance(ds_standard, PaddedWeatherDataset) n_original_windows = ( len(ds_standard.get_original_indices()) * time_step_int ) - diff_means = [diff_means_gathered[:n_original_windows]] - diff_squares = [diff_squares_gathered[:n_original_windows]] + diff_means = [diff_means_gathered_tensor[:n_original_windows]] + diff_squares = [diff_squares_gathered_tensor[:n_original_windows]] diff_means = [torch.cat(diff_means, dim=0)] # (B', d_features,) diff_squares = [torch.cat(diff_squares, dim=0)] # (B', d_features,) @@ -468,7 +498,7 @@ def main( dist.destroy_process_group() -def cli(): +def cli() -> None: """Parse CLI arguments and trigger :func:`main`.""" parser = ArgumentParser(description="Training arguments") parser.add_argument( diff --git a/neural_lam/datastore/npyfilesmeps/config.py b/neural_lam/datastore/npyfilesmeps/config.py index b423b4a1..be55dc73 100644 --- a/neural_lam/datastore/npyfilesmeps/config.py +++ b/neural_lam/datastore/npyfilesmeps/config.py @@ -3,7 +3,7 @@ # Standard library from dataclasses import dataclass, field from datetime import timedelta -from typing import Any, Dict, List +from typing import Any # Third-party import dataclass_wizard @@ -24,7 +24,7 @@ class Projection: """ class_name: str - kwargs: Dict[str, Any] + kwargs: dict[str, Any] @dataclass @@ -47,14 +47,14 @@ class Dataset: """ name: str - var_names: List[str] - var_units: List[str] - var_longnames: List[str] + var_names: list[str] + var_units: list[str] + var_longnames: list[str] num_forcing_features: int num_timesteps: int step_length: timedelta num_ensemble_members: int - remove_state_features_with_index: List[int] = field(default_factory=list) + remove_state_features_with_index: list[int] = field(default_factory=list) @dataclass @@ -70,5 +70,5 @@ class NpyDatastoreConfig(dataclass_wizard.YAMLWizard): """ dataset: Dataset - grid_shape_state: List[int] + grid_shape_state: list[int] projection: Projection diff --git a/neural_lam/datastore/npyfilesmeps/store.py b/neural_lam/datastore/npyfilesmeps/store.py index e14bbc74..ef2eed4d 100644 --- a/neural_lam/datastore/npyfilesmeps/store.py +++ b/neural_lam/datastore/npyfilesmeps/store.py @@ -10,7 +10,7 @@ from datetime import timedelta from functools import cached_property from pathlib import Path -from typing import List, Optional +from typing import Any, cast # Third-party import cartopy.crs as ccrs @@ -34,7 +34,11 @@ OPEN_WATER_FILENAME_FORMAT = "wtr_{analysis_time:%Y%m%d%H}.npy" -def _load_np(fp, add_feature_dim, feature_dim_mask=None): +def _load_np( + fp: str | Path, + add_feature_dim: bool, + feature_dim_mask: np.ndarray | None = None, +) -> np.ndarray: """ Load an ``.npy`` file and optionally expand/mask the feature axis. @@ -162,10 +166,18 @@ class NpyFilesDatastoreMEPS(BaseRegularGridDatastore): is_forecast = True + _config_path: Path + _root_path: Path + _config: NpyDatastoreConfig + _num_ensemble_members: int + _num_timesteps: int + _step_length: timedelta + _remove_state_features_with_index: list[int] | None + def __init__( self, - config_path, - ): + config_path: str | Path, + ) -> None: """ Create a new NpyFilesDatastore using the configuration file at the given path. The config file should be a YAML file and will be loaded @@ -182,7 +194,9 @@ def __init__( """ self._config_path = Path(config_path) self._root_path = self._config_path.parent - self._config = NpyDatastoreConfig.from_yaml_file(self._config_path) + self._config = ( # ty: ignore[invalid-assignment] + NpyDatastoreConfig.from_yaml_file(self._config_path) + ) self._num_ensemble_members = self.config.dataset.num_ensemble_members self._num_timesteps = self.config.dataset.num_timesteps @@ -220,7 +234,7 @@ def config(self) -> NpyDatastoreConfig: return self._config def get_dataarray( - self, category: str, split: Optional[str], standardize: bool = False + self, category: str, split: str | None, standardize: bool = False ) -> DataArray: """ Get the data array for the given category and split of data. If the @@ -314,7 +328,9 @@ def get_dataarray( da = da.rename(dict(feature=f"{category}_feature")) # stack the [x, y] dimensions into a `grid_index` dimension - da = self.stack_grid_coords(da) + da_stacked = self.stack_grid_coords(da) + assert isinstance(da_stacked, xr.DataArray) + da = da_stacked # check that we have the right features actual_features = da[f"{category}_feature"].values.tolist() @@ -334,9 +350,9 @@ def get_dataarray( def _get_single_timeseries_dataarray( self, - features: List[str], - split: Optional[str] = None, - member: Optional[int] = None, + features: list[str], + split: str | None = None, + member: int | None = None, ) -> DataArray: """ Get the data array spanning the complete time series for a given set of @@ -347,7 +363,7 @@ def _get_single_timeseries_dataarray( Parameters ---------- - features : List[str] + features : list[str] The list of features to load the data for. For the 'state' category, this should be the result of `self.get_vars_names(category="state")`, for the 'forcing' category @@ -473,9 +489,14 @@ def _get_single_timeseries_dataarray( x = xs[:, 0] # Unique x-coordinates (changes along the first axis) y = ys[0, :] # Unique y-coordinates (changes along the second axis) for d in dims: + coord_values: Any if d == "elapsed_forecast_duration": - coord_values = self.step_length * np.arange(self._num_timesteps) + coord_values = ( + self.step_length # ty: ignore[unsupported-operator] + * np.arange(self._num_timesteps) + ) elif d == "analysis_time": + assert split is not None coord_values = self._get_analysis_times(split=split) elif d == "y": coord_values = y @@ -507,7 +528,7 @@ def _get_single_timeseries_dataarray( # done until the data is actually needed arrays = [ dask.array.from_delayed( - dask.delayed(_load_np)( + dask.delayed(_load_np)( # ty: ignore[call-non-callable] fp=fp, add_feature_dim=add_feature_dim, feature_dim_mask=feature_dim_mask, @@ -536,7 +557,7 @@ def _get_single_timeseries_dataarray( return da - def _get_analysis_times(self, split) -> List[np.datetime64]: + def _get_analysis_times(self, split: str) -> list[np.datetime64]: """Get the analysis times for the given split by parsing the filenames of all the files found for the given split. @@ -547,7 +568,7 @@ def _get_analysis_times(self, split) -> List[np.datetime64]: Returns ------- - List[dt.datetime] + list[dt.datetime] The analysis times for the given split, sorted in ascending order. """ @@ -568,7 +589,9 @@ def _get_analysis_times(self, split) -> List[np.datetime64]: return sorted(times) - def _calc_datetime_forcing_features(self, da_time: xr.DataArray): + def _calc_datetime_forcing_features( + self, da_time: xr.DataArray + ) -> xr.DataArray: """ Compute sinusoidal encodings of hour-of-day and day-of-year. @@ -586,11 +609,14 @@ def _calc_datetime_forcing_features(self, da_time: xr.DataArray): da_year_angle = da_time.dt.dayofyear / 365 * 2 * np.pi da_datetime_forcing = xr.concat( - ( - np.sin(da_hour_angle), - np.cos(da_hour_angle), - np.sin(da_year_angle), - np.cos(da_year_angle), + cast( + list[xr.DataArray], + [ + np.sin(da_hour_angle), + np.cos(da_hour_angle), + np.sin(da_year_angle), + np.cos(da_year_angle), + ], ), dim="feature", ) @@ -604,7 +630,7 @@ def _calc_datetime_forcing_features(self, da_time: xr.DataArray): return da_datetime_forcing - def get_vars_units(self, category: str) -> List[str]: + def get_vars_units(self, category: str) -> list[str]: """Return unit strings for the variables in ``category``.""" if category == "state": return self.config.dataset.var_units @@ -622,7 +648,7 @@ def get_vars_units(self, category: str) -> List[str]: else: raise NotImplementedError(f"Category {category} not supported") - def get_vars_names(self, category: str) -> List[str]: + def get_vars_names(self, category: str) -> list[str]: """Return canonical short names for the variables in ``category``.""" if category == "state": return self.config.dataset.var_names @@ -642,7 +668,7 @@ def get_vars_names(self, category: str) -> List[str]: else: raise NotImplementedError(f"Category {category} not supported") - def get_vars_long_names(self, category: str) -> List[str]: + def get_vars_long_names(self, category: str) -> list[str]: """Return descriptive names for the variables in ``category``.""" if category == "state": return self.config.dataset.var_longnames @@ -742,6 +768,7 @@ def boundary_mask(self) -> xr.DataArray: values, dims=["y", "x"], coords=dict(x=x, y=y), name="boundary_mask" ) da_mask_stacked_xy = self.stack_grid_coords(da_mask).astype(int) + assert isinstance(da_mask_stacked_xy, xr.DataArray) return da_mask_stacked_xy def get_standardization_dataarray(self, category: str) -> xr.Dataset: @@ -766,7 +793,7 @@ def get_standardization_dataarray(self, category: str) -> xr.Dataset: """ - def load_pickled_tensor(fn): + def load_pickled_tensor(fn: str) -> np.ndarray: """Load a serialized tensor from ``static`` and convert to numpy.""" return torch.load( self.root_path / "static" / fn, weights_only=True diff --git a/neural_lam/datastore/plot_example.py b/neural_lam/datastore/plot_example.py index 13f32e57..2cc14b39 100644 --- a/neural_lam/datastore/plot_example.py +++ b/neural_lam/datastore/plot_example.py @@ -1,21 +1,24 @@ """CLI helper to plot slices from datastores for manual inspection.""" # Third-party +import matplotlib.figure import matplotlib.pyplot as plt +import xarray as xr # Local from . import DATASTORES, init_datastore +from .base import BaseRegularGridDatastore def plot_example_from_datastore( - category, - datastore, - col_dim, - split="train", - standardize=True, - selection={}, - index_selection={}, -): + category: str, + datastore: BaseRegularGridDatastore, + col_dim: str, + split: str = "train", + standardize: bool = True, + selection: dict = {}, + index_selection: dict = {}, +) -> matplotlib.figure.Figure: """ Create a plot of the data from the datastore. @@ -47,10 +50,13 @@ def plot_example_from_datastore( Matplotlib figure object. """ da = datastore.get_dataarray(category=category, split=split) + assert da is not None if standardize: da_stats = datastore.get_standardization_dataarray(category=category) da = (da - da_stats[f"{category}_mean"]) / da_stats[f"{category}_std"] - da = datastore.unstack_grid_coords(da) + da_unstacked = datastore.unstack_grid_coords(da) + assert isinstance(da_unstacked, xr.DataArray) + da = da_unstacked if len(selection) > 0: da = da.sel(**selection) @@ -58,10 +64,10 @@ def plot_example_from_datastore( da = da.isel(**index_selection) col = col_dim.format(category=category) - # check that the column dimension exists and that the resulting shape is 2D if col not in da.dims: raise ValueError(f"Column dimension {col} not found in dataarray.") + da_col_item = da.isel({col: 0}).squeeze() if not len(da_col_item.shape) == 2: raise ValueError( @@ -73,7 +79,7 @@ def plot_example_from_datastore( crs = datastore.coords_projection col_wrap = min(4, int(da[col].count())) - g = da.plot( + g = da.plot( # ty: ignore[missing-argument] x="x", y="y", col=col, @@ -94,16 +100,17 @@ def plot_example_from_datastore( # Standard library import argparse - def _parse_dict(arg_str): + def _parse_dict(arg_str: str) -> tuple[str, int | float | str]: """Parse ``key=value`` CLI arguments into typed dictionary entries.""" key, value = arg_str.split("=") + typed_value: int | float | str = value for op in [int, float]: try: - value = op(value) + typed_value = op(value) break except ValueError: pass - return key, value + return key, typed_value parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter @@ -180,6 +187,10 @@ def _parse_dict(arg_str): datastore_kind=datastore_kind, config_path=args.datastore_config_path, ) + # Standard library + from typing import cast + + datastore = cast(BaseRegularGridDatastore, datastore) plot_example_from_datastore( args.category, diff --git a/neural_lam/gnn_layers.py b/neural_lam/gnn_layers.py index 7a92ea76..f61f3029 100644 --- a/neural_lam/gnn_layers.py +++ b/neural_lam/gnn_layers.py @@ -1,7 +1,6 @@ """Interaction Network and PropagationNet GNN layers used by Neural-LAM.""" # Standard library -from typing import Optional, Type, Union # Third-party import torch @@ -27,9 +26,9 @@ def __init__( input_dim: int, update_edges: bool = True, hidden_layers: int = 1, - hidden_dim: Optional[int] = None, - edge_chunk_sizes: Optional[list[int]] = None, - aggr_chunk_sizes: Optional[list[int]] = None, + hidden_dim: int | None = None, + edge_chunk_sizes: list[int] | None = None, + aggr_chunk_sizes: list[int] | None = None, aggr: str = "sum", ) -> None: """ @@ -113,7 +112,7 @@ def forward( send_rep: torch.Tensor, rec_rep: torch.Tensor, edge_rep: torch.Tensor, - ) -> Union[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]: + ) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]: """ Apply the interaction network to update receiver node representations, and optionally edge representations. @@ -177,8 +176,8 @@ def aggregate( self, inputs: torch.Tensor, index: torch.Tensor, - ptr: Optional[torch.Tensor], - dim_size: Optional[int], + ptr: torch.Tensor | None, + dim_size: int | None, ) -> tuple[torch.Tensor, torch.Tensor]: """ Overridden aggregation function to: @@ -205,9 +204,9 @@ def __init__( input_dim: int, update_edges: bool = True, hidden_layers: int = 1, - hidden_dim: Optional[int] = None, - edge_chunk_sizes: Optional[list[int]] = None, - aggr_chunk_sizes: Optional[list[int]] = None, + hidden_dim: int | None = None, + edge_chunk_sizes: list[int] | None = None, + aggr_chunk_sizes: list[int] | None = None, aggr: str = "sum", ) -> None: """Initialise the :class:`PropagationNet` layer. @@ -256,7 +255,7 @@ def message( } -def get_gnn_class(gnn_type: str) -> Type[pyg.nn.MessagePassing]: +def get_gnn_class(gnn_type: str) -> type[pyg.nn.MessagePassing]: """ Look up a GNN class by name. diff --git a/neural_lam/metrics.py b/neural_lam/metrics.py index 1eb1d526..c332f011 100644 --- a/neural_lam/metrics.py +++ b/neural_lam/metrics.py @@ -2,7 +2,6 @@ # Standard library from collections.abc import Callable -from typing import Optional # Third-party import torch @@ -37,7 +36,7 @@ def get_metric(metric_name: str) -> Callable[..., torch.Tensor]: def mask_and_reduce_metric( metric_entry_vals: torch.Tensor, - mask: Optional[torch.Tensor], + mask: torch.Tensor | None, average_grid: bool, sum_vars: bool, ) -> torch.Tensor: @@ -89,7 +88,7 @@ def wmse( pred: torch.Tensor, target: torch.Tensor, pred_std: torch.Tensor, - mask: Optional[torch.Tensor] = None, + mask: torch.Tensor | None = None, average_grid: bool = True, sum_vars: bool = True, ) -> torch.Tensor: @@ -142,7 +141,7 @@ def mse( pred: torch.Tensor, target: torch.Tensor, pred_std: torch.Tensor, - mask: Optional[torch.Tensor] = None, + mask: torch.Tensor | None = None, average_grid: bool = True, sum_vars: bool = True, ) -> torch.Tensor: @@ -187,7 +186,7 @@ def wmae( pred: torch.Tensor, target: torch.Tensor, pred_std: torch.Tensor, - mask: Optional[torch.Tensor] = None, + mask: torch.Tensor | None = None, average_grid: bool = True, sum_vars: bool = True, ) -> torch.Tensor: @@ -240,7 +239,7 @@ def mae( pred: torch.Tensor, target: torch.Tensor, pred_std: torch.Tensor, - mask: Optional[torch.Tensor] = None, + mask: torch.Tensor | None = None, average_grid: bool = True, sum_vars: bool = True, ) -> torch.Tensor: @@ -285,7 +284,7 @@ def nll( pred: torch.Tensor, target: torch.Tensor, pred_std: torch.Tensor, - mask: Optional[torch.Tensor] = None, + mask: torch.Tensor | None = None, average_grid: bool = True, sum_vars: bool = True, ) -> torch.Tensor: @@ -334,7 +333,7 @@ def crps_gauss( pred: torch.Tensor, target: torch.Tensor, pred_std: torch.Tensor, - mask: Optional[torch.Tensor] = None, + mask: torch.Tensor | None = None, average_grid: bool = True, sum_vars: bool = True, ) -> torch.Tensor: diff --git a/neural_lam/models/forecasters/autoregressive.py b/neural_lam/models/forecasters/autoregressive.py index a8135f62..7167c64c 100644 --- a/neural_lam/models/forecasters/autoregressive.py +++ b/neural_lam/models/forecasters/autoregressive.py @@ -17,6 +17,9 @@ class ARForecaster(Forecaster): unroll a forecast. Makes use of a StepPredictor at each AR step. """ + boundary_mask: torch.Tensor + interior_mask: torch.Tensor + def __init__( self, predictor: StepPredictor, datastore: BaseDatastore ) -> None: diff --git a/neural_lam/models/module.py b/neural_lam/models/module.py index b097d417..d785c3e3 100644 --- a/neural_lam/models/module.py +++ b/neural_lam/models/module.py @@ -19,7 +19,7 @@ # Local from .. import metrics, vis from ..config import NeuralLAMConfig -from ..datastore import BaseDatastore +from ..datastore.base import BaseRegularGridDatastore from ..loss_weighting import get_state_feature_weighting from ..weather_dataset import WeatherDataset from .forecasters.base import Forecaster @@ -33,11 +33,20 @@ class ForecasterModule(pl.LightningModule): # pylint: disable=arguments-differ + interior_mask_bool: torch.Tensor + per_var_std: torch.Tensor | None + state_mean: torch.Tensor + state_std: torch.Tensor + forcing_mean: torch.Tensor | None + forcing_std: torch.Tensor | None + forcing_mean_tiled: torch.Tensor | None + forcing_std_tiled: torch.Tensor | None + def __init__( self, forecaster: Forecaster, config: NeuralLAMConfig, - datastore: BaseDatastore, + datastore: BaseRegularGridDatastore, loss: str = "wmse", lr: float = 1e-3, restore_opt: bool = False, @@ -47,8 +56,8 @@ def __init__( train_steps_to_log: list[int] | None = None, metrics_watch: list[str] | None = None, var_leads_metrics_watch: dict[int, list[int]] | None = None, - args=None, - ): + args: Any | None = None, + ) -> None: """ Initialize the ForecasterModule. @@ -275,13 +284,13 @@ def _create_dataarray_from_tensor( The resulting xarray DataArray. """ weather_dataset = WeatherDataset(datastore=self.datastore, split=split) - time = np.array(time.cpu(), dtype="datetime64[ns]") + time_np = np.array(time.cpu(), dtype="datetime64[ns]") da = weather_dataset.create_dataarray_from_tensor( - tensor=tensor, time=time, category=category + tensor=tensor, time=time_np, category=category ) return da - def configure_optimizers(self): + def configure_optimizers(self) -> torch.optim.Optimizer: """ Configure the optimizers and learning rate schedulers. @@ -290,13 +299,14 @@ def configure_optimizers(self): torch.optim.Optimizer The configured optimizer. """ - opt = torch.optim.AdamW( - self.parameters(), lr=self.hparams.lr, betas=(0.9, 0.95) - ) + lr = self.hparams.lr # ty: ignore[unresolved-attribute] + opt = torch.optim.AdamW(self.parameters(), lr=lr, betas=(0.9, 0.95)) return opt @staticmethod - def _safe_std(std_values, eps, category): + def _safe_std( + std_values: np.ndarray | torch.Tensor, eps: float, category: str + ) -> torch.Tensor: """Build a float32 std tensor, clamping near-zero values to `eps`. Mirrors the previous CPU-side WeatherDataset behavior: features with @@ -313,7 +323,11 @@ def _safe_std(std_values, eps, category): ) return torch.clamp(std, min=eps) - def on_after_batch_transfer(self, batch, dataloader_idx): + def on_after_batch_transfer( + self, + batch: tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor], + dataloader_idx: int, + ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: """Standardize a batch on-device after transfer to the accelerator. Lightning calls this for every train/val/test/predict batch. @@ -326,6 +340,9 @@ def on_after_batch_transfer(self, batch, dataloader_idx): target_states = (target_states - self.state_mean) / self.state_std if forcing.shape[-1] > 0: + assert ( + self.forcing_mean is not None and self.forcing_std is not None + ) if self.forcing_mean_tiled is None: # Forcing is (..., num_forcing_vars * window_size). # WeatherDataset stacks (forcing_feature, window) @@ -339,13 +356,20 @@ def on_after_batch_transfer(self, batch, dataloader_idx): self.forcing_std_tiled = self.forcing_std.repeat_interleave( window_size ) + assert ( + self.forcing_mean_tiled is not None + and self.forcing_std_tiled is not None + ) forcing = ( forcing - self.forcing_mean_tiled ) / self.forcing_std_tiled return init_states, target_states, forcing, batch_times - def common_step(self, batch): + def common_step( + self, + batch: tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor], + ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor | None, torch.Tensor]: """ Perform a common prediction step for training, validation, and testing. @@ -367,7 +391,10 @@ def common_step(self, batch): ) return prediction, target_states, pred_std, batch_times - def training_step(self, batch): + def training_step( + self, + batch: tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor], + ) -> torch.Tensor: """ Perform a single training step. @@ -389,7 +416,7 @@ def training_step(self, batch): return batch_loss - def all_gather_cat(self, tensor_to_gather): + def all_gather_cat(self, tensor_to_gather: torch.Tensor) -> torch.Tensor: """ Gather tensors from all GPUs and concatenate them. @@ -404,6 +431,7 @@ def all_gather_cat(self, tensor_to_gather): The concatenated tensor from all processes. """ gathered = self.all_gather(tensor_to_gather) + assert isinstance(gathered, torch.Tensor) # all_gather adds dim 0 only on multi-device; on single # device it returns the same tensor unchanged. if gathered.dim() > tensor_to_gather.dim(): @@ -515,7 +543,11 @@ def _log_step_loss( batch_size=batch_size, ) - def validation_step(self, batch, batch_idx): + def validation_step( + self, + batch: tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor], + batch_idx: int, + ) -> None: """ Perform a single validation step. @@ -543,15 +575,21 @@ def validation_step(self, batch, batch_idx): ) self.val_metrics["mse"].append(entry_mses) - def on_validation_epoch_end(self): + def on_validation_epoch_end(self) -> None: """ Perform actions at the end of the validation epoch. Aggregates and plots validation metrics. """ self.aggregate_and_plot_metrics(self.val_metrics, prefix="val") - if self.trainer.is_global_zero and self.hparams.metrics_watch: - unmatched = set(self.hparams.metrics_watch) - self.matched_metrics + if ( + self.trainer.is_global_zero + and self.hparams.metrics_watch # ty: ignore[unresolved-attribute] + ): + metrics_watch = ( + self.hparams.metrics_watch # ty: ignore[unresolved-attribute] + ) + unmatched = set(metrics_watch) - self.matched_metrics if unmatched: warnings.warn( "The following metrics in --metrics_watch " @@ -566,7 +604,11 @@ def on_validation_epoch_end(self): metric_list.clear() # pylint: disable-next=unused-argument - def test_step(self, batch, batch_idx): + def test_step( + self, + batch: tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor], + batch_idx: int, + ) -> None: """ Perform a single test step. @@ -594,7 +636,7 @@ def test_step(self, batch, batch_idx): hparams = self.hparams val_steps_to_log = ( - hparams.val_steps_to_log # type: ignore[attr-defined] + hparams.val_steps_to_log # ty: ignore[unresolved-attribute] ) for metric_name in ("mse", "mae"): @@ -625,19 +667,25 @@ def test_step(self, batch, batch_idx): self.trainer.is_global_zero and self.plotted_examples < self.n_example_pred ): - n_additional_examples = min( + n_examples = min( prediction.shape[0], self.n_example_pred - self.plotted_examples, ) self.plot_examples( batch, - n_additional_examples, + n_examples, prediction=prediction, split="test", ) - def plot_examples(self, batch, n_examples, split, prediction): + def plot_examples( + self, + batch: tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor], + n_examples: int, + split: str, + prediction: torch.Tensor, + ) -> None: """ Plot example predictions. @@ -713,7 +761,7 @@ def plot_examples(self, batch, n_examples, split, prediction): if self.create_gif: plot_dir_path = os.path.join( - self.logger.save_dir, + self.logger.save_dir, # ty: ignore[unresolved-attribute] f"example_plots_{example_i}", ) os.makedirs(plot_dir_path, exist_ok=True) @@ -755,7 +803,9 @@ def plot_examples(self, batch, n_examples, split, prediction): key = f"{var_name}_example" if hasattr(self.logger, "log_image"): - self.logger.log_image(key=key, images=[fig], step=t_i) + self.logger.log_image( # ty: ignore[call-non-callable] + key=key, images=[fig], step=t_i + ) else: warnings.warn( f"{self.logger} does not support image logging." @@ -795,19 +845,21 @@ def plot_examples(self, batch, n_examples, split, prediction): torch.save( pred_slice.cpu(), os.path.join( - self.logger.save_dir, + self.logger.save_dir, # ty: ignore[unresolved-attribute] f"example_pred_{self.plotted_examples}.pt", ), ) torch.save( target_slice.cpu(), os.path.join( - self.logger.save_dir, + self.logger.save_dir, # ty: ignore[unresolved-attribute] f"example_target_{self.plotted_examples}.pt", ), ) - def create_metric_log_dict(self, metric_tensor, prefix, metric_name): + def create_metric_log_dict( + self, metric_tensor: torch.Tensor, prefix: str, metric_name: str + ) -> dict[str, Any]: """ Create a dictionary of metrics to log. @@ -825,7 +877,7 @@ def create_metric_log_dict(self, metric_tensor, prefix, metric_name): dict Dictionary of logged metrics and figures. """ - log_dict = {} + log_dict: dict[str, Any] = {} metric_fig = vis.plot_error_heatmap( errors=metric_tensor, datastore=self.datastore, @@ -835,21 +887,31 @@ def create_metric_log_dict(self, metric_tensor, prefix, metric_name): if prefix == "test": metric_fig.savefig( - os.path.join(self.logger.save_dir, f"{full_log_name}.pdf") + os.path.join( + self.logger.save_dir, # ty: ignore[unresolved-attribute] + f"{full_log_name}.pdf", + ) ) np.savetxt( - os.path.join(self.logger.save_dir, f"{full_log_name}.csv"), + os.path.join( + self.logger.save_dir, # ty: ignore[unresolved-attribute] + f"{full_log_name}.csv", + ), metric_tensor.cpu().numpy(), delimiter=",", ) var_names = self.datastore.get_vars_names(category="state") - if full_log_name in self.hparams.metrics_watch: + hparams = self.hparams + metrics_watch = ( + hparams.metrics_watch # ty: ignore[unresolved-attribute] + ) + var_leads_metrics_watch = ( + hparams.var_leads_metrics_watch # ty: ignore[unresolved-attribute] + ) + if full_log_name in metrics_watch: self.matched_metrics.add(full_log_name) - for ( - var_i, - timesteps, - ) in self.hparams.var_leads_metrics_watch.items(): + for var_i, timesteps in var_leads_metrics_watch.items(): var_name = var_names[var_i] for step in timesteps: key = f"{full_log_name}_{var_name}_step_{step}" @@ -857,7 +919,9 @@ def create_metric_log_dict(self, metric_tensor, prefix, metric_name): return log_dict - def aggregate_and_plot_metrics(self, metrics_dict, prefix): + def aggregate_and_plot_metrics( + self, metrics_dict: dict[str, list[torch.Tensor]], prefix: str + ) -> None: """ Aggregate metrics from all GPUs and plot them. @@ -920,11 +984,13 @@ def aggregate_and_plot_metrics(self, metrics_dict, prefix): key = f"{key}-{current_epoch}" if hasattr(self.logger, "log_image"): - self.logger.log_image(key=key, images=[figure]) + self.logger.log_image( # ty: ignore[call-non-callable] + key=key, images=[figure] + ) plt.close("all") - def on_test_epoch_end(self): + def on_test_epoch_end(self) -> None: """ Perform actions at the end of the test epoch. Aggregates and plots test metrics and spatial loss maps. @@ -936,6 +1002,13 @@ def on_test_epoch_end(self): ) if self.trainer.is_global_zero: mean_spatial_loss = torch.mean(spatial_loss_tensor, dim=0) + hparams = self.hparams + val_steps_to_log = ( + hparams.val_steps_to_log # ty: ignore[unresolved-attribute] + ) + logger_save_dir = ( + self.logger.save_dir # ty: ignore[unresolved-attribute] + ) loss_map_figs = [ vis.plot_spatial_error( @@ -945,7 +1018,8 @@ def on_test_epoch_end(self): f"({(self.time_step_int * t_i)} {self.time_step_unit})", ) for t_i, loss_map in zip( - self.hparams.val_steps_to_log, mean_spatial_loss + val_steps_to_log, + mean_spatial_loss, ) ] @@ -954,30 +1028,37 @@ def on_test_epoch_end(self): if not isinstance(self.logger, pl.loggers.WandbLogger): key = f"{key}_{i}" if hasattr(self.logger, "log_image"): - self.logger.log_image(key=key, images=[fig]) + self.logger.log_image( # ty: ignore[call-non-callable] + key=key, images=[fig] + ) pdf_loss_map_figs = [ vis.plot_spatial_error(error=loss_map, datastore=self.datastore) for loss_map in mean_spatial_loss ] pdf_loss_maps_dir = os.path.join( - self.logger.save_dir, "spatial_loss_maps" + logger_save_dir, "spatial_loss_maps" ) os.makedirs(pdf_loss_maps_dir, exist_ok=True) for t_i, fig in zip( - self.hparams.val_steps_to_log, pdf_loss_map_figs + val_steps_to_log, + pdf_loss_map_figs, ): fig.savefig(os.path.join(pdf_loss_maps_dir, f"loss_t{t_i}.pdf")) torch.save( mean_spatial_loss.cpu(), - os.path.join(self.logger.save_dir, "mean_spatial_loss.pt"), + os.path.join( + logger_save_dir, + "mean_spatial_loss.pt", + ), ) - if self.hparams.metrics_watch: - unmatched = ( - set(self.hparams.metrics_watch) - self.matched_metrics - ) + metrics_watch = ( + hparams.metrics_watch # ty: ignore[unresolved-attribute] + ) + if metrics_watch: + unmatched = set(metrics_watch) - self.matched_metrics if unmatched: warnings.warn( "The following metrics in --metrics_watch " @@ -1001,7 +1082,7 @@ def on_test_epoch_end(self): # otherwise stay permanently False). self.plotted_examples = 0 - def on_load_checkpoint(self, checkpoint): + def on_load_checkpoint(self, checkpoint: dict[str, Any]) -> None: """ Perform actions when loading a checkpoint. Handles backward compatibility for older checkpoints. diff --git a/neural_lam/models/step_predictors/base.py b/neural_lam/models/step_predictors/base.py index daf8b0e6..6efdaacf 100644 --- a/neural_lam/models/step_predictors/base.py +++ b/neural_lam/models/step_predictors/base.py @@ -18,6 +18,19 @@ class StepPredictor(nn.Module, ABC): time steps plus forcing into a prediction of the next state. """ + grid_static_features: torch.Tensor + state_mean: torch.Tensor + state_std: torch.Tensor + + # Registered buffers for clamping + sigmoid_lower_lims: torch.Tensor + sigmoid_upper_lims: torch.Tensor + softplus_lower_lims: torch.Tensor + softplus_upper_lims: torch.Tensor + clamp_lower_upper_idx: torch.Tensor + clamp_lower_idx: torch.Tensor + clamp_upper_idx: torch.Tensor + def __init__( self, datastore: BaseDatastore, diff --git a/neural_lam/models/step_predictors/graph/base.py b/neural_lam/models/step_predictors/graph/base.py index 449f4bb6..c62312c6 100644 --- a/neural_lam/models/step_predictors/graph/base.py +++ b/neural_lam/models/step_predictors/graph/base.py @@ -18,6 +18,16 @@ class BaseGraphModel(StepPredictor): the encode-process-decode idea. """ + diff_mean: torch.Tensor + diff_std: torch.Tensor + g2m_features: torch.Tensor + m2g_features: torch.Tensor + g2m_edge_index: torch.Tensor + m2g_edge_index: torch.Tensor + mesh_static_features: torch.Tensor | list[torch.Tensor] + m2m_features: torch.Tensor | list[torch.Tensor] + m2m_edge_index: torch.Tensor | list[torch.Tensor] + def __init__( self, datastore: BaseDatastore, diff --git a/neural_lam/models/step_predictors/graph/graph_lam.py b/neural_lam/models/step_predictors/graph/graph_lam.py index fdb12a12..3aa77832 100644 --- a/neural_lam/models/step_predictors/graph/graph_lam.py +++ b/neural_lam/models/step_predictors/graph/graph_lam.py @@ -21,6 +21,10 @@ class GraphLAM(BaseGraphModel): Oskarsson et al. (2023). """ + mesh_static_features: torch.Tensor + m2m_features: torch.Tensor + m2m_edge_index: torch.Tensor + def __init__( self, datastore: BaseDatastore, @@ -36,6 +40,7 @@ def __init__( output_clamping_upper: dict[str, float] | None = None, g2m_gnn_type: str = "InteractionNet", m2g_gnn_type: str = "InteractionNet", + **_kwargs: object, ) -> None: """ Initialize the GraphLAM model. diff --git a/neural_lam/models/step_predictors/graph/hi_lam.py b/neural_lam/models/step_predictors/graph/hi_lam.py index ee3eda8b..d01b56ac 100644 --- a/neural_lam/models/step_predictors/graph/hi_lam.py +++ b/neural_lam/models/step_predictors/graph/hi_lam.py @@ -5,6 +5,7 @@ # Standard library # Third-party +import torch from torch import nn # Local @@ -37,7 +38,7 @@ def __init__( m2g_gnn_type: str = "InteractionNet", mesh_up_gnn_type: str = "InteractionNet", mesh_down_gnn_type: str = "InteractionNet", - ): + ) -> None: """ Initialize the HiLAM model. @@ -100,7 +101,7 @@ def __init__( [self.make_same_gnns() for _ in range(processor_layers)] ) # Nested lists (proc_steps, num_levels) - def make_same_gnns(self): + def make_same_gnns(self) -> nn.ModuleList: """ Make intra-level GNNs. @@ -120,7 +121,7 @@ def make_same_gnns(self): ] ) - def make_up_gnns(self): + def make_up_gnns(self) -> nn.ModuleList: """ Make GNNs for processing steps up through the hierarchy. @@ -141,7 +142,7 @@ def make_up_gnns(self): ] ) - def make_down_gnns(self): + def make_down_gnns(self) -> nn.ModuleList: """ Make GNNs for processing steps down through the hierarchy. @@ -164,12 +165,12 @@ def make_down_gnns(self): def mesh_down_step( self, - mesh_rep_levels, - mesh_same_rep, - mesh_down_rep, - down_gnns, - same_gnns, - ): + mesh_rep_levels: list[torch.Tensor], + mesh_same_rep: list[torch.Tensor], + mesh_down_rep: list[torch.Tensor], + down_gnns: nn.ModuleList, + same_gnns: nn.ModuleList, + ) -> tuple[list[torch.Tensor], list[torch.Tensor], list[torch.Tensor]]: """ Run the downward pass of vertical processing, alternating between down-edges and same-level edges from the top to the bottom level. @@ -234,8 +235,13 @@ def mesh_down_step( return mesh_rep_levels, mesh_same_rep, mesh_down_rep def mesh_up_step( - self, mesh_rep_levels, mesh_same_rep, mesh_up_rep, up_gnns, same_gnns - ): + self, + mesh_rep_levels: list[torch.Tensor], + mesh_same_rep: list[torch.Tensor], + mesh_up_rep: list[torch.Tensor], + up_gnns: nn.ModuleList, + same_gnns: nn.ModuleList, + ) -> tuple[list[torch.Tensor], list[torch.Tensor], list[torch.Tensor]]: """ Run the upward pass of vertical processing, alternating between up-edges and same-level edges from the bottom to the top level. @@ -300,8 +306,17 @@ def mesh_up_step( return mesh_rep_levels, mesh_same_rep, mesh_up_rep def hi_processor_step( - self, mesh_rep_levels, mesh_same_rep, mesh_up_rep, mesh_down_rep - ): + self, + mesh_rep_levels: list[torch.Tensor], + mesh_same_rep: list[torch.Tensor], + mesh_up_rep: list[torch.Tensor], + mesh_down_rep: list[torch.Tensor], + ) -> tuple[ + list[torch.Tensor], + list[torch.Tensor], + list[torch.Tensor], + list[torch.Tensor], + ]: """ Run all processor steps (down then up at each layer depth) over the hierarchical mesh. @@ -337,6 +352,11 @@ def hi_processor_step( self.mesh_up_gnns, self.mesh_up_same_gnns, ): + assert isinstance(down_gnns, nn.ModuleList) + assert isinstance(down_same_gnns, nn.ModuleList) + assert isinstance(up_gnns, nn.ModuleList) + assert isinstance(up_same_gnns, nn.ModuleList) + # Down mesh_rep_levels, mesh_same_rep, mesh_down_rep = self.mesh_down_step( mesh_rep_levels, diff --git a/neural_lam/models/step_predictors/graph/hi_lam_parallel.py b/neural_lam/models/step_predictors/graph/hi_lam_parallel.py index da7a644a..372d2484 100644 --- a/neural_lam/models/step_predictors/graph/hi_lam_parallel.py +++ b/neural_lam/models/step_predictors/graph/hi_lam_parallel.py @@ -2,8 +2,6 @@ Parallel hierarchical graph-based LAM model. """ -# Standard library - # Third-party import torch import torch_geometric as pyg @@ -40,7 +38,7 @@ def __init__( m2g_gnn_type: str = "InteractionNet", mesh_up_gnn_type: str = "InteractionNet", mesh_down_gnn_type: str = "InteractionNet", - ): + ) -> None: """ Initialize the HiLAMParallel model. @@ -145,8 +143,17 @@ def __init__( ) def hi_processor_step( - self, mesh_rep_levels, mesh_same_rep, mesh_up_rep, mesh_down_rep - ): + self, + mesh_rep_levels: list[torch.Tensor], + mesh_same_rep: list[torch.Tensor], + mesh_up_rep: list[torch.Tensor], + mesh_down_rep: list[torch.Tensor], + ) -> tuple[ + list[torch.Tensor], + list[torch.Tensor], + list[torch.Tensor], + list[torch.Tensor], + ]: """ Run all processor steps in parallel across all edge types and hierarchy levels. @@ -182,7 +189,7 @@ def hi_processor_step( mesh_rep_levels, dim=1 ) # (B, num_mesh_nodes, hidden_dim) mesh_edge_rep = torch.cat( - mesh_same_rep + mesh_up_rep + mesh_down_rep, axis=1 + mesh_same_rep + mesh_up_rep + mesh_down_rep, dim=1 ) # (B, num_edges, hidden_dim) # Here, update mesh_*_rep and mesh_rep @@ -196,13 +203,15 @@ def hi_processor_step( mesh_edge_rep, self.edge_split_sections, dim=1 ) - mesh_same_rep = mesh_edge_rep_sections[: self.num_levels] - mesh_up_rep = mesh_edge_rep_sections[ - self.num_levels : self.num_levels + (self.num_levels - 1) - ] - mesh_down_rep = mesh_edge_rep_sections[ - self.num_levels + (self.num_levels - 1) : - ] # Last are down edges + mesh_same_rep = list(mesh_edge_rep_sections[: self.num_levels]) + mesh_up_rep = list( + mesh_edge_rep_sections[ + self.num_levels : self.num_levels + (self.num_levels - 1) + ] + ) + mesh_down_rep = list( + mesh_edge_rep_sections[self.num_levels + (self.num_levels - 1) :] + ) # Last are down edges # TODO: We return all, even though only down edges really are used # later diff --git a/neural_lam/models/step_predictors/graph/hierarchical.py b/neural_lam/models/step_predictors/graph/hierarchical.py index 8baa99b5..c42e9dab 100644 --- a/neural_lam/models/step_predictors/graph/hierarchical.py +++ b/neural_lam/models/step_predictors/graph/hierarchical.py @@ -3,6 +3,7 @@ # Standard library # Third-party +import torch from torch import nn # Local @@ -17,6 +18,15 @@ class BaseHiGraphModel(BaseGraphModel): Base class for hierarchical graph models. """ + # Buffers or graph features that are lists of tensors in hierarchical models + mesh_static_features: list[torch.Tensor] + m2m_features: list[torch.Tensor] + mesh_up_features: list[torch.Tensor] + mesh_down_features: list[torch.Tensor] + m2m_edge_index: list[torch.Tensor] + mesh_up_edge_index: list[torch.Tensor] + mesh_down_edge_index: list[torch.Tensor] + def __init__( self, datastore: BaseDatastore, @@ -34,7 +44,7 @@ def __init__( m2g_gnn_type: str = "InteractionNet", mesh_up_gnn_type: str = "InteractionNet", mesh_down_gnn_type: str = "InteractionNet", - ): + ) -> None: """Extend :class:`BaseGraphModel` with hierarchical mesh structures.""" super().__init__( datastore=datastore, @@ -140,7 +150,7 @@ def __init__( ] ) - def get_num_mesh(self): + def get_num_mesh(self) -> tuple[int, int]: """ Compute mesh node counts used for encoding and decoding. @@ -158,7 +168,7 @@ def get_num_mesh(self): ) return num_mesh_nodes, num_mesh_nodes_ignore - def embedd_mesh_nodes(self): + def embedd_mesh_nodes(self) -> torch.Tensor: """ Embed static mesh node features for the bottom level only; remaining levels are embedded at the start of ``process_step``. @@ -173,7 +183,7 @@ def embedd_mesh_nodes(self): """ return self.mesh_embedders[0](self.mesh_static_features[0]) - def process_step(self, mesh_rep): + def process_step(self, mesh_rep: torch.Tensor) -> torch.Tensor: """ Process the mesh representation across all hierarchy levels, implementing the full init-process-readout cycle. @@ -282,8 +292,17 @@ def process_step(self, mesh_rep): return mesh_rep_levels[0] # (B, num_mesh_nodes[0], hidden_dim) def hi_processor_step( - self, mesh_rep_levels, mesh_same_rep, mesh_up_rep, mesh_down_rep - ): + self, + mesh_rep_levels: list[torch.Tensor], + mesh_same_rep: list[torch.Tensor], + mesh_up_rep: list[torch.Tensor], + mesh_down_rep: list[torch.Tensor], + ) -> tuple[ + list[torch.Tensor], + list[torch.Tensor], + list[torch.Tensor], + list[torch.Tensor], + ]: """ Internal processor step between mesh init and read-out. diff --git a/neural_lam/plot_graph.py b/neural_lam/plot_graph.py index 2b347e8c..8351cba0 100644 --- a/neural_lam/plot_graph.py +++ b/neural_lam/plot_graph.py @@ -3,7 +3,7 @@ # Standard library import os from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser -from typing import Any, Optional +from typing import Any # Third-party import numpy as np @@ -24,7 +24,7 @@ def plot_graph( hierarchical: bool, graph_ldict: dict[str, Any], show_axis: bool = False, - save: Optional[str] = None, + save: str | None = None, ) -> go.Figure: """Build a 3D plotly figure of the graph structure. diff --git a/neural_lam/train_model.py b/neural_lam/train_model.py index 2a9775c9..0fdc0933 100644 --- a/neural_lam/train_model.py +++ b/neural_lam/train_model.py @@ -6,7 +6,8 @@ import random import shutil import time -from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser +from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser, Namespace +from typing import Any # Third-party # for logging the model: @@ -17,16 +18,52 @@ # Local from . import utils -from .config import load_config_and_datastore +from .config import NeuralLAMConfig, load_config_and_datastore +from .datastore.base import BaseDatastore from .gnn_layers import GNN_TYPES from .models import MODELS, ARForecaster, ForecasterModule from .weather_dataset import WeatherDataModule +def build_predictor( + predictor_class: type, + args: Namespace, + config: NeuralLAMConfig, + datastore: BaseDatastore, +) -> Any: + """ + Instantiate a step predictor with explicit GNN kwargs for its + model family. + """ + kwargs = { + "datastore": datastore, + "graph_name": args.graph, + "hidden_dim": args.hidden_dim, + "hidden_layers": args.hidden_layers, + "processor_layers": args.processor_layers, + "mesh_aggr": args.mesh_aggr, + "num_past_forcing_steps": args.num_past_forcing_steps, + "num_future_forcing_steps": args.num_future_forcing_steps, + "output_std": args.output_std, + "output_clamping_lower": config.training.output_clamping.lower, + "output_clamping_upper": config.training.output_clamping.upper, + "g2m_gnn_type": getattr(args, "g2m_gnn_type", "InteractionNet"), + "m2g_gnn_type": getattr(args, "m2g_gnn_type", "InteractionNet"), + } + if getattr(args, "model", None) in ("hi_lam", "hi_lam_parallel"): + kwargs["mesh_up_gnn_type"] = getattr( + args, "mesh_up_gnn_type", "InteractionNet" + ) + kwargs["mesh_down_gnn_type"] = getattr( + args, "mesh_down_gnn_type", "InteractionNet" + ) + return predictor_class(**kwargs) + + class AdaptiveHelpFormatter(ArgumentDefaultsHelpFormatter): """``--help`` formatter that scales the column width to the terminal.""" - def __init__(self, prog): + def __init__(self, prog: str) -> None: """Pick a help-column width based on the current terminal size.""" terminal_width = shutil.get_terminal_size(fallback=(100, 20)).columns width = max(80, min(terminal_width, 120)) @@ -38,7 +75,11 @@ def __init__(self, prog): ) -def load_forecaster_module_from_checkpoint(ckpt_path, config, datastore): +def load_forecaster_module_from_checkpoint( + ckpt_path: str, + config: NeuralLAMConfig, + datastore: BaseDatastore, +) -> ForecasterModule: """ Reconstruct a ForecasterModule from a checkpoint without requiring the caller to know the original architecture kwargs. @@ -50,19 +91,7 @@ def load_forecaster_module_from_checkpoint(ckpt_path, config, datastore): ckpt = torch.load(ckpt_path, weights_only=False) args = ckpt["hyper_parameters"]["args"] predictor_class = MODELS[args.model] - predictor = predictor_class( - datastore=datastore, - graph_name=args.graph, - hidden_dim=args.hidden_dim, - hidden_layers=args.hidden_layers, - processor_layers=args.processor_layers, - mesh_aggr=args.mesh_aggr, - num_past_forcing_steps=args.num_past_forcing_steps, - num_future_forcing_steps=args.num_future_forcing_steps, - output_std=args.output_std, - output_clamping_lower=config.training.output_clamping.lower, - output_clamping_upper=config.training.output_clamping.upper, - ) + predictor = build_predictor(predictor_class, args, config, datastore) forecaster = ARForecaster(predictor, datastore) return ForecasterModule.load_from_checkpoint( ckpt_path, @@ -73,7 +102,7 @@ def load_forecaster_module_from_checkpoint(ckpt_path, config, datastore): @logger.catch -def main(input_args=None): +def main(input_args: list[str] | None = None) -> None: """Main function for training and evaluating models.""" parser = ArgumentParser( description="Train or evaluate MLWP models for LAM", @@ -446,6 +475,7 @@ def main(input_args=None): device_name = "cpu" # Set devices to use + devices: str | list[int] if args.devices == ["auto"]: devices = "auto" else: @@ -457,23 +487,7 @@ def main(input_args=None): # Build predictor and forecaster externally, then inject into # ForecasterModule predictor_class = MODELS[args.model] - predictor = predictor_class( - datastore=datastore, - graph_name=args.graph, - hidden_dim=args.hidden_dim, - hidden_layers=args.hidden_layers, - processor_layers=args.processor_layers, - mesh_aggr=args.mesh_aggr, - num_past_forcing_steps=args.num_past_forcing_steps, - num_future_forcing_steps=args.num_future_forcing_steps, - output_std=args.output_std, - output_clamping_lower=config.training.output_clamping.lower, - output_clamping_upper=config.training.output_clamping.upper, - g2m_gnn_type=args.g2m_gnn_type, - m2g_gnn_type=args.m2g_gnn_type, - mesh_up_gnn_type=args.mesh_up_gnn_type, - mesh_down_gnn_type=args.mesh_down_gnn_type, - ) + predictor = build_predictor(predictor_class, args, config, datastore) forecaster = ARForecaster(predictor, datastore) model = ForecasterModule( diff --git a/neural_lam/utils/buffer_list.py b/neural_lam/utils/buffer_list.py index c9508939..16ff8793 100644 --- a/neural_lam/utils/buffer_list.py +++ b/neural_lam/utils/buffer_list.py @@ -1,7 +1,7 @@ """Module wrapper exposing a list of tensors as registered buffers.""" # Standard library -from typing import Iterator, Union, overload +from typing import Iterator, overload # Third-party import torch @@ -44,8 +44,8 @@ def __getitem__(self, key: slice) -> list[torch.Tensor]: """Slice-indexed access overload; see the implementation below.""" def __getitem__( - self, key: Union[int, slice] - ) -> Union[torch.Tensor, list[torch.Tensor]]: + self, key: int | slice + ) -> torch.Tensor | list[torch.Tensor]: """Return the buffer(s) at ``key``. Supports integer indexing (with Python-style negative indices) @@ -76,13 +76,13 @@ def __iter__(self) -> Iterator[torch.Tensor]: """Iterate over the registered buffers in ascending index order.""" return (self[i] for i in range(len(self))) - def __itruediv__(self, other: float) -> "BufferList": + def __itruediv__(self, other: float | torch.Tensor) -> "BufferList": """ Divide each element in list with other. Parameters ---------- - other : float + other : float or torch.Tensor The value to divide by. Returns @@ -92,13 +92,13 @@ def __itruediv__(self, other: float) -> "BufferList": """ return self.__imul__(1.0 / other) - def __imul__(self, other: float) -> "BufferList": + def __imul__(self, other: float | torch.Tensor) -> "BufferList": """ Multiply each element in list with other. Parameters ---------- - other : float + other : float or torch.Tensor The value to multiply by. Returns diff --git a/neural_lam/utils/graph.py b/neural_lam/utils/graph.py index 08259cd0..426968ec 100644 --- a/neural_lam/utils/graph.py +++ b/neural_lam/utils/graph.py @@ -4,7 +4,7 @@ import os import warnings from pathlib import Path -from typing import Any, Union +from typing import Any # Third-party import torch @@ -142,7 +142,7 @@ def zero_index_g2m( def load_graph( - graph_dir_path: Union[str, Path], + graph_dir_path: str | Path, mesh_node_features_scaling: float, device: str = "cpu", ) -> tuple[bool, dict[str, Any]]: diff --git a/neural_lam/utils/logging.py b/neural_lam/utils/logging.py index 706629e0..e1c20862 100644 --- a/neural_lam/utils/logging.py +++ b/neural_lam/utils/logging.py @@ -1,9 +1,13 @@ """Setup and configuration of training loggers (WandB / MLFlow).""" # Standard library +import argparse import os import warnings -from typing import Any +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from ..datastore.base import BaseDatastore # Third-party import pytorch_lightning as pl @@ -33,7 +37,7 @@ def log_on_rank_zero( **kwargs : Any Keyword arguments passed to the logger. """ - if rank_zero_only.rank == 0: + if rank_zero_only.rank == 0: # ty: ignore[unresolved-attribute] log_fn = getattr(logger, level, logger.info) log_fn(msg, *args, **kwargs) @@ -67,14 +71,17 @@ def init_training_logger_metrics( @rank_zero_only def setup_training_logger( - datastore: Any, args: Any, run_name: str, run_dir: str -) -> Any: + datastore: "BaseDatastore", + args: argparse.Namespace, + run_name: str, + run_dir: str, +) -> pl.loggers.Logger: """ Set up the training logger (WandB or MLFlow). Parameters ---------- - datastore : Any + datastore : BaseDatastore Datastore providing metadata for logging configuration. args : argparse.Namespace Parsed training arguments controlling the logger backend. @@ -88,7 +95,7 @@ def setup_training_logger( Returns ------- - Any + pl.loggers.Logger The initialized logger object. Raises @@ -117,7 +124,7 @@ def setup_training_logger( return pl.loggers.WandbLogger( project=args.logger_project, name=None if args.wandb_id else run_name, - config=dict(training=vars(args), datastore=datastore._config), + config=dict(training=vars(args), datastore=datastore.config), resume=wandb_resume, id=args.wandb_id, save_dir=run_dir, @@ -140,7 +147,7 @@ def setup_training_logger( save_dir=run_dir, ) training_logger.log_hyperparams( - dict(training=vars(args), datastore=datastore._config) + dict(training=vars(args), datastore=datastore.config) ) return training_logger else: diff --git a/neural_lam/utils/tensor.py b/neural_lam/utils/tensor.py index a36c61cf..981ba2a8 100644 --- a/neural_lam/utils/tensor.py +++ b/neural_lam/utils/tensor.py @@ -37,7 +37,7 @@ def inverse_softplus( ``torch.clamp`` will zero the gradients near the bounds, but values this close to zero or ``threshold / beta`` already have negligible gradients. """ - x_clamped = torch.clamp( + x_clamped = torch.clamp( # ty: ignore[no-matching-overload] x, min=torch.log(torch.tensor(1e-6 + 1)) / beta, max=threshold / beta ) diff --git a/neural_lam/vis.py b/neural_lam/vis.py index 1e3dd415..cac7b942 100644 --- a/neural_lam/vis.py +++ b/neural_lam/vis.py @@ -2,7 +2,7 @@ # Standard library import warnings -from typing import Optional +from typing import Any # Third-party import cartopy.crs as ccrs @@ -16,6 +16,7 @@ import numpy as np import torch import xarray as xr +from cartopy.mpl.geoaxes import GeoAxes # Local from . import utils @@ -122,7 +123,7 @@ def _get_heatmap_var_labels(datastore: BaseRegularGridDatastore) -> list[str]: ] -def _to_heatmap_matrix(values) -> np.ndarray: +def _to_heatmap_matrix(values: Any) -> np.ndarray: """ Convert heatmap inputs to a ``(num_state_vars, pred_steps)`` matrix. @@ -228,7 +229,9 @@ def _get_heatmap_color_values( If ``normalization`` is not one of ``'state_std'`` or ``'diff_std'``. """ - def _per_var_fallback(): + def _per_var_fallback() -> ( + tuple[np.ndarray, str, matplotlib.colors.Colormap] + ): """ Normalize errors by per-variable maximum value. @@ -340,7 +343,7 @@ def _get_annotation_text_color( def plot_on_axis( - ax: matplotlib.axes.Axes, + ax: GeoAxes, da: xr.DataArray, datastore: BaseRegularGridDatastore, vmin: float | None = None, @@ -469,7 +472,7 @@ def plot_on_axis( def plot_error_heatmap( errors: torch.Tensor, datastore: BaseRegularGridDatastore, - title: Optional[str] = None, + title: str | None = None, normalization: str = "state_std", ) -> matplotlib.figure.Figure: """ @@ -546,7 +549,9 @@ def plot_error_heatmap( ) else: formatted_error = str(error) - text_color = _get_annotation_text_color(color_values_np[j, i], im) + text_color = _get_annotation_text_color( + float(color_values_np[j, i]), im + ) ax.text( i, j, @@ -586,7 +591,7 @@ def plot_error_heatmap( def plot_error_map( errors: torch.Tensor, datastore: BaseRegularGridDatastore, - title: Optional[str] = None, + title: str | None = None, ) -> matplotlib.figure.Figure: """ Deprecated: use :func:`plot_error_heatmap` instead. @@ -618,8 +623,8 @@ def plot_prediction( datastore: BaseRegularGridDatastore, da_prediction: xr.DataArray, da_target: xr.DataArray, - title: Optional[str] = None, - vrange: Optional[tuple[float, float]] = None, + title: str | None = None, + vrange: tuple[float, float] | None = None, boundary_alpha: float = 0.7, crop_to_interior: bool = True, colorbar_label: str = "", @@ -702,8 +707,8 @@ def plot_prediction( def plot_spatial_error( error: torch.Tensor, datastore: BaseRegularGridDatastore, - title: Optional[str] = None, - vrange: Optional[tuple[float, float]] = None, + title: str | None = None, + vrange: tuple[float, float] | None = None, boundary_alpha: float = 0.7, crop_to_interior: bool = True, colorbar_label: str = "", @@ -748,7 +753,7 @@ def plot_spatial_error( ) mesh = plot_on_axis( - ax=ax, + ax=ax, # ty: ignore[invalid-argument-type] da=xr.DataArray(error_np), datastore=datastore, vmin=vmin, @@ -767,7 +772,7 @@ def plot_spatial_error( pad=0.02, ) cbar.ax.tick_params(labelsize=_TICK_SIZE) - cbar.formatter.set_powerlimits((-3, 3)) + cbar.formatter.set_powerlimits((-3, 3)) # ty: ignore[unresolved-attribute] if colorbar_label: cbar.set_label(_tex_safe(colorbar_label), size=_LABEL_SIZE) diff --git a/neural_lam/weather_dataset.py b/neural_lam/weather_dataset.py index 4168396a..32c05604 100644 --- a/neural_lam/weather_dataset.py +++ b/neural_lam/weather_dataset.py @@ -3,7 +3,7 @@ # Standard library import datetime import warnings -from typing import Iterator, Optional, Union +from typing import Iterator # Third-party import numpy as np @@ -70,16 +70,17 @@ def __init__( self.num_future_forcing_steps = num_future_forcing_steps self.load_single_member = load_single_member - self.da_state = self.datastore.get_dataarray( + da_state = self.datastore.get_dataarray( category="state", split=self.split ) - self.da_forcing = self.datastore.get_dataarray( - category="forcing", split=self.split - ) - if self.da_state is None: + if da_state is None: raise ValueError( "The datastore must provide state data for the WeatherDataset." ) + self.da_state = da_state + self.da_forcing = self.datastore.get_dataarray( + category="forcing", split=self.split + ) if self.datastore.is_ensemble and self.load_single_member: warnings.warn( @@ -463,9 +464,9 @@ def _build_item_dataarrays( da_target_times, ) - def __getitem__( + def __getitem__( # ty: ignore[invalid-method-override] self, idx: int - ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, np.ndarray]: + ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: """ Return a single training sample, which consists of the initial states, target states, forcing and batch times. @@ -533,7 +534,9 @@ def __getitem__( def __iter__( self, - ) -> Iterator[tuple[torch.Tensor, torch.Tensor, torch.Tensor, np.ndarray]]: + ) -> Iterator[ + tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor] + ]: """ Convenience method to iterate over the dataset. @@ -547,9 +550,9 @@ def __iter__( def create_dataarray_from_tensor( self, tensor: torch.Tensor, - time: Union[datetime.datetime, list[datetime.datetime]], + time: datetime.datetime | list[datetime.datetime] | np.ndarray, category: str, - ): + ) -> xr.DataArray: """ Construct a xarray.DataArray from a `pytorch.Tensor` with coordinates for `grid_index`, `time` and `{category}_feature` matching the shape @@ -580,7 +583,7 @@ def create_dataarray_from_tensor( The constructed DataArray. """ - def _is_listlike(obj): + def _is_listlike(obj: object) -> bool: """Return ``True`` for list/tuple/ndarray-like containers.""" return hasattr(obj, "__iter__") and not isinstance(obj, str) @@ -591,7 +594,7 @@ def _is_listlike(obj): raise ValueError( "Expected a single time for a 2D tensor with assumed " "dimensions (grid_index, {category}_feature), but got " - f"{len(time)} times" # type: ignore + f"{len(time)} times" # ty: ignore[invalid-argument-type] ) elif len(tensor.shape) == 3: add_time_as_dim = True @@ -686,17 +689,17 @@ def __init__( self.load_single_member = load_single_member self.batch_size = batch_size self.num_workers: int = num_workers - self.train_dataset: Optional[WeatherDataset] = None - self.val_dataset: Optional[WeatherDataset] = None - self.test_dataset: Optional[WeatherDataset] = None - self.multiprocessing_context: Union[str, None] = None + self.train_dataset: WeatherDataset | None = None + self.val_dataset: WeatherDataset | None = None + self.test_dataset: WeatherDataset | None = None + self.multiprocessing_context: str | None = None self.eval_split = eval_split if num_workers > 0: # default to spawn for now, as the default on linux "fork" hangs # when using dask (which the npyfilesmeps datastore uses) self.multiprocessing_context = "spawn" - def setup(self, stage: Optional[str] = None) -> None: + def setup(self, stage: str | None = None) -> None: """ Instantiate datasets for the requested trainer stage. @@ -737,6 +740,7 @@ def setup(self, stage: Optional[str] = None) -> None: def train_dataloader(self) -> torch.utils.data.DataLoader: """Load train dataset.""" + assert self.train_dataset is not None return torch.utils.data.DataLoader( self.train_dataset, batch_size=self.batch_size, @@ -749,6 +753,7 @@ def train_dataloader(self) -> torch.utils.data.DataLoader: def val_dataloader(self) -> torch.utils.data.DataLoader: """Load validation dataset.""" + assert self.val_dataset is not None return torch.utils.data.DataLoader( self.val_dataset, batch_size=self.batch_size, @@ -761,6 +766,7 @@ def val_dataloader(self) -> torch.utils.data.DataLoader: def test_dataloader(self) -> torch.utils.data.DataLoader: """Load test dataset.""" + assert self.test_dataset is not None return torch.utils.data.DataLoader( self.test_dataset, batch_size=self.batch_size, diff --git a/pyproject.toml b/pyproject.toml index 113329e1..3cd9cc6f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,12 @@ gpu = ["torch>=2.12,<2.13"] # CUDA 13.0, default GPU build gpu-cu128 = ["torch>=2.11,<2.12"] # CUDA 12.8, last torch series with cu128 wheels [dependency-groups] -dev = ["pre-commit>=3.8.0", "pytest>=8.3.2", "pooch>=1.8.2"] +dev = [ + "pre-commit>=3.8.0", + "pytest>=8.3.2", + "pooch>=1.8.2", + "ty>=0.0.59", +] [tool.uv] # uv-specific configuration for PyTorch CPU/GPU variant selection. @@ -121,6 +126,12 @@ per-file-ignores = [ [tool.codespell] skip = "requirements/*" +[tool.ty.environment] +python = ".venv" + +[tool.ty.rules] +possibly-missing-submodule = "ignore" + # Pylint config [tool.pylint] ignore = [ diff --git a/tests/test_train_model_warnings.py b/tests/test_train_model_warnings.py index eb4c2bc0..5cc7e043 100644 --- a/tests/test_train_model_warnings.py +++ b/tests/test_train_model_warnings.py @@ -1,4 +1,5 @@ # Standard library +from types import SimpleNamespace from unittest.mock import MagicMock, patch # Third-party @@ -9,7 +10,11 @@ loguru.logger.catch = lambda f: f # First-party -from neural_lam.train_model import main # noqa: E402 +from neural_lam.train_model import ( # noqa: E402 + build_predictor, + load_forecaster_module_from_checkpoint, + main, +) @pytest.mark.parametrize( @@ -101,6 +106,95 @@ def capture_init(_self, **kwargs): assert captured_kwargs["train_steps_to_log"] == [2] +def test_checkpoint_loader_restores_gnn_type_kwargs(): + """Checkpoint reload must preserve custom GNN choices from saved args.""" + args = SimpleNamespace( + model="hi_lam", + graph="hierarchical", + hidden_dim=4, + hidden_layers=1, + processor_layers=1, + mesh_aggr="sum", + num_past_forcing_steps=1, + num_future_forcing_steps=1, + output_std=False, + g2m_gnn_type="PropagationNet", + m2g_gnn_type="PropagationNet", + mesh_up_gnn_type="PropagationNet", + mesh_down_gnn_type="InteractionNet", + ) + config = SimpleNamespace( + training=SimpleNamespace( + output_clamping=SimpleNamespace(lower={}, upper={}) + ) + ) + datastore = MagicMock() + captured_kwargs = {} + + class DummyPredictor: + def __init__(self, **kwargs): + captured_kwargs.update(kwargs) + + loaded_module = MagicMock() + + with ( + patch( + "neural_lam.train_model.torch.load", + return_value={"hyper_parameters": {"args": args}}, + ), + patch("neural_lam.train_model.MODELS", {"hi_lam": DummyPredictor}), + patch("neural_lam.train_model.ARForecaster"), + patch( + "neural_lam.train_model.ForecasterModule.load_from_checkpoint", + return_value=loaded_module, + ), + ): + result = load_forecaster_module_from_checkpoint( + "model.ckpt", config, datastore + ) + + assert result is loaded_module + assert captured_kwargs["g2m_gnn_type"] == "PropagationNet" + assert captured_kwargs["m2g_gnn_type"] == "PropagationNet" + assert captured_kwargs["mesh_up_gnn_type"] == "PropagationNet" + assert captured_kwargs["mesh_down_gnn_type"] == "InteractionNet" + + +def test_build_predictor_omits_hierarchical_gnn_kwargs_for_graph_lam(): + """GraphLAM must not receive hierarchical-only GNN constructor kwargs.""" + args = SimpleNamespace( + model="graph_lam", + graph="multiscale", + hidden_dim=4, + hidden_layers=1, + processor_layers=1, + mesh_aggr="sum", + num_past_forcing_steps=1, + num_future_forcing_steps=1, + output_std=False, + g2m_gnn_type="PropagationNet", + m2g_gnn_type="InteractionNet", + mesh_up_gnn_type="PropagationNet", + mesh_down_gnn_type="PropagationNet", + ) + config = SimpleNamespace( + training=SimpleNamespace( + output_clamping=SimpleNamespace(lower={}, upper={}) + ) + ) + captured_kwargs = {} + + class DummyGraphLAM: + def __init__(self, **kwargs): + captured_kwargs.update(kwargs) + + build_predictor(DummyGraphLAM, args, config, MagicMock()) + + assert "mesh_up_gnn_type" not in captured_kwargs + assert "mesh_down_gnn_type" not in captured_kwargs + assert captured_kwargs["g2m_gnn_type"] == "PropagationNet" + + @pytest.mark.parametrize( "train_steps,val_steps,match_err", [ diff --git a/uv.lock b/uv.lock index b9d5a7ed..795cb0c2 100644 --- a/uv.lock +++ b/uv.lock @@ -2,27 +2,32 @@ version = 1 revision = 3 requires-python = ">=3.10" resolution-markers = [ - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version < '3.11' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version < '3.11' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version < '3.11' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version < '3.11' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", @@ -693,23 +698,28 @@ name = "contourpy" version = "1.3.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", @@ -857,7 +867,8 @@ name = "cuda-bindings" version = "12.9.6" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14'", + "python_full_version >= '3.15'", + "python_full_version == '3.14.*'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", @@ -895,7 +906,8 @@ name = "cuda-bindings" version = "13.2.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14'", + "python_full_version >= '3.15'", + "python_full_version == '3.14.*'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", @@ -938,7 +950,8 @@ name = "cuda-toolkit" version = "12.8.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14'", + "python_full_version >= '3.15'", + "python_full_version == '3.14.*'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", @@ -988,7 +1001,8 @@ name = "cuda-toolkit" version = "13.0.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14'", + "python_full_version >= '3.15'", + "python_full_version == '3.14.*'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", @@ -2554,23 +2568,28 @@ name = "networkx" version = "3.6.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", @@ -2605,9 +2624,9 @@ dependencies = [ { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, { name = "shapely" }, { name = "torch", version = "2.11.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "(extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "torch", version = "2.12.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "torch", version = "2.12.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version < '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, { name = "torch", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128')" }, - { name = "torch", version = "2.12.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "torch", version = "2.12.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, { name = "torch", version = "2.12.0+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" }, marker = "extra == 'extra-10-neural-lam-gpu' or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, { name = "torch-geometric" }, { name = "tueplots" }, @@ -2616,8 +2635,8 @@ dependencies = [ [package.optional-dependencies] cpu = [ - { name = "torch", version = "2.12.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "torch", version = "2.12.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "torch", version = "2.12.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version < '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "torch", version = "2.12.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, ] gpu = [ { name = "torch", version = "2.12.0+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" } }, @@ -2631,6 +2650,7 @@ dev = [ { name = "pooch" }, { name = "pre-commit" }, { name = "pytest" }, + { name = "ty" }, ] [package.metadata] @@ -2666,6 +2686,7 @@ dev = [ { name = "pooch", specifier = ">=1.8.2" }, { name = "pre-commit", specifier = ">=3.8.0" }, { name = "pytest", specifier = ">=8.3.2" }, + { name = "ty", specifier = ">=0.0.59" }, ] [[package]] @@ -2716,23 +2737,28 @@ name = "numcodecs" version = "0.16.5" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", @@ -2839,23 +2865,28 @@ name = "numpy" version = "2.4.4" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", @@ -4083,23 +4114,28 @@ name = "pyproj" version = "3.7.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", @@ -4236,9 +4272,9 @@ dependencies = [ { name = "packaging" }, { name = "pyyaml" }, { name = "torch", version = "2.11.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "(extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "torch", version = "2.12.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "torch", version = "2.12.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version < '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, { name = "torch", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128')" }, - { name = "torch", version = "2.12.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "torch", version = "2.12.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, { name = "torch", version = "2.12.0+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" }, marker = "extra == 'extra-10-neural-lam-gpu' or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, { name = "torchmetrics" }, { name = "tqdm" }, @@ -4453,23 +4489,28 @@ name = "scikit-learn" version = "1.8.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", @@ -4588,23 +4629,28 @@ name = "scipy" version = "1.17.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", @@ -4854,23 +4900,28 @@ name = "spherical-geometry" version = "1.4.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", @@ -5083,7 +5134,8 @@ name = "torch" version = "2.11.0+cu128" source = { registry = "https://download.pytorch.org/whl/cu128" } resolution-markers = [ - "python_full_version >= '3.14'", + "python_full_version >= '3.15'", + "python_full_version == '3.14.*'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", @@ -5135,21 +5187,21 @@ name = "torch" version = "2.12.0" source = { registry = "https://download.pytorch.org/whl/cpu" } resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'darwin'", + "python_full_version == '3.14.*' and sys_platform == 'darwin'", "python_full_version == '3.13.*' and sys_platform == 'darwin'", "python_full_version == '3.12.*' and sys_platform == 'darwin'", "python_full_version == '3.11.*' and sys_platform == 'darwin'", "python_full_version < '3.11' and sys_platform == 'darwin'", ] dependencies = [ - { name = "filelock", marker = "(sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "fsspec", marker = "(sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "jinja2", marker = "(sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "filelock", marker = "(python_full_version < '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "fsspec", marker = "(python_full_version < '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "jinja2", marker = "(python_full_version < '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.11' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.11' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.11' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.11' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.11' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "setuptools", marker = "(sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "sympy", marker = "(sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "typing-extensions", marker = "(sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.11' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.11' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.11' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "setuptools", marker = "(python_full_version < '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "sympy", marker = "(python_full_version < '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "typing-extensions", marker = "(python_full_version < '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, ] wheels = [ { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.12.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:1834bd984f8a2f4f16bdfbeecca9146184b220aa46276bf5756735b5dae12812", upload-time = "2026-05-12T16:20:02Z" }, @@ -5166,7 +5218,8 @@ name = "torch" version = "2.12.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14'", + "python_full_version >= '3.15'", + "python_full_version == '3.14.*'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", @@ -5226,21 +5279,23 @@ name = "torch" version = "2.12.0+cpu" source = { registry = "https://download.pytorch.org/whl/cpu" } resolution-markers = [ - "python_full_version >= '3.14' and sys_platform != 'darwin'", + "python_full_version >= '3.15' and sys_platform != 'darwin'", + "python_full_version == '3.14.*' and sys_platform != 'darwin'", "python_full_version == '3.13.*' and sys_platform != 'darwin'", "python_full_version == '3.12.*' and sys_platform != 'darwin'", "python_full_version == '3.11.*' and sys_platform != 'darwin'", + "python_full_version >= '3.15' and sys_platform == 'darwin'", "python_full_version < '3.11' and sys_platform != 'darwin'", ] dependencies = [ - { name = "filelock", marker = "(sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "fsspec", marker = "(sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "jinja2", marker = "(sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "filelock", marker = "(python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "fsspec", marker = "(python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "jinja2", marker = "(python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.11' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.11' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.11' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.11' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.11' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "setuptools", marker = "(sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "sympy", marker = "(sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "typing-extensions", marker = "(sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "setuptools", marker = "(python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "sympy", marker = "(python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "typing-extensions", marker = "(python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, ] wheels = [ { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.12.0%2Bcpu-cp310-cp310-linux_s390x.whl", hash = "sha256:0e04beb2ab285bdcc5bb15d9cf7b2a757cf0d9422092fa5747de946359e1b409", upload-time = "2026-05-12T23:15:34Z" }, @@ -5281,7 +5336,8 @@ name = "torch" version = "2.12.0+cu130" source = { registry = "https://download.pytorch.org/whl/cu130" } resolution-markers = [ - "python_full_version >= '3.14'", + "python_full_version >= '3.15'", + "python_full_version == '3.14.*'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", @@ -5358,9 +5414,9 @@ dependencies = [ { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, { name = "packaging" }, { name = "torch", version = "2.11.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "(extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, - { name = "torch", version = "2.12.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "torch", version = "2.12.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version < '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, { name = "torch", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128')" }, - { name = "torch", version = "2.12.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, + { name = "torch", version = "2.12.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version >= '3.15' and extra == 'extra-10-neural-lam-cpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (python_full_version < '3.15' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu') or (sys_platform != 'darwin' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128') or (extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, { name = "torch", version = "2.12.0+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" }, marker = "extra == 'extra-10-neural-lam-gpu' or (extra == 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu-cu128')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/81/34/39b8b749333db56c0585d7a11fa62a283c087bb1dfc897d69fb8cedbefb1/torchmetrics-1.9.0.tar.gz", hash = "sha256:a488609948600df52d3db4fcdab02e62aab2a85ef34da67037dc3e65b8512faa", size = 581765, upload-time = "2026-03-09T17:41:22.443Z" } @@ -5385,7 +5441,8 @@ name = "triton" version = "3.6.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14'", + "python_full_version >= '3.15'", + "python_full_version == '3.14.*'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", @@ -5413,7 +5470,8 @@ name = "triton" version = "3.7.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14'", + "python_full_version >= '3.15'", + "python_full_version == '3.14.*'", "python_full_version == '3.13.*'", "python_full_version == '3.12.*'", "python_full_version == '3.11.*'", @@ -5449,6 +5507,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b6/5b/dc9e79200e7e5b4795a242b777729ccf8687be9025c14bca403a6182e2c2/tueplots-0.2.4-py3-none-any.whl", hash = "sha256:aafe4ff0727ab127f2665488d070fd2df3fb3dff876c8cf3cfe6091d144744aa", size = 18016, upload-time = "2026-03-24T08:34:42.267Z" }, ] +[[package]] +name = "ty" +version = "0.0.59" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/b0/84ae7b3bf6e3e9f57eb9635eeff5a80b36e57aa089f40be0fb5c384fa176/ty-0.0.59.tar.gz", hash = "sha256:53e53ffeed78ad59cd237fa8ea1316d2b94e13efdea9a945698acab549e005aa", size = 6145435, upload-time = "2026-07-12T20:22:02.781Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/e8/650b42fbef4d48e6ca682b0b6e9b68fa8fcf55cbb0a6892ab89990018b6f/ty-0.0.59-py3-none-linux_armv6l.whl", hash = "sha256:f8fb08a767ef8f11ea3c537b9d77860726cc2bc39e6f77ad13c02d5b289f20a7", size = 11700328, upload-time = "2026-07-12T20:21:26.046Z" }, + { url = "https://files.pythonhosted.org/packages/22/ac/0ca3a89d5f59ae5f308e5e83428cac5f9143200767743e052fba90b4b81e/ty-0.0.59-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c7f4d5630836c8a0ba13dd4ac7bdae080a7d6ebe965b817ff642dc961bcf2a53", size = 11494310, upload-time = "2026-07-12T20:21:28.491Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f8/5076de6001cefbccd8e6dc8472262697e43308ff66b0e87c72abba136357/ty-0.0.59-py3-none-macosx_11_0_arm64.whl", hash = "sha256:872f6fb02c6db5553c4d5fb283b3d50f0985fb9a29a910e4fda4793a775c1926", size = 11026797, upload-time = "2026-07-12T20:21:30.879Z" }, + { url = "https://files.pythonhosted.org/packages/2e/0f/fca28481b6a138e2b798ad9fdc98a095475f9104948ba242fce4b477782b/ty-0.0.59-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2af8eefbfe806337770eec12c0c819c5f1b8f5b85f8369cb1cc9fa25234a2208", size = 11475304, upload-time = "2026-07-12T20:21:33.041Z" }, + { url = "https://files.pythonhosted.org/packages/08/4b/1fed8b81b389ef4bbc0400f19e05fc16496b162577779dc0e5fc65ac216c/ty-0.0.59-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0acf8b76a1c9a7ddef460b42475f6c76193164426ab080783af1c3175b4b999b", size = 11533131, upload-time = "2026-07-12T20:21:35.189Z" }, + { url = "https://files.pythonhosted.org/packages/5f/fc/04eec35e05a10e0fea1c6503a290ccc3935efda9c845aff64e83282c1af7/ty-0.0.59-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:043c2e00eb1d7475f928af7dedd71f69b64e69bfca55e36f4c968479e1373fc4", size = 12205932, upload-time = "2026-07-12T20:21:37.324Z" }, + { url = "https://files.pythonhosted.org/packages/a9/dd/a61de859659fa11b55917ad38340a8f2c61f5ae17d1874929f29084c6990/ty-0.0.59-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f0d688d857441df57f48fca66c029d85cf737c510e7be1d01144cdad1e58d968", size = 12758406, upload-time = "2026-07-12T20:21:39.525Z" }, + { url = "https://files.pythonhosted.org/packages/c6/e8/fa66f05997eab8ca75fc4f17320140e25467849e0cc75597f898cc22099c/ty-0.0.59-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a96c9f88394a3b42c737e2125b2330543f0d90a43b49761f377d96f8c3ee0d62", size = 12288176, upload-time = "2026-07-12T20:21:41.784Z" }, + { url = "https://files.pythonhosted.org/packages/15/68/0fca59963bd5123f42d5f7da50667e7a52e8e9615e3a16d8c2c0d3b2d143/ty-0.0.59-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08dbcb268edcafcb152e59475b5b495ce28d0b340a395c09943557678f4d5a6", size = 12028471, upload-time = "2026-07-12T20:21:43.82Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5b/cd7dabbbab392578f11179919da5c25d8c3322e5388a688f539ea0539603/ty-0.0.59-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:8812764b9a40fdc98df1272826e73a298ef56b06681135e643bcf90aad1896f7", size = 12297646, upload-time = "2026-07-12T20:21:45.76Z" }, + { url = "https://files.pythonhosted.org/packages/1d/37/2e9c94f0b383d8cbe1a35517ab470b7810bc9d7501603ab532bcd5be5e90/ty-0.0.59-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:fd53b8581641d8dad7bfac6d5ea589e91a883d6837e0b9a286fdae30722b7c69", size = 11432519, upload-time = "2026-07-12T20:21:47.694Z" }, + { url = "https://files.pythonhosted.org/packages/9d/0a/af93e9785200f11ac416cc20235fc2464c9bd978e791190684ea0e458795/ty-0.0.59-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:86da5872124a41877d95058bc17d33ddcff034b587eb5f1e2917ab88ba227dac", size = 11554993, upload-time = "2026-07-12T20:21:49.671Z" }, + { url = "https://files.pythonhosted.org/packages/4b/dd/651bf87e20d00376c81b19124756491cffaf20eb8bec05a8794e5a8cf641/ty-0.0.59-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6a233eef5f2fd4d894881e4a0aec83c9f172bfae1d787d6596ee1939fcc7723e", size = 11818230, upload-time = "2026-07-12T20:21:51.659Z" }, + { url = "https://files.pythonhosted.org/packages/16/50/c947c4155fea751d135b19affdf734bbce72a94e446b866cf0c62f8bed69/ty-0.0.59-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7ff678c18b5f1e3128b75a35e50dee7908dea55155baa31cd790619d5014cbf5", size = 12135194, upload-time = "2026-07-12T20:21:53.796Z" }, + { url = "https://files.pythonhosted.org/packages/b1/13/e5feb138888de1e95037c843571bbbd4ac21bf0a190507468098599a321f/ty-0.0.59-py3-none-win32.whl", hash = "sha256:cf8abb4b8095c5fe39102b8127f5886db308c8d4600909ddbc905512ce9c8163", size = 11179249, upload-time = "2026-07-12T20:21:55.752Z" }, + { url = "https://files.pythonhosted.org/packages/76/dd/52914dcbeeba92c207de40ef7109a58dcb5527aeb21c8f8feb7402aa9e29/ty-0.0.59-py3-none-win_amd64.whl", hash = "sha256:1dde20a82243d24407869e5a608c2f15efddd5cefc662aef461a5af84bfb3f8b", size = 12251079, upload-time = "2026-07-12T20:21:58.1Z" }, + { url = "https://files.pythonhosted.org/packages/d4/8f/ac36fde77e223297454c1e0aeb8888c169eaacf3163bb609e3af942c88cb/ty-0.0.59-py3-none-win_arm64.whl", hash = "sha256:987043ee9e021f49493d9135891ac69c1affeee0d4ad4480c5fa4d9c975fc91b", size = 11650921, upload-time = "2026-07-12T20:22:00.348Z" }, +] + [[package]] name = "typing-extensions" version = "4.15.0" @@ -5612,23 +5695,28 @@ name = "xarray" version = "2026.2.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", @@ -5810,23 +5898,28 @@ name = "zarr" version = "3.1.6" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra == 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra == 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform != 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and sys_platform == 'darwin' and extra == 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", - "python_full_version >= '3.14' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version >= '3.15' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", + "python_full_version == '3.14.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.13.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.12.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'", "python_full_version == '3.11.*' and extra != 'extra-10-neural-lam-cpu' and extra != 'extra-10-neural-lam-gpu' and extra != 'extra-10-neural-lam-gpu-cu128'",