Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
24b04ab
chore: add ty configuration to pyproject toml file
abelaba Apr 23, 2026
0385e94
chore: remove mypy and type: ignore statements
abelaba Apr 23, 2026
c5e6012
chore: add ty: ignore statements
abelaba Apr 23, 2026
9f82788
chore: remove sqlalchemy stubs
abelaba Apr 23, 2026
63a1f14
chore: remove mypy comments and add replace mypy with on contribution…
abelaba Apr 23, 2026
ac50ca9
Merge remote-tracking branch 'upstream/main' into mypy-ty-migration
abelaba Jul 13, 2026
ba2d960
chore: add ty ignore comments
abelaba Jul 13, 2026
dd45ad2
bump ty to latest version
abelaba Jul 13, 2026
a5064b5
Merge remote-tracking branch 'upstream/main' into mypy-ty-migration
janosg Sep 25, 2026
23ef5a4
Fix bugs hidden by ty ignores and accept Sequence inputs
janosg Sep 25, 2026
584fd44
Reinstall optimagic in algo selection hook env on every run; note ty …
janosg Sep 25, 2026
c0d945b
Narrow optional results in tests instead of ignoring ty errors
janosg Sep 25, 2026
8d62241
Fix small type errors instead of ignoring them
janosg Sep 25, 2026
9a51e4f
Declare __algo_info__ and _problem_type instead of ignoring ty errors
janosg Sep 25, 2026
eb1a34e
Fix criterion_plot crash when stacking exploration samples from a dat…
janosg Sep 28, 2026
f14abbd
Type jac=True and derivative sequences; drop None from multistart docs
janosg Sep 28, 2026
711f699
Enforce all ruff ANN rules and prune stale annotation exemptions
janosg Sep 29, 2026
be2e905
Merge branch 'main' into mypy-ty-migration
janosg Sep 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ jobs:
run: >-
pixi run -e tests-linux-py314
python -m doctest -v docs/source/how_to/how_to_constraints.md
run-mypy:
name: Run mypy
run-ty:
name: Run ty
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
Expand All @@ -145,6 +145,6 @@ jobs:
cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }}
frozen: true
environments: type-checking
- name: Run mypy
- name: Run ty
shell: bash -el {0}
run: pixi run -e type-checking mypy
run: pixi run -e type-checking ty --output-format github
32 changes: 16 additions & 16 deletions .tools/create_algo_selection_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,62 +104,62 @@ def _get_all_algorithms(modules: list[ModuleType]) -> dict[str, Type[Algorithm]]
def _get_algorithms_in_module(module: ModuleType) -> dict[str, Type[Algorithm]]:
"""Collect all algorithms in a single module."""
candidate_dict = dict(inspect.getmembers(module, inspect.isclass))
candidate_dict = {
k: v for k, v in candidate_dict.items() if hasattr(v, "__algo_info__")
}
algos = {}
for candidate in candidate_dict.values():
name = candidate.algo_info.name
if issubclass(candidate, Algorithm) and candidate is not Algorithm:
algos[name] = candidate
if (
issubclass(candidate, Algorithm)
and candidate is not Algorithm
and candidate.__algo_info__ is not None
):
algos[candidate.__algo_info__.name] = candidate
return algos


# ======================================================================================
# Functions to filter algorithms by selectors
# ======================================================================================
def _is_gradient_based(algo: Type[Algorithm]) -> bool:
return algo.algo_info.needs_jac # type: ignore
return algo.algo_info.needs_jac


def _is_gradient_free(algo: Type[Algorithm]) -> bool:
return not _is_gradient_based(algo)


def _is_global(algo: Type[Algorithm]) -> bool:
return algo.algo_info.is_global # type: ignore
return algo.algo_info.is_global


def _is_local(algo: Type[Algorithm]) -> bool:
return not _is_global(algo)


def _is_bounded(algo: Type[Algorithm]) -> bool:
return algo.algo_info.supports_bounds # type: ignore
return algo.algo_info.supports_bounds


def _is_linear_constrained(algo: Type[Algorithm]) -> bool:
return algo.algo_info.supports_linear_constraints # type: ignore
return algo.algo_info.supports_linear_constraints


def _is_nonlinear_constrained(algo: Type[Algorithm]) -> bool:
return algo.algo_info.supports_nonlinear_constraints # type: ignore
return algo.algo_info.supports_nonlinear_constraints


def _is_scalar(algo: Type[Algorithm]) -> bool:
return algo.algo_info.solver_type == AggregationLevel.SCALAR # type: ignore
return algo.algo_info.solver_type == AggregationLevel.SCALAR


def _is_least_squares(algo: Type[Algorithm]) -> bool:
return algo.algo_info.solver_type == AggregationLevel.LEAST_SQUARES # type: ignore
return algo.algo_info.solver_type == AggregationLevel.LEAST_SQUARES


def _is_likelihood(algo: Type[Algorithm]) -> bool:
return algo.algo_info.solver_type == AggregationLevel.LIKELIHOOD # type: ignore
return algo.algo_info.solver_type == AggregationLevel.LIKELIHOOD


def _is_parallel(algo: Type[Algorithm]) -> bool:
return algo.algo_info.supports_parallelism # type: ignore
return algo.algo_info.supports_parallelism


def _get_filters() -> dict[str, Callable[[Type[Algorithm]], bool]]:
Expand Down Expand Up @@ -385,7 +385,7 @@ def _all(self) -> list[Type[Algorithm]]:
def _available(self) -> list[Type[Algorithm]]:
_all = self._all()
return [
a for a in _all if a.algo_info.is_available # type: ignore
a for a in _all if a.algo_info.is_available
]

@property
Expand Down
10 changes: 5 additions & 5 deletions .tools/update_algo_selection_hook.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python
import importlib.util
import subprocess
import sys
from pathlib import Path
Expand All @@ -15,13 +14,14 @@ def run(cmd: list[str], **kwargs: Any) -> None:
subprocess.check_call(cmd, cwd=ROOT, **kwargs)


def ensure_optimagic_is_locally_installed() -> None:
if importlib.util.find_spec("optimagic") is None:
run(["uv", "pip", "install", "--python", sys.executable, "-e", "."])
def install_optimagic_locally() -> None:
# Always (re)install so that dependencies added after the hook environment was
# created are picked up. This is fast if nothing changed.
run(["uv", "pip", "install", "--quiet", "--python", sys.executable, "-e", "."])


def main() -> int:
ensure_optimagic_is_locally_installed()
install_optimagic_locally()
run(PYTHON + [".tools/create_algo_selection_code.py"])

ruff_args = [
Expand Down
7 changes: 7 additions & 0 deletions docs/source/development/ep-02-typing.md
Original file line number Diff line number Diff line change
Expand Up @@ -1653,6 +1653,13 @@ access to currently internal objects such as the MSM objective function.

We choose mypy as static type checker and run it as part of our continuous integration.

```{note}
We have since replaced mypy by [ty](https://docs.astral.sh/ty/). ty is much faster and
also checks the bodies of unannotated functions and our tests. Its configuration lives
in the `[tool.ty]` section of `pyproject.toml`. The mypy settings below are kept for
reference.
```

Once this enhancement proposal is fully implemented, we want to use the following
settings:

Expand Down
2 changes: 1 addition & 1 deletion docs/source/development/how_to_contribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ For regular contributors: **Clone** the [repository](https://github.com/optimagi
use:

```console
$ pixi run mypy
$ pixi run ty
```

To see all available pixi tasks, run:
Expand Down
Loading
Loading