diff --git a/.codecov.yml b/.codecov.yml index d61d211..ba90ed6 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -13,4 +13,5 @@ comment: flags: [] paths: [] ignore: - - "openff/pablo/_version.py" + - "examples/" + - "docs/" diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..e5f2055 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + + groups: + dependencies: + patterns: + - "*" diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..75db4ad --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,47 @@ +name: GH Actions Lints +on: + push: + branches: + - main + pull_request: + branches: + - main + +concurrency: + # Specific group naming so CI is only cancelled + # within same PR or on merge to main + group: ${{ github.ref }}-${{ github.head_ref }}-${{ github.workflow }} + cancel-in-progress: true + +defaults: + run: + shell: bash -l {0} + +jobs: + lints: + if: "github.repository == 'openforcefield/openff-pablo'" + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Build information + run: | + uname -a + df -h + ulimit -a + + - uses: prefix-dev/setup-pixi@v0.8.0 + with: + pixi-version: v0.50.0 + activate-environment: lint + + - run: ruff check openff + + - run: pixi r typecheck diff --git a/.github/workflows/gh-ci.yaml b/.github/workflows/tests.yaml similarity index 52% rename from .github/workflows/gh-ci.yaml rename to .github/workflows/tests.yaml index 95483e9..5d20ff4 100644 --- a/.github/workflows/gh-ci.yaml +++ b/.github/workflows/tests.yaml @@ -1,4 +1,4 @@ -name: GH Actions CI +name: GH Actions Tests on: push: branches: @@ -23,14 +23,13 @@ defaults: shell: bash -l {0} jobs: - main-tests: + tests: if: "github.repository == 'openforcefield/openff-pablo'" runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] - python-version: ["3.11"] steps: - uses: actions/checkout@v4 @@ -43,38 +42,18 @@ jobs: df -h ulimit -a - - name: Install environment - uses: mamba-org/setup-micromamba@v2 + - uses: prefix-dev/setup-pixi@v0.8.0 with: - environment-file: devtools/conda-envs/test_env.yaml - create-args: >- - python=${{ matrix.python-version }} + pixi-version: v0.52.0 + environments: test - - name: Install package - run: | - python --version - python -m pip install . - - - name: Python information - run: | - which python - which pip - pip list - micromamba info - micromamba list + - run: pixi r slowtest -v --color=yes --cov=openff/pablo --cov-append --cov-report=xml - - name: Type check - if: runner.os == 'Linux' - run: | - basedpyright openff + - run: pixi r doctest -v --color=yes - - name: Run tests - run: | - pytest -n auto -v --color=yes - - # - name: codecov - # uses: codecov/codecov-action@v3 - # with: - # file: coverage.xml - # name: codecov-${{ matrix.os }}-py${{ matrix.python-version }} - # verbose: True + - name: Codecov + uses: codecov/codecov-action@v5 + with: + files: ./coverage.xml + disable_search: true + fail_ci_if_error: false diff --git a/.gitignore b/.gitignore index df7a46f..79577a4 100644 --- a/.gitignore +++ b/.gitignore @@ -116,4 +116,8 @@ poetry.lock # zed .zed/ +# pixi +.pixi +pixi.lock + .ccd_cache diff --git a/devtools/conda-envs/docs_env.yaml b/devtools/conda-envs/docs_env.yaml deleted file mode 100644 index bcf459b..0000000 --- a/devtools/conda-envs/docs_env.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: pablo-docs -channels: - - conda-forge -dependencies: - # Base depends - - python>=3.11,<3.13 - - pip - - # Documentation - - myst-parser - - sphinx==6.1.2 - - sphinx-notfound-page - - autodoc-pydantic - - sphinx-click - - # Imports - - openff-units - - openff-toolkit>=0.17.0 - - polars - - openmm - - mdtraj - - numpy - - nglview - - typer>=0.14 - - mdanalysis - - rdkit - - pyxdg - - rustworkx - - gemmi - - # Pip-only installs - - pip: - - git+https://github.com/openforcefield/openff-sphinx-theme.git@main diff --git a/devtools/conda-envs/test_env.yaml b/devtools/conda-envs/test_env.yaml deleted file mode 100644 index 534d55e..0000000 --- a/devtools/conda-envs/test_env.yaml +++ /dev/null @@ -1,49 +0,0 @@ -name: pablo-test -channels: - - conda-forge -dependencies: - # Base depends (runtime and imports) - - pip - - python>=3.11 - - openff-toolkit-base>=0.17.0 - - rdkit - - openmm - - pyxdg - - rustworkx - - gemmi - - # Lints - - basedpyright - - ruff - - # Testing - - pytest - - pytest-xdist - - pytest-socket - # - pytest-cov - # - codecov - - # Examples - - jupyterlab>=4 - - ipywidgets>=8 - - jupyterlab_execute_time - - jupyterlab-lsp - - jupyterlab_rise - - jedi-language-server - - jupyterlab_code_formatter - - black - - isort - - snakeviz - - nglview>=3.0.6,<3.1.0 - - pdbfixer - - mdanalysis - - openff-interchange - - ambertools - - numpy - - pymol-open-source - - openff-nagl-base >= 0.5.2 - - openff-nagl-models - - pytorch-cpu >= 2.6 - - - pip: - - git+https://github.com/openforcefield/openff-toolkit.git@main diff --git a/openff/pablo/_utils.py b/openff/pablo/_utils.py index e30f539..429fb76 100644 --- a/openff/pablo/_utils.py +++ b/openff/pablo/_utils.py @@ -18,7 +18,6 @@ import rdkit.Chem.Draw import rdkit.Chem.rdDepictor import rdkit.Geometry -from IPython.display import SVG from openff.toolkit import Molecule from openff.toolkit.topology._mm_molecule import _SimpleMolecule from openff.toolkit.topology.molecule import MoleculeLike @@ -348,7 +347,7 @@ def draw_molecule( emphasize_atoms: list[int] | None = None, explicit_hydrogens: bool | None = None, color_by_element: bool | None = None, -) -> SVG: +): """Draw a molecule Parameters @@ -392,6 +391,7 @@ def draw_molecule( When an atom or bond in highlight_atoms or highlight_bonds is missing from the image, including when it is present in the molecule but hidden. """ + from IPython.display import SVG # We're working in RDKit try: diff --git a/openff/pablo/residue.py b/openff/pablo/residue.py index 51cc4c8..975a77e 100644 --- a/openff/pablo/residue.py +++ b/openff/pablo/residue.py @@ -542,6 +542,41 @@ def from_smiles( virtual_sites Virtual sites expected by the residue. See :py:data:`openff.pablo.ResidueDefinition.virtual_sites` + + Examples + -------- + + To create a ``ResidueDefinition`` for a neutral cysteine residue: + + >>> from openff.pablo.residue import ResidueDefinition + >>> from openff.pablo.chem import DISULFIDE_BOND, PEPTIDE_BOND + >>> + >>> ResidueDefinition.from_smiles( + ... residue_name="CYS", + ... mapped_smiles=r"[N:1]([C@@:2]([C:5]([S:6][H:13])([H:11])[H:12])([C:3]([O:7][H:14])=[O:4])[H:10])([H:8])[H:9]", + ... atom_names={ + ... 1: "N", + ... 2: "CA", + ... 3: "C", + ... 4: "O", + ... 5: "CB", + ... 6: "SG", + ... 7: "OXT", + ... 8: "H", + ... 9: "H2", + ... 10: "HA", + ... 11: "HB2", + ... 12: "HB3", + ... 13: "HG", + ... 14: "HXT", + ... }, + ... leaving_atoms={7, 14, 13, 9}, + ... crosslink=DISULFIDE_BOND, + ... linking_bond=PEPTIDE_BOND, + ... description="CYSTEINE", + ... ) + ResidueDefinition(...) + """ molecule = Molecule.from_mapped_smiles( mapped_smiles, diff --git a/pyproject.toml b/pyproject.toml index 878f132..3b8fb9c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,19 +27,91 @@ dynamic = [ "version", ] -[project.optional-dependencies] -test = [ - "pytest>=6.0", - "pytest-xdist>=2.5", - "pytest-cov>=3.0", -] -doc = [ - "sphinx", -] +[project.urls] +source = "https://github.com/openforcefield/openff-pablo" +documentation = "https://openff-pablo.readthedocs.io" + +[tool.pixi.workspace] +channels = ["conda-forge"] +platforms = ["linux-64", "osx-arm64", "osx-64"] + +[tool.pixi.dependencies] +openff-toolkit-base = ">=0.17.0" +rdkit = "*" +openmm = "*" +numpy = "*" +rustworkx = "*" +pyxdg = "*" +gemmi = "*" + +[tool.pixi.pypi-dependencies] +openff-pablo = { path = ".", editable = true } + +[tool.pixi.feature.doc.dependencies] +myst-parser = "*" +sphinx = "==6.1.2" +sphinx-notfound-page = "*" +autodoc-pydantic = "*" +sphinx-click = "*" + +[tool.pixi.feature.doc.pypi-dependencies] +openff-sphinx-theme = { git = "https://github.com/openforcefield/openff-sphinx-theme.git", rev = "main" } + +[tool.pixi.feature.test.dependencies] +pytest = "*" +pytest-xdist = "*" +pytest-cov = "*" +codecov = "*" + +[tool.pixi.feature.example.dependencies] +jupyterlab = ">=4" +ipywidgets = ">=8" +jupyterlab_execute_time = "*" +jupyterlab-lsp = "*" +jupyterlab_rise = "*" +jedi-language-server = "*" +jupyterlab_code_formatter = "*" +black = "*" +isort = "*" +snakeviz = "*" +nglview = ">=3.0.6,<3.1.0" + +[tool.pixi.feature.lint.dependencies] +basedpyright = "*" +ruff = "*" + +[tool.pixi.environments] +test = { features = ["test", "test-tasks"], solve-group = "default" } +doc = { features = ["doc", "doc-tasks"], solve-group = "default" } +example = { features = ["example", "example-tasks"], solve-group = "default" } +lint = { features = ["lint", "test", "doc", "example"], solve-group = "default" } -# [project.urls] -# source = "https://github.com/openforcefield/openff-pablo" -# documentation = "https://openff-pablo.readthedocs.io" +[tool.pixi.feature.test-tasks.tasks.slowtest] +cmd = "pytest -n auto" +cwd = "." + +[tool.pixi.feature.test-tasks.tasks.test] +cmd = "pytest -n auto -m 'not slow'" +cwd = "." + +[tool.pixi.feature.test-tasks.tasks.doctest] +cmd = "pytest -n auto --doctest-glob 'docs/*.md' --doctest-glob 'docs/*.rst' --doctest-modules --ignore openff/pablo/_tests/ --ignore-glob docs/*.py openff/ docs/" +cwd = "." +[tool.pixi.feature.doc-tasks.tasks.doc] +cmd = "sphinx-build -j auto docs docs/_build/html" +cwd = "." + +[tool.pixi.feature.doc-tasks.tasks.watchdoc] +cmd = "watchexec --on-busy-update restart -w openff -w docs --print-events 'sphinx-build -j auto docs docs/_build/html'" +cwd = "." + +[tool.pixi.feature.example-tasks.tasks.lab] +cmd = "jupyter lab" +cwd = "examples" + +[tool.pixi.feature.lint.tasks.typecheck] +cmd = "basedpyright openff" +cwd = "." [tool.versioningit] default-version = "v0.0.0.dev0+VERSIONMISSING" @@ -60,12 +132,8 @@ include = ["openff.*"] include = ["openff"] exclude = [ ".soap", - "docs", - "examples", - "**/_tests/data", "**/node_modules", "**/__pycache__", - "**/.*", ] "ignore" = [ ".soap", @@ -76,6 +144,8 @@ exclude = [ "**/__pycache__", "**/.*", ] +"venvPath" = ".pixi/envs" +"venv" = "lint" typeCheckingMode = "strict" @@ -101,5 +171,10 @@ namespace-packages = ["openff/pablo/"] ignore = ["E731"] [tool.ruff.lint.isort] -known-third-party = ["openff.toolkit", "openff.utilities", "openff.units"] +known-third-party = [ + "openff.toolkit", + "openff.utilities", + "openff.units", + "openff.utilities", +] known-first-party = ["openff.pablo"] diff --git a/readthedocs.yaml b/readthedocs.yaml index c9ba525..4e3bde5 100644 --- a/readthedocs.yaml +++ b/readthedocs.yaml @@ -5,16 +5,17 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "mambaforge-4.10" - -python: - install: - - method: pip - path: . - -sphinx: - configuration: docs/conf.py - fail_on_warning: true - -conda: - environment: devtools/conda-envs/docs_env.yaml + python: "3.12" + jobs: + create_environment: + - asdf plugin add pixi + - asdf install pixi latest + - asdf global pixi latest + pre_install: + # https://docs.readthedocs.com/platform/stable/build-customization.html#avoid-having-a-dirty-git-index + - git update-index --assume-unchanged pyproject.toml docs/conf.py + install: + - pixi install -e doc + build: + html: + - pixi run -e doc sphinx-build -W -T -b html docs $READTHEDOCS_OUTPUT/html