mirror of
https://github.com/RosettaCommons/foundry.git
synced 2026-06-04 13:24:22 +08:00
test: bootstrap mypy + pytest + coverage CI gates (#284)
* test: bootstrap mypy + pytest + coverage CI gates Wire up the tooling the upcoming test/annotation/refactor work depends on: - Add mypy>=1.13 to [dev] and a lenient [tool.mypy] config scoped to src/foundry + src/foundry_cli (ignore_missing_imports, no disallow_untyped_defs). The 14 modules with pre-existing type errors are pinned via [[tool.mypy.overrides]] ignore_errors=true and listed as the ratchet target — fix and remove, never add. - Add [tool.pytest.ini_options] (testpaths=["tests"], --strict-markers --strict-config) and [tool.coverage.*] (source = src/foundry + src/foundry_cli, branch = true) for opt-in gap finding. - Add .github/workflows/test.yaml with mypy and pytest jobs running on the same triggers as lint_production.yaml. Top-level tests/ only; per-model tests under models/*/tests/ may require GPU and checkpoints and stay out of CI for now. Co-authored-by: Sergey Lyskov <sergey.lyskov@jhu.edu> * test(mypy): extend ignore list with 4 modules CI surfaced Local sanity-check ran mypy without foundry installed, so torch / lightning resolved to `Any` and errors that depend on knowing those types stayed invisible. First CI run installed the full deps and surfaced 6 errors in 4 additional modules: foundry.model.layers.blocks foundry.training.schedulers foundry.utils.logging foundry.utils.xpu.xpu_accelerator Same ratchet contract as the original 14: do not add, only remove (after fixing the errors and removing `ignore_errors = true`). Co-authored-by: Sergey Lyskov <sergey.lyskov@jhu.edu> * style: ruff format 2 pre-existing files unrelated to bootstrap These files have been failing `ruff format --check` on production HEAD (merged via #275 and #281 without a pre-commit run). They block the existing `lint_production` workflow on every PR, including this bootstrap. Strictly out of scope for 0001 — kept in a separate commit so it can be cherry-picked or reverted cleanly. models/rfd3/src/rfd3/inference/input_parsing.py models/rfd3/tests/test_partial_diffusion.py No semantic changes — `ruff format` output only. Co-authored-by: Sergey Lyskov <sergey.lyskov@jhu.edu> * ci: run test workflow on all pull requests Drop the base-branch filter on the pull_request trigger so PRs targeting stacked task branches are gated too, not only PRs into the mainline branches. Co-authored-by: Sergey Lyskov <sergey.lyskov@jhu.edu> * Update test.yaml to remove pull_request_target Removed pull_request_target event from workflow. --------- Co-authored-by: Sergey Lyskov <sergey.lyskov@jhu.edu> Co-authored-by: Sergey Lyskov <3302736+lyskov@users.noreply.github.com>
This commit is contained in:
49
.github/workflows/test.yaml
vendored
Normal file
49
.github/workflows/test.yaml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, production, wip/for-release, wip/remove-chemdata]
|
||||
# Run on every pull request regardless of base branch, so stacked task-branch PRs
|
||||
# are gated too (not just PRs targeting the mainline branches above).
|
||||
pull_request:
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
mypy:
|
||||
name: mypy (type check)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
cache: 'pip'
|
||||
cache-dependency-path: pyproject.toml
|
||||
- name: Install package + dev extras
|
||||
# `[dev]` pulls in mypy and the dev tooling. The package itself is needed
|
||||
# so mypy can resolve `import foundry.*` against the installed source.
|
||||
run: pip install -e ".[dev]"
|
||||
- name: mypy
|
||||
run: mypy
|
||||
|
||||
pytest:
|
||||
name: pytest (top-level tests/)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
cache: 'pip'
|
||||
cache-dependency-path: pyproject.toml
|
||||
- name: Install package + dev extras
|
||||
run: pip install -e ".[dev]"
|
||||
- name: pytest
|
||||
# Top-level tests/ only. Per-model tests under models/*/tests/ may require
|
||||
# GPU and downloaded checkpoints and are not yet wired into CI.
|
||||
run: pytest
|
||||
@@ -778,9 +778,7 @@ class DesignInputSpecification(BaseModel):
|
||||
if is_motif.any() and (~is_motif).any():
|
||||
diffused_coord = atom_array.coord[~is_motif]
|
||||
finite = np.isfinite(diffused_coord).all(axis=-1)
|
||||
center = np.nan_to_num(
|
||||
np.mean(diffused_coord[finite], axis=0)
|
||||
)
|
||||
center = np.nan_to_num(np.mean(diffused_coord[finite], axis=0))
|
||||
atom_array.coord = atom_array.coord - center
|
||||
logger.info(
|
||||
f"Partial diffusion: centering on diffused-region COM ({center})."
|
||||
|
||||
@@ -58,12 +58,12 @@ def test_partial_diffusion_respects_ori_token():
|
||||
delta = aa_shift.coord.mean(axis=0) - aa_default.coord.mean(axis=0)
|
||||
# Coords are translated by -ori_token at parse time, so the post-parse
|
||||
# whole-structure mean must drop by ~50 Å on x.
|
||||
assert delta[0] == pytest.approx(-50.0, abs=1.5), (
|
||||
f"ori_token=[50,0,0] should shift coords by -50 in x; got delta={delta}"
|
||||
)
|
||||
assert abs(delta[1]) < 1.5 and abs(delta[2]) < 1.5, (
|
||||
f"ori_token=[50,0,0] should not move y/z; got delta={delta}"
|
||||
)
|
||||
assert delta[0] == pytest.approx(
|
||||
-50.0, abs=1.5
|
||||
), f"ori_token=[50,0,0] should shift coords by -50 in x; got delta={delta}"
|
||||
assert (
|
||||
abs(delta[1]) < 1.5 and abs(delta[2]) < 1.5
|
||||
), f"ori_token=[50,0,0] should not move y/z; got delta={delta}"
|
||||
|
||||
|
||||
@pytest.mark.fast
|
||||
@@ -86,9 +86,9 @@ def test_partial_diffusion_defaults_to_diffused_region_com():
|
||||
pytest.skip("Test fixture has no separable motif/diffused split")
|
||||
|
||||
diffused_com = aa.coord[~is_motif].mean(axis=0)
|
||||
assert np.allclose(diffused_com, 0, atol=1e-3), (
|
||||
f"diffused-region COM should be at origin after centering; got {diffused_com}"
|
||||
)
|
||||
assert np.allclose(
|
||||
diffused_com, 0, atol=1e-3
|
||||
), f"diffused-region COM should be at origin after centering; got {diffused_com}"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -73,6 +73,8 @@ dev = [
|
||||
"assertpy",
|
||||
"ruff==0.8.3",
|
||||
"ipdb",
|
||||
# Type checking
|
||||
"mypy>=1.13,<2",
|
||||
# Debugger/interactive
|
||||
"debugpy>=1.8.5,<2",
|
||||
"ipykernel>=6.29.4,<7",
|
||||
@@ -201,6 +203,57 @@ ignore = [
|
||||
[tool.pyright]
|
||||
typeCheckingMode = "off"
|
||||
|
||||
# Type checking ----------------------------------------------------------------------
|
||||
# Lenient baseline so the existing largely-unannotated code does not fail the gate.
|
||||
# Per-module strictness is ratcheted up via [tool.mypy.overrides] as annotations land.
|
||||
[tool.mypy]
|
||||
python_version = "3.12"
|
||||
files = ["src/foundry", "src/foundry_cli"]
|
||||
ignore_missing_imports = true
|
||||
warn_unused_ignores = true
|
||||
warn_redundant_casts = true
|
||||
disallow_untyped_defs = false
|
||||
check_untyped_defs = false
|
||||
|
||||
# Modules with pre-existing type errors at bootstrap time. These are the track-1
|
||||
# ratchet list — fix the errors and remove the entry to enable type-checking for
|
||||
# that module. Do NOT add modules to this list; only remove from it.
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
"foundry.callbacks.health_logging",
|
||||
"foundry.callbacks.metrics_logging",
|
||||
"foundry.callbacks.train_logging",
|
||||
"foundry.common",
|
||||
"foundry.hydra.resolvers",
|
||||
"foundry.inference_engines.base",
|
||||
"foundry.metrics.metric",
|
||||
"foundry.model.layers.blocks",
|
||||
"foundry.trainers.fabric",
|
||||
"foundry.training.schedulers",
|
||||
"foundry.utils.components",
|
||||
"foundry.utils.datasets",
|
||||
"foundry.utils.ddp",
|
||||
"foundry.utils.logging",
|
||||
"foundry.utils.rigid",
|
||||
"foundry.utils.weights",
|
||||
"foundry.utils.xpu.xpu_accelerator",
|
||||
"foundry_cli.download_checkpoints",
|
||||
]
|
||||
ignore_errors = true
|
||||
|
||||
# Testing ----------------------------------------------------------------------------
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
addopts = "-ra --strict-markers --strict-config"
|
||||
|
||||
[tool.coverage.run]
|
||||
source = ["src/foundry", "src/foundry_cli"]
|
||||
branch = true
|
||||
|
||||
[tool.coverage.report]
|
||||
show_missing = true
|
||||
skip_covered = false
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"build>=1.3.0",
|
||||
|
||||
Reference in New Issue
Block a user