[project] name = "morph" version = "0.1.0" description = "Flow-matching molecular generation and scaffold decoration with a molecular DiT" readme = "README.md" keywords = ["molecular-generation", "flow-matching", "scaffold-decoration"] requires-python = ">=3.11" dependencies = [ "click>=8.3.1", "hydra-core>=1.3.2", "lightning>=2.5.5", "omegaconf>=2.3.0", "numpy>=2.0", "pandas>=2.3.3", "rdkit>=2025.9.1", "scipy>=1.15.0", # Pre-release allowed: the NVIDIA 25.10 container ships a CUDA-enabled # 2.9.0a0 build. Preserve that container build instead of replacing it with # a mismatched PyPI Torch/torchvision pair. "torch>=2.9.0a0, <2.9.1", "torch-geometric>=2.7.0", "torchmetrics>=1.8.0", "wandb>=0.22.2", "posebusters>=0.6.0", "matplotlib>=3.10.8", "lmdb>=2.2.0", "py3dmol>=2.5.4", "ipykernel>=7.2.0", "ase>=3.28.0", ] [dependency-groups] dev = ["pytest>=9.1.1", "ruff>=0.16.5"] [project.optional-dependencies] flash-attn = ["flash-attn>=2.8.3, <2.8.4"] [project.scripts] morph = "morph.cli:cli" [tool.uv.extra-build-dependencies] flash-attn = [{ requirement = "torch", match-runtime = true }] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["src/morph"] [tool.hatch.build.targets.wheel.force-include] "configs" = "morph/configs" [tool.ruff] # Allow lines to be as long as 88. line-length = 88 # Keep attributed third-party implementations close to their upstream sources. extend-exclude = ["src/morph/_vendor"] [tool.ruff.format] docstring-code-format = true # Correctness, readability, and public API documentation. [tool.ruff.lint] # consider selecting "ISC", for implicit string concat # consider selecting "T201", for print in production code select = [ "B", # flake8-bugbear "C4", # flake8-comprehensions "D", # pydocstyle "E", # pycodestyle error "E501", # line too long "EXE", # flake8-executable "F", # pyflakes "FLY", # flynt "I", # isort "ICN", # flake8-import-conventions "PD", # pandas-vet "PERF", # perflint "PIE", # flake8-pie "PL", # pylint "PT", # flake8-pytest-style "PYI", # flakes8-pyi "Q", # flake8-quotes "RSE", # flake8-raise "RUF", # Ruff-specific rules "SIM", # flake8-simplify "SLOT", # flakes8-slot "TCH", # flake8-type-checking "TID", # flake8-tidy-imports "UP", # pyupgrade "W", # pycodestyle warning "W505", # line too long "YTT", # flake8-2020 ] # also consider ignoring "C901", for high mccabe function complexity # also consider ignoring "ERA001", for found commented out code ignore = [ "EXE002", # shebang is not a python interpreter "RUF012", # missing classvar type "RUF013", # Optional prohibited by PEP484 "B006", # Do not use mutable data structures for argument defaults "ANN003", # missing type annotations for kwargs "B019", # Use of functools.lru_cache on methods can lead to memory leaks "C408", # unnecessary-collection-call "COM812", # trailing comma missing "D205", # 1 blank line required between summary line and description "D415", # first line of docstring must end with punctuation "DTZ005", # use of datetime.now() without timezone "E731", # do not assign a lambda expression, use a def "EM", # flake8-errmsg "FBT001", # Boolean positional argument in function "FBT002", # Boolean keyword argument in function "NPY002", # TODO replace legacy np.random.seed "PLR", # pylint refactor "PLW2901", # Outer for loop variable overwritten by inner assignment target "PT006", # pytest-parametrize-names-wrong-type "PT011", # pytest-raises-too-broad "PT013", # pytest-incorrect-pytest-import "PT019", # pytest-fixture-param-without-value "PTH", # prefer Path to os.path "S301", # pickle can be unsafe "S310", # url open functions can be unsafe "TRY003", # long exception messages not defined in the exception class itself "UP015", # unnecessary "r" in open call "D107", # docstring for __init__ "D212", # remove whitespace after opening quotes "D202", # no blank lines after docstring "D301", "D100", "D103", ] pydocstyle.convention = "google" [env] PROJECT_ROOT = "."