Files
foundry/pyproject.toml
lyskov-ai 3ae4ee81e6 chore(mypy): bring models/rfd3 into scope behind an ignore_errors ratchet (#297)
* refactor(mypy): un-ignore 5 easy-tier modules

Fix each module's single pre-existing type error with a pure annotation
or setattr change (no behavior change) and remove it from the
[[tool.mypy.overrides]] ignore_errors list:

- callbacks/train_logging: loss_trackers: dict[str, MeanMetric]
- callbacks/metrics_logging: seen_examples: set[str]
- common: setattr(wrapper, "_has_run", True) for the @wraps wrapper
- hydra/resolvers: attribute_path: str | None (body already guards)
- inference_engines/base: base_overrides: dict[str, Any]

13 modules remain on the ignore list. mypy now type-checks the 5
newly-included modules cleanly.

Co-authored-by: Sergey Lyskov <sergey.lyskov@jhu.edu>

* refactor(mypy): un-ignore 7 medium-tier modules

Resolve the type errors in and remove from the [[tool.mypy.overrides]]
ignore_errors list. Mostly narrowing / annotation fixes; two deliberate
type-honesty fixes flagged below.

- utils/weights: lowercase `any` -> `Any` in _PatternPolicyMixin (4x);
  assert-narrow fallback_policy at the call site (matches get_policy idiom)
- model/layers/blocks: class-level w/b: torch.Tensor for the registered
  buffers (avoids nn.Module's Tensor | Module __getattr__ fallback)
- utils/components: is-None narrowing + tip_names local in get_name_mask's
  TIP branch (exists() can't narrow for mypy); drop orphaned exists import
- utils/logging: str(field) for the tree key; assign to a new hparams local
  rather than reassigning the typed cfg param
- foundry_cli/download_checkpoints: guard on `hasher is not None`;
  total_size = 0.0 for the float accumulation
- training/schedulers: SchedulerConfig.scheduler is now a required field
  (was = None, but documented required and assumed non-None everywhere)
- utils/xpu/xpu_accelerator: name @property -> @staticmethod to match
  lightning's Accelerator ABC

6 hard-tier modules remain on the ignore list.

Co-authored-by: Sergey Lyskov <sergey.lyskov@jhu.edu>

* refactor(mypy): un-ignore metrics/metric module

Fix the 11 type errors in foundry.metrics.metric and remove it from the
[tool.mypy.overrides] ignore_errors list (5 hard-tier modules remain).

- str(name) coercion of DictConfig.items() keys (str|bytes|int|... union)
- exists() -> 'is not None' narrowing; drop orphaned atomworks import
- widen compute_from_kwargs -> dict|list and kwargs_to_compute_args -> dict|None
  to match the actual returns / documented contract (callers already handle them)
- three type: ignore[arg-type] on nested_dict.get/getitem for an upstream
  atomworks annotation bug (param typed dict[tuple,...] but navigated as nested
  dict[str,Any]); warn_unused_ignores will flag them if upstream is fixed

No behavior change. All gates green (ruff, mypy 41 files, pytest 27 passed).

Co-authored-by: Sergey Lyskov <sergey.lyskov@jhu.edu>

* refactor(mypy): un-ignore utils/{ddp,rigid,datasets}

Clear the three remaining foundry.utils.* modules off the mypy ignore_errors list (47 errors: ddp 12, rigid 16, datasets 19). Type-honesty and annotation fixes only, no behavior change: narrow DictConfig|dict params to DictConfig where attribute access requires it (item access kept where a plain-dict default is real), honest int|None / Tensor|None widenings, variable renames to avoid type-reuse, str() coercion of DictConfig keys, the file's own if/elif/else narrowing pattern, and documented type: ignore / cast for genuine torch and atomworks stub limitations. Two hard-tier modules remain (callbacks/health_logging, trainers/fabric).

Co-authored-by: lyskov-ai <277346777+lyskov-ai@users.noreply.github.com>

* refactor(mypy): un-ignore callbacks/health_logging

Clear foundry.callbacks.health_logging off the mypy ignore_errors list
by fixing its 23 type errors (annotation / type-honesty only, no
behavior change):

- import the stdlib 'types' module directly instead of relying on
  'from typing import types' (worked at runtime but fragile/untyped)
- replace 'callable'-used-as-a-type with Mapping[str, Callable[..., Any]]
  on the stat/histogram dict params and Callable[..., bool] | None on the
  filter params; annotate the two MappingProxyType default constants to
  match
- annotate the _hooks / _temp_cache / _cache instance vars
- make implicit-Optional defaults explicit (... | None) on the two
  plot_tensor_* helpers, matching their is-not-None guards
- in plot_tensor_hist, replace two type-changing param reassignments with
  equivalent always-set locals (display_values, step_labels)

Only trainers/fabric remains on the ignore list.

Co-authored-by: lyskov-ai <277346777+lyskov-ai@users.noreply.github.com>

* refactor(mypy): un-ignore trainers/fabric (ratchet complete)

Clear foundry.trainers.fabric (the last and largest module) off the
mypy ignore_errors list and remove the now-empty override block. The
ratchet ignore list is now empty: all of src/foundry + src/foundry_cli
type-checks with no per-module exemptions.

Fixes are annotation / type-honesty only, no behavior change:

- annotate self.state as dict[str, Any] (a heterogeneous, dynamically-
  keyed training-state bag, also merged with arbitrary checkpoint keys);
  this collapses ~69 union-attr/operator/arg-type errors. Also annotate
  default_state and declare _current_train_return (set by subclass
  training_step implementations).
- dataloader types: Fabric.setup_dataloaders is stub-typed to return
  DataLoader | list[DataLoader], so cast its single-loader results to
  DataLoader and change train_loop/validation_loop params from
  _FabricDataLoader to DataLoader (drop the now-unused import).
- precision: widen the param to str | int | None (the body sets it None
  when an XPU plugin takes over), cast to the guarded Literal at the
  XPUMixedPrecision call, and add one documented type: ignore[arg-type]
  where our public API is wider than Fabric's precision Literal.
- narrow the parameter-freezing guard to direct attribute access; type
  get_latest_checkpoint as Path | None (matching its returns) with a
  cast at the single caller; drop a stale type: ignore.

Co-authored-by: lyskov-ai <277346777+lyskov-ai@users.noreply.github.com>

* chore(mypy): bring models/rfd3 into scope behind an ignore_errors ratchet

Add models/rfd3/src/rfd3 to [tool.mypy].files so the rfd3 model package
is type-checked by the standard gate (mypy now covers 99 files: foundry +
rfd3). Seed a fresh [[tool.mypy.overrides]] ignore_errors ratchet listing
the 32 rfd3 modules with pre-existing type errors (194 total), mirroring
the original src/foundry bootstrap; the 26 already-clean rfd3 modules are
type-checked immediately. Modules are cleared from the ratchet one slice
at a time in follow-up work.

Config only, no code changes. rfd3 is an editable install, so imports
resolve without an added mypy_path.

Co-authored-by: lyskov-ai <277346777+lyskov-ai@users.noreply.github.com>

---------

Co-authored-by: Sergey Lyskov <sergey.lyskov@jhu.edu>
Co-authored-by: Hope Woods <hope.woods@omsf.io>
2026-06-03 15:48:39 -05:00

277 lines
7.3 KiB
TOML

[project]
name = "rc-foundry"
dynamic = ["version"]
description = "Shared utilities and training infrastructure for biomolecular structure prediction models."
readme = "README.md"
requires-python = ">=3.12,<3.13"
authors = [
{ name = "Institute for Protein Design", email = "contact@ipd.uw.edu" },
]
license = { file = "LICENSE.md" }
classifiers = [
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"Natural Language :: English",
"Operating System :: POSIX :: Linux",
"Operating System :: MacOS",
"Operating System :: Microsoft :: Windows",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Scientific/Engineering :: Bio-Informatics",
"License :: OSI Approved :: BSD License",
]
dependencies = [
# ... configuration & CLI
"rootutils>=1.0.7,<1.1",
"hydra-core>=1.3.0,<1.4",
"environs>=11.0.0,<12",
# ... logging
"wandb>=0.15.10,<1",
"rich>=13.9.4",
# ... typing & documentation
"jaxtyping>=0.2.17,<1",
"beartype>=0.18.0,<1",
"typer>=0.20.0,<1",
# ... ml tools (core)
"torch>=2.2.0,<3",
"lightning>=2.5.0",
"loralib>=0.1.1",
"einops>=0.8.0,<1",
"einx>=0.1.0,<1",
"opt_einsum>=3.4.0,<4",
"dm-tree>=0.1.6,<1",
"zstandard",
"pandas",
# "biotite",
"atomworks[ml]>=2.1.1",
"ipykernel>=6.31.0",
"assertpy",
"toolz",
]
[project.optional-dependencies]
rfd3na = [
"pydantic>=2.8",
]
rfd3 = [
"pydantic>=2.8",
]
rf3 = [
"cuequivariance_ops_cu12>=0.6.1; sys_platform == 'linux'",
"cuequivariance_ops_torch_cu12>=0.6.1; sys_platform == 'linux'",
"cuequivariance_torch>=0.6.1; sys_platform == 'linux'",
]
all = [
"rc-foundry[rfd3na]",
"rc-foundry[rfd3]",
"rc-foundry[rf3]",
]
dev = [
# Linters & formatters
"assertpy",
"ruff==0.8.3",
"ipdb",
# Type checking
"mypy>=1.13,<2",
# Debugger/interactive
"debugpy>=1.8.5,<2",
"ipykernel>=6.29.4,<7",
# Testing tools
"pytest>=8.2.0,<9", # testing framework
"pytest-testmon>=2.1.1,<3", # run only tests related to changed code
"pytest-xdist>=3.6.1,<4", # run tests in parallel
"pytest-dotenv>=0.5.2,<1", # load environment variables from .env file
"pytest-cov>=4.1.0,<5", # generate coverage report
"pytest-benchmark>=5.0.0,<6", # benchmark tests for speed
"atomworks[ml,dev,openbabel]>=2.1.1",
"pre-commit"
]
[project.scripts]
rf3 = "rf3.cli:app"
rfd3 = "rfd3.cli:app"
rfd3na = "rfd3na.cli:app"
mpnn = "mpnn.inference:main"
foundry = "foundry_cli.download_checkpoints:app"
# Build settings ----------------------------------------------------------------------
[build-system]
requires = [
"hatchling",
"hatch-vcs == 0.4",
]
build-backend = "hatchling.build"
[tool.hatch.version]
source = "vcs"
fallback-version = "0.0.0"
local-scheme = "no-local-version"
[tool.hatch.build.hooks.vcs]
version-file = "src/foundry/version.py"
tag-pattern = "^v(?P<version>.*)$"
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = [
"src/foundry",
"src/foundry_cli",
"models/rf3/src/rf3",
"models/rfd3/src/rfd3",
"models/rfd3na/src/rfd3na",
"models/mpnn/src/mpnn",
]
[tool.hatch.build.targets.wheel.force-include]
"models/rfd3na/configs" = "rfd3na/configs"
"models/rfd3/configs" = "rfd3/configs"
"models/rf3/configs" = "rf3/configs"
# Formatting & linting settings -------------------------------------------------------
[tool.ruff]
line-length = 88
indent-width = 4
target-version = "py310"
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".ipynb_checkpoints",
".mypy_cache",
".nox",
".pants.d",
".pyenv",
".pytest_cache",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
".vscode",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"site-packages",
"env",
".venv",
"venv",
"*.ipynb",
"dev.py",
"archive",
]
[tool.ruff.format]
# Like Black, use double quotes for strings.
quote-style = "double"
# Like Black, indent with spaces, rather than tabs.
indent-style = "space"
# Like Black, respect magic trailing commas.
skip-magic-trailing-comma = false
# Like Black, automatically detect the appropriate line ending.
line-ending = "auto"
# Enable auto-formatting of code examples in docstrings. Markdown,
# reStructuredText code/literal blocks and doctests are all supported.
docstring-code-format = true
docstring-code-line-length = 88
[tool.ruff.lint]
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
# Sort imports
extend-select = ["I", "F401"]
ignore = [
"F722", # for jaxtyping shape annotation
"F821", # temporary to avoid jaxtyping warnings, see: https://github.com/astral-sh/ruff/issues/17386
"E741", # enable us to use variables like "L"
]
[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", "models/rfd3/src/rfd3"]
ignore_missing_imports = true
warn_unused_ignores = true
warn_redundant_casts = true
disallow_untyped_defs = false
check_untyped_defs = false
# rfd3 enablement ratchet. `models/rfd3` was brought into mypy's scope in 0010;
# these modules had pre-existing type errors at that point and are exempted until
# annotated. Fix the errors and remove the entry to enable type-checking for that
# module (same playbook as the now-cleared src/foundry ratchet). Do NOT add modules.
[[tool.mypy.overrides]]
module = [
"rfd3.engine",
"rfd3.inference.datasets",
"rfd3.inference.input_parsing",
"rfd3.inference.legacy_input_parsing",
"rfd3.inference.parsing",
"rfd3.inference.symmetry.symmetry_utils",
"rfd3.metrics.design_metrics",
"rfd3.model.RFD3",
"rfd3.model.inference_sampler",
"rfd3.model.layers.block_utils",
"rfd3.model.layers.chunked_pairwise",
"rfd3.run_inference",
"rfd3.testing.testing_utils",
"rfd3.trainer.dump_validation_structures",
"rfd3.trainer.fabric_trainer",
"rfd3.trainer.rfd3",
"rfd3.trainer.trainer_utils",
"rfd3.transforms.conditioning_base",
"rfd3.transforms.design_transforms",
"rfd3.transforms.dna_crop",
"rfd3.transforms.hbonds",
"rfd3.transforms.hbonds_hbplus",
"rfd3.transforms.ncaa_transforms",
"rfd3.transforms.pipelines",
"rfd3.transforms.ppi_transforms",
"rfd3.transforms.rasa",
"rfd3.transforms.training_conditions",
"rfd3.transforms.util_transforms",
"rfd3.transforms.virtual_atoms",
"rfd3.utils.inference",
"rfd3.utils.io",
"rfd3.utils.vizualize",
]
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",
"hatchling>=1.28.0",
]