From c010e297538d7c5789bb433ec637e8191a500a27 Mon Sep 17 00:00:00 2001 From: selmanozleyen Date: Mon, 9 Sep 2024 15:52:59 +0200 Subject: [PATCH 1/4] set versions --- .github/workflows/test.yml | 4 ++-- docs/installation.rst | 2 +- pyproject.toml | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e27a02960..4b61b858a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,10 +19,10 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - python: ["3.9", "3.10"] + python: ["3.10", "3.11"] include: - os: macos-latest - python: "3.9" + python: "3.10" steps: - uses: actions/checkout@v3 diff --git a/docs/installation.rst b/docs/installation.rst index 5d0e416b5..344cc9efb 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -1,6 +1,6 @@ Installation ============ -:mod:`moscot` requires Python version >= 3.9 to run. +:mod:`moscot` requires Python version >= 3.10 to run. PyPI ---- diff --git a/pyproject.toml b/pyproject.toml index ea8f1a6ec..1c47e53a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "moscot" dynamic = ["version"] description = "Multi-omic single-cell optimal transport tools" readme = "README.rst" -requires-python = ">=3.9" +requires-python = ">=3.10" license = {file = "LICENSE"} classifiers = [ "Development Status :: 4 - Beta", @@ -232,7 +232,7 @@ ignore_roles = [ [tool.mypy] mypy_path = "$MYPY_CONFIG_FILE_DIR/src" -python_version = "3.9" +python_version = "3.10" plugins = "numpy.typing.mypy_plugin" ignore_errors = false @@ -269,7 +269,7 @@ max_line_length = 120 legacy_tox_ini = """ [tox] min_version = 4.0 -env_list = lint-code,py{3.9,3.10,3.11} +env_list = lint-code,py{3.10,3.11,3.12} skip_missing_interpreters = true [testenv] From 02882826ea027976dcb524ac7d4c218516425fee Mon Sep 17 00:00:00 2001 From: selmanozleyen Date: Tue, 10 Sep 2024 15:37:03 +0200 Subject: [PATCH 2/4] asses mypy errors From 1559c363655eec1d0464dfb10eee04b0d295e83e Mon Sep 17 00:00:00 2001 From: selmanozleyen Date: Thu, 12 Sep 2024 14:54:56 +0200 Subject: [PATCH 3/4] Revert "asses mypy errors" This reverts commit 2e87abea310c91839a10a5a1250ba0e5ba760b98. --- src/moscot/_types.py | 4 ++-- src/moscot/backends/ott/_utils.py | 2 +- src/moscot/backends/ott/output.py | 4 ++-- src/moscot/backends/utils.py | 3 ++- src/moscot/base/cost.py | 4 ++-- src/moscot/base/output.py | 2 +- src/moscot/base/problems/_mixins.py | 4 ++-- src/moscot/base/problems/_utils.py | 2 +- src/moscot/base/problems/problem.py | 2 +- src/moscot/costs/_costs.py | 6 +++--- src/moscot/plotting/_utils.py | 2 +- src/moscot/problems/generic/_generic.py | 4 ++-- src/moscot/problems/space/_mapping.py | 4 ++-- src/moscot/problems/space/_mixins.py | 6 +++--- src/moscot/problems/time/_lineage.py | 2 +- src/moscot/problems/time/_mixins.py | 6 +++--- src/moscot/utils/tagged_array.py | 2 +- 17 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/moscot/_types.py b/src/moscot/_types.py index c3f599d2d..1c60884a2 100644 --- a/src/moscot/_types.py +++ b/src/moscot/_types.py @@ -10,8 +10,8 @@ ArrayLike = NDArray[np.float64] except (ImportError, TypeError): - ArrayLike = np.ndarray - DTypeLike = np.dtype + ArrayLike = np.ndarray # type: ignore[misc] + DTypeLike = np.dtype # type: ignore[misc] ProblemKind_t = Literal["linear", "quadratic", "unknown"] Numeric_t = Union[int, float] # type of `time_key` arguments diff --git a/src/moscot/backends/ott/_utils.py b/src/moscot/backends/ott/_utils.py index 42cc87af5..2cac53b30 100644 --- a/src/moscot/backends/ott/_utils.py +++ b/src/moscot/backends/ott/_utils.py @@ -108,7 +108,7 @@ def densify(arr: ArrayLike) -> jax.Array: dense :mod:`jax` array. """ if sp.issparse(arr): - arr = arr.toarray() + arr = arr.toarray() # type: ignore[attr-defined] elif isinstance(arr, jesp.BCOO): arr = arr.todense() return jnp.asarray(arr) diff --git a/src/moscot/backends/ott/output.py b/src/moscot/backends/ott/output.py index c50850ec3..60d727faf 100644 --- a/src/moscot/backends/ott/output.py +++ b/src/moscot/backends/ott/output.py @@ -375,8 +375,8 @@ def project_to_transport_matrix( # type:ignore[override] The projected transport matrix. """ src_cells, tgt_cells = jnp.asarray(src_cells), jnp.asarray(tgt_cells) - push: Callable[[Any], Any] = self.push if condition is None else lambda x: self.push(x, condition) # type: ignore - pull: Callable[[Any], Any] = self.pull if condition is None else lambda x: self.pull(x, condition) # type: ignore + push = self.push if condition is None else lambda x: self.push(x, condition) + pull = self.pull if condition is None else lambda x: self.pull(x, condition) func, src_dist, tgt_dist = (push, src_cells, tgt_cells) if forward else (pull, tgt_cells, src_cells) return self._project_transport_matrix( src_dist=src_dist, diff --git a/src/moscot/backends/utils.py b/src/moscot/backends/utils.py index 988e05413..fde874c0f 100644 --- a/src/moscot/backends/utils.py +++ b/src/moscot/backends/utils.py @@ -42,7 +42,8 @@ def register_solver( return _REGISTRY.register(backend) # type: ignore[return-value] -@register_solver("ott") +# TODO(@MUCDK) fix mypy error +@register_solver("ott") # type: ignore[arg-type] def _( problem_kind: Literal["linear", "quadratic"], solver_name: Optional[Literal["GENOTLinSolver"]] = None, diff --git a/src/moscot/base/cost.py b/src/moscot/base/cost.py index 73adfe8c9..8bea310be 100644 --- a/src/moscot/base/cost.py +++ b/src/moscot/base/cost.py @@ -53,12 +53,12 @@ def __call__(self, *args: Any, **kwargs: Any) -> ArrayLike: """ cost = self._compute(*args, **kwargs) if np.any(np.isnan(cost)): - maxx = np.nanmax(cost) # type: ignore[var-annotated] + maxx = np.nanmax(cost) logger.warning( f"Cost matrix contains `{np.sum(np.isnan(cost))}` NaN values, " f"setting them to the maximum value `{maxx}`." ) - cost = np.nan_to_num(cost, nan=maxx) + cost = np.nan_to_num(cost, nan=maxx) # type: ignore[call-overload] if np.any(cost < 0): raise ValueError(f"Cost matrix contains `{np.sum(cost < 0)}` negative values.") return cost diff --git a/src/moscot/base/output.py b/src/moscot/base/output.py index 3565c5790..9617b8729 100644 --- a/src/moscot/base/output.py +++ b/src/moscot/base/output.py @@ -354,7 +354,7 @@ def transport_matrix(self) -> ArrayLike: # noqa: D102 @property def shape(self) -> tuple[int, int]: # noqa: D102 - return self.transport_matrix.shape + return self.transport_matrix.shape # type: ignore[return-value] def to( # noqa: D102 self, device: Optional[Device_t] = None, dtype: Optional[DTypeLike] = None diff --git a/src/moscot/base/problems/_mixins.py b/src/moscot/base/problems/_mixins.py index 8d27cd177..9c460eac2 100644 --- a/src/moscot/base/problems/_mixins.py +++ b/src/moscot/base/problems/_mixins.py @@ -388,7 +388,7 @@ def _sample_from_tmap( account_for_unbalancedness: bool = False, interpolation_parameter: Optional[Numeric_t] = None, seed: Optional[int] = None, - ) -> tuple[Any, list[str]]: + ) -> tuple[list[Any], list[ArrayLike]]: rng = np.random.RandomState(seed) if account_for_unbalancedness and interpolation_parameter is None: raise ValueError("When accounting for unbalancedness, interpolation parameter must be provided.") @@ -453,7 +453,7 @@ def _sample_from_tmap( for i in range(len(rows_batch)) ] all_cols_sampled.extend(cols_sampled) - return rows, all_cols_sampled + return rows, all_cols_sampled # type: ignore[return-value] def _interpolate_transport( self: AnalysisMixinProtocol[K, B], diff --git a/src/moscot/base/problems/_utils.py b/src/moscot/base/problems/_utils.py index 482f79b75..40bf0a99a 100644 --- a/src/moscot/base/problems/_utils.py +++ b/src/moscot/base/problems/_utils.py @@ -386,7 +386,7 @@ def perm_test_extractor(res: Sequence[Tuple[ArrayLike, ArrayLike]]) -> Tuple[Arr corr_bs = np.concatenate(corr_bs, axis=0) corr_ci_low, corr_ci_high = np.quantile(corr_bs, q=ql, axis=0), np.quantile(corr_bs, q=qh, axis=0) - return pvals, corr_ci_low, corr_ci_high + return pvals, corr_ci_low, corr_ci_high # type:ignore[return-value] if not (0 <= confidence_level <= 1): raise ValueError(f"Expected `confidence_level` to be in interval `[0, 1]`, found `{confidence_level}`.") diff --git a/src/moscot/base/problems/problem.py b/src/moscot/base/problems/problem.py index 93a3e24d0..708b35d44 100644 --- a/src/moscot/base/problems/problem.py +++ b/src/moscot/base/problems/problem.py @@ -183,7 +183,7 @@ def _split_mass(arr: ArrayLike) -> ArrayLike: if start >= adata.n_obs: raise IndexError(f"Expected starting index to be smaller than `{adata.n_obs}`, found `{start}`.") data = np.zeros((adata.n_obs,), dtype=float) - data[range(start, min(start + offset, adata.n_obs))] = 1.0 # type: ignore[index] + data[range(start, min(start + offset, adata.n_obs))] = 1.0 else: raise TypeError(f"Unable to interpret subset of type `{type(subset)}`.") elif not hasattr(data, "shape"): diff --git a/src/moscot/costs/_costs.py b/src/moscot/costs/_costs.py index fd79b8a71..f41c0f7f2 100644 --- a/src/moscot/costs/_costs.py +++ b/src/moscot/costs/_costs.py @@ -138,7 +138,7 @@ def _scaled_hamming_dist(x: ArrayLike, y: ArrayLike) -> float: raise ValueError("No shared indices.") b2 = y[shared_indices] - differences: ArrayLike = b1 != b2 - double_scars: ArrayLike = differences & (b1 != 0) & (b2 != 0) + differences = b1 != b2 + double_scars = differences & (b1 != 0) & (b2 != 0) - return float(float(np.sum(differences)) + np.sum(double_scars)) / len(b1) + return (np.sum(differences) + np.sum(double_scars)) / len(b1) diff --git a/src/moscot/plotting/_utils.py b/src/moscot/plotting/_utils.py index 7047945b0..358ae5fa2 100644 --- a/src/moscot/plotting/_utils.py +++ b/src/moscot/plotting/_utils.py @@ -463,7 +463,7 @@ def _plot_scatter( _ = kwargs.pop("palette", None) if (time_points[i] == source and push) or (time_points[i] == target and not push): st = f"not in {time_points[i]}" - vmin, vmax = np.nanmin(tmp[mask]), np.nanmax(tmp[mask]) # type: ignore[var-annotated] + vmin, vmax = np.nanmin(tmp[mask]), np.nanmax(tmp[mask]) column = pd.Series(tmp).fillna(st).astype("category") # TODO(michalk8): check if len(np.unique(column[mask.values].values)) > 2: diff --git a/src/moscot/problems/generic/_generic.py b/src/moscot/problems/generic/_generic.py index c5b885dcc..8d727d0d0 100644 --- a/src/moscot/problems/generic/_generic.py +++ b/src/moscot/problems/generic/_generic.py @@ -37,7 +37,7 @@ def set_quad_defaults(z: Optional[Union[str, Mapping[str, Any]]]) -> Dict[str, s raise TypeError("`x_attr` and `y_attr` must be of type `str` or `dict` if no callback is provided.") -class SinkhornProblem(GenericAnalysisMixin[K, B], CompoundProblem[K, B]): +class SinkhornProblem(GenericAnalysisMixin[K, B], CompoundProblem[K, B]): # type: ignore[misc] """Class for solving a :term:`linear problem`. Parameters @@ -264,7 +264,7 @@ def _valid_policies(self) -> Tuple[Policy_t, ...]: return _constants.SEQUENTIAL, _constants.EXPLICIT, _constants.STAR # type: ignore[return-value] -class GWProblem(GenericAnalysisMixin[K, B], CompoundProblem[K, B]): +class GWProblem(GenericAnalysisMixin[K, B], CompoundProblem[K, B]): # type: ignore[misc] """Class for solving the :term:`GW ` or :term:`FGW ` problems. Parameters diff --git a/src/moscot/problems/space/_mapping.py b/src/moscot/problems/space/_mapping.py index dcb74d60a..abe440e28 100644 --- a/src/moscot/problems/space/_mapping.py +++ b/src/moscot/problems/space/_mapping.py @@ -65,8 +65,8 @@ def _create_problem( adata_tgt=self.adata_sc, src_obs_mask=src_mask, tgt_obs_mask=None, - src_var_mask=self.filtered_vars, - tgt_var_mask=self.filtered_vars, + src_var_mask=self.filtered_vars, # type: ignore[arg-type] + tgt_var_mask=self.filtered_vars, # type: ignore[arg-type] src_key=src, tgt_key=tgt, **kwargs, diff --git a/src/moscot/problems/space/_mixins.py b/src/moscot/problems/space/_mixins.py index a182999f1..d72c79c2b 100644 --- a/src/moscot/problems/space/_mixins.py +++ b/src/moscot/problems/space/_mixins.py @@ -42,7 +42,7 @@ class SpatialAlignmentMixinProtocol(AnalysisMixinProtocol[K, B]): _spatial_key: Optional[str] batch_key: Optional[str] - def _subset_spatial( + def _subset_spatial( # type:ignore[empty-body] self: "SpatialAlignmentMixinProtocol[K, B]", k: K, spatial_key: str, @@ -780,13 +780,13 @@ def _compute_correspondence( def pdist(row_idx: ArrayLike, col_idx: float, feat: ArrayLike) -> Any: if len(row_idx) > 0: - return pairwise_distances(feat[row_idx, :], feat[[col_idx], :]).mean() + return pairwise_distances(feat[row_idx, :], feat[[col_idx], :]).mean() # type: ignore[index] return np.nan # TODO(michalk8): vectorize using jax, this is just a for loop vpdist = np.vectorize(pdist, excluded=["feat"]) if sp.issparse(features): - features = features.toarray() + features = features.toarray() # type: ignore[attr-defined] feat_arr, index_arr, support_arr = [], [], [] for ind, i in enumerate(support): diff --git a/src/moscot/problems/time/_lineage.py b/src/moscot/problems/time/_lineage.py index b20ee5e11..809b7f8b9 100644 --- a/src/moscot/problems/time/_lineage.py +++ b/src/moscot/problems/time/_lineage.py @@ -23,7 +23,7 @@ __all__ = ["TemporalProblem", "LineageProblem"] -class TemporalProblem( +class TemporalProblem( # type: ignore[misc] TemporalMixin[Numeric_t, BirthDeathProblem], BirthDeathMixin, CompoundProblem[Numeric_t, BirthDeathProblem] ): """Class for analyzing time-series single cell data based on :cite:`schiebinger:19`. diff --git a/src/moscot/problems/time/_mixins.py b/src/moscot/problems/time/_mixins.py index 3d565bdec..29a44aed0 100644 --- a/src/moscot/problems/time/_mixins.py +++ b/src/moscot/problems/time/_mixins.py @@ -587,7 +587,7 @@ def cell_costs_source(self: TemporalMixinProtocol[K, B]) -> Optional[pd.DataFram # TODO(michalk8): `[1]` will fail if potentials is None df_list = [ pd.DataFrame( - np.asarray(problem.solution.potentials[0]), + np.asarray(problem.solution.potentials[0]), # type: ignore[union-attr,index] index=problem.adata_src.obs_names, columns=cols, ) @@ -612,7 +612,7 @@ def cell_costs_target(self: TemporalMixinProtocol[K, B]) -> Optional[pd.DataFram # TODO(michalk8): `[1]` will fail if potentials is None df_list = [ pd.DataFrame( - np.array(problem.solution.potentials[1]), + np.array(problem.solution.potentials[1]), # type: ignore[union-attr,index] index=problem.adata_tgt.obs_names, columns=cols, ) @@ -664,7 +664,7 @@ def _get_data( else: raise ValueError(f"No data found for `{target}` time point.") - return ( + return ( # type:ignore[return-value] source_data, growth_rates_source, intermediate_data, diff --git a/src/moscot/utils/tagged_array.py b/src/moscot/utils/tagged_array.py index 5a1ed5781..050573534 100644 --- a/src/moscot/utils/tagged_array.py +++ b/src/moscot/utils/tagged_array.py @@ -167,7 +167,7 @@ def shape(self) -> Tuple[int, int]: x, y = self.data_src, (self.data_src if self.data_tgt is None else self.data_tgt) return x.shape[0], y.shape[0] - return self.data_src.shape + return self.data_src.shape # type: ignore[return-value] @property def is_cost_matrix(self) -> bool: From f92b6bc9a8f620efda60e8384bdcfcc34cde8358 Mon Sep 17 00:00:00 2001 From: selmanozleyen Date: Thu, 12 Sep 2024 14:57:01 +0200 Subject: [PATCH 4/4] fix mypy errors --- src/moscot/__init__.py | 6 +++--- src/moscot/base/output.py | 2 +- src/moscot/utils/tagged_array.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/moscot/__init__.py b/src/moscot/__init__.py index 02925d781..dc69df60d 100644 --- a/src/moscot/__init__.py +++ b/src/moscot/__init__.py @@ -4,9 +4,9 @@ try: md = metadata.metadata(__name__) - __version__ = md.get("version", "") - __author__ = md.get("Author", "") - __maintainer__ = md.get("Maintainer-email", "") + __version__ = md.get("version", "") # type: ignore[attr-defined] + __author__ = md.get("Author", "") # type: ignore[attr-defined] + __maintainer__ = md.get("Maintainer-email", "") # type: ignore[attr-defined] except ImportError: md = None diff --git a/src/moscot/base/output.py b/src/moscot/base/output.py index 9617b8729..3565c5790 100644 --- a/src/moscot/base/output.py +++ b/src/moscot/base/output.py @@ -354,7 +354,7 @@ def transport_matrix(self) -> ArrayLike: # noqa: D102 @property def shape(self) -> tuple[int, int]: # noqa: D102 - return self.transport_matrix.shape # type: ignore[return-value] + return self.transport_matrix.shape def to( # noqa: D102 self, device: Optional[Device_t] = None, dtype: Optional[DTypeLike] = None diff --git a/src/moscot/utils/tagged_array.py b/src/moscot/utils/tagged_array.py index 050573534..5a1ed5781 100644 --- a/src/moscot/utils/tagged_array.py +++ b/src/moscot/utils/tagged_array.py @@ -167,7 +167,7 @@ def shape(self) -> Tuple[int, int]: x, y = self.data_src, (self.data_src if self.data_tgt is None else self.data_tgt) return x.shape[0], y.shape[0] - return self.data_src.shape # type: ignore[return-value] + return self.data_src.shape @property def is_cost_matrix(self) -> bool: