From a08f3c68553cbf5fc28617bfec90210996682ee2 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Thu, 29 Jan 2026 11:24:47 +0100 Subject: [PATCH 1/7] add api docs --- docs/.DS_Store | Bin 0 -> 6148 bytes docs/ExampleNotebooks | 1 + docs/Makefile | 20 + docs/_ext/.sass.py.swp | Bin 0 -> 12288 bytes docs/_ext/sass.py | 86 ++++ docs/_sass/deflist-flowchart.scss | 397 ++++++++++++++++++ docs/_static/API.svg | 1 + docs/_static/CLI.svg | 1 + docs/_static/Cookbook.svg | 1 + docs/_static/Download.svg | 1 + docs/_static/OFE-color-icon.svg | 12 + docs/_static/Rocket.svg | 1 + docs/_static/Showcase.svg | 75 ++++ docs/_static/Tutorial.svg | 1 + docs/_static/UserGuide.svg | 1 + docs/_templates/autosummary/base.rst | 5 + docs/_templates/autosummary/class.rst | 5 + docs/conf.py | 254 +++++++++++ docs/environment.yaml | 36 ++ docs/index.rst | 26 ++ .../api/generated/openfe_analysis.rst | 37 ++ .../api/generated/openfe_analysis.utils.rst | 29 ++ docs/reference/api/index.rst | 10 + docs/reference/index.rst | 9 + src/openfe_analysis/rmsd.py | 38 +- 25 files changed, 1039 insertions(+), 8 deletions(-) create mode 100644 docs/.DS_Store create mode 160000 docs/ExampleNotebooks create mode 100644 docs/Makefile create mode 100644 docs/_ext/.sass.py.swp create mode 100644 docs/_ext/sass.py create mode 100644 docs/_sass/deflist-flowchart.scss create mode 100644 docs/_static/API.svg create mode 100644 docs/_static/CLI.svg create mode 100644 docs/_static/Cookbook.svg create mode 100644 docs/_static/Download.svg create mode 100644 docs/_static/OFE-color-icon.svg create mode 100644 docs/_static/Rocket.svg create mode 100644 docs/_static/Showcase.svg create mode 100644 docs/_static/Tutorial.svg create mode 100644 docs/_static/UserGuide.svg create mode 100644 docs/_templates/autosummary/base.rst create mode 100644 docs/_templates/autosummary/class.rst create mode 100644 docs/conf.py create mode 100644 docs/environment.yaml create mode 100644 docs/index.rst create mode 100644 docs/reference/api/generated/openfe_analysis.rst create mode 100644 docs/reference/api/generated/openfe_analysis.utils.rst create mode 100644 docs/reference/api/index.rst create mode 100644 docs/reference/index.rst diff --git a/docs/.DS_Store b/docs/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..88fb60ff3e07be0388022b1add1d07525b11792d GIT binary patch literal 6148 zcmeHK%}T>S5Z-NTn^J@v6nYGJEtpm*6fdFH7cim+m6(vC!I&*gVh*K{v%Zi|;`2DO zyEy~{-bCyS?0&QJvzz%K`@GcX4{{<)$Z(ddq&R~829dzDBR4?@^tR6Z*g=bL>yGQ zA6!Sv!ZQ!fMUweZvRuoAC|p9w-A$B)qL_<32~(NtDu>ZG`kp!5Y$mhm$U3#h+mW@I zO>EFlrrT}bI6OK&yY!ypmqffNA~|p_WnW_j@1WFbdUe-HERsjCS2rh3JQvlq#+s)ifcf&l= zXWVYOd>tEld~PCOGtFcY%4U%Is_DsP-Bdy;Hyi##1UqCIuncUSfgS9?{(aNrzsK3l zAJ{d&^-$K+GGH073|Iy%1C{~HfMvikU>UgS7|_`^_8PLjrONzd^}cQ0dv$ByECZGS z%YbFTGGH073|Iy%1C{~HfMvikU>Udx84v+uuiwVlueT$4{QrOS_y1oz8M_923VZ^5 z0K5-e0wnM}@F4KxeT;nuya!wc-UiMA5|{-J0Z#!tfh#*0`vUkJco%pFxC}f8><4xM z+kv0&W$bI^j{{flX6y&xd*A}_7H}ST1=s^z zxr?zcfs4QyU>-OCJOuo?ow09#%fNZy6!0|A0uBPZfro+L?quvI;49!w;27{IaPFb&!lclL5 z3xt+|)8O4AiYdHOo=S_{m#V(%B7(q!TNw4cB@q|0<`}!Q&{?59rH3)5FG*nn(oscW#*43!?nLx~bgXid&TUaS=!_6S_~SF0>~TjniIF z=58RnMXwe*^D0Vue8uw;F_4~jwqn6?9K+~wY)Qt$BJnl$jE8B?bw5%ZzrvFVZKG?< z$UKlCS7ctp&b9dQtRE%I^%kVdt1D32E!CspU-MP9Z8S_{keE!gJ6Hr;HMtxq?WKz| zMq<1iQ|7MRDDqnSM0XQQpIJ~kuYtrWY`x8&n6y~aEjf=1WM=$k(hNaC*bEc~0`%G# z7Q<(_`C%eSD~e@}QCPYvV;V;~rZfxzW%k4=o;QdBB*-h3xu~*%s)0ZXv4_u+<~dCh zBDgY7$J0dgs$w90cZ24QeH9v}(6LwD(RP)YOz;OI!(di7yPi>M>nE6SXqzb}6XR8=zML>Coa%e-Q%W1*uZ z>FJb|NLkh0(~<6bstChqx#qao&@unD4O(FoOU6o;0-(FK(e)cqjWDu`LLQ;0l@^IF ziB9UGtD2}Rp|;33Op?opu^EyoOpCniAI2LZL*9)In~&#aL5w1dwqVl;6m-)NBTkGK z)=6@;gYcEZR0=2;WfGxe%3BDSY-=>TNfd$@GXzaZs;eh%q&(48 zXI)S3$-kD4Z58+G+MV_}{SxH3K2Ep!y~Xpp739yv{n zqv}SrHZn7XJXV7f_Rv@y`A|Aeh$?K^{aJNK-Ka`I4>Rfq)xc<-4Q>`%M$NFWIO>jU zXr1Lis>YuYA&k+U^q3(tOC~(jW>Wi4;@F z;7}&8V!q#r|6;;44Oh~8k&klw^=FzY2sMxPMLk$ I Path: + if src is None: + target = Path(conf_dir) + else: + target = Path(src) + if not target.is_absolute(): + target = Path(conf_dir) / target + return target + + +def get_targets(app: Sphinx) -> dict[Path, Path]: + src_dir = configure_path(app.confdir, app.config.sass_src_dir) + dst_dir = configure_path(app.outdir, app.config.sass_out_dir) + + if isinstance(app.config.sass_targets, dict): + targets = app.config.sass_targets + else: + targets = { + path: path.relative_to(src_dir).with_suffix(".css") + for path in src_dir.glob("**/[!_]*.s[ca]ss") + } + + return {src_dir / src: dst_dir / dst for src, dst in targets.items()} + + +def build_sass_sources(app: Sphinx, env: BuildEnvironment): + logger.debug("Building stylesheet files") + include_paths = [str(p) for p in app.config.sass_include_paths] + targets = get_targets(app) + output_style = app.config.sass_output_style + # Build css files + for src, dst in targets.items(): + content = src.read_text() + css = sass.compile( + string=content, + output_style=output_style, + include_paths=[str(src.parent)] + include_paths, + ) + dst.parent.mkdir(exist_ok=True, parents=True) + dst.write_text(css) + + +def setup(app: Sphinx): + """ + Setup function for this extension. + """ + logger.debug(f"Using {__name__}") + app.add_config_value("sass_include_paths", [], "html") + app.add_config_value("sass_src_dir", None, "html") + app.add_config_value("sass_out_dir", None, "html") + app.add_config_value("sass_targets", None, "html") + app.add_config_value("sass_output_style", "compressed", "html") + app.connect("env-updated", build_sass_sources) + + return { + "version": "0.3.4ofe", + "parallel_read_safe": True, + "parallel_write_safe": True, + } diff --git a/docs/_sass/deflist-flowchart.scss b/docs/_sass/deflist-flowchart.scss new file mode 100644 index 0000000..b65f54b --- /dev/null +++ b/docs/_sass/deflist-flowchart.scss @@ -0,0 +1,397 @@ +:root { + --arrow-thickness: 4px; + --arrow-head-size: 7px; + --arrow-length: 2em; + --arrow-multiple-gap: 20px; + --arrow-color: var(--pst-color-text-muted); + --arrow-fade-dist: 0px; + --flowchart-def-bg-color: var(--pst-color-surface); + --flowchart-bg-color: var(--pst-color-background); + --flowchart-def-border-color: var(--pst-color-border); + --flowchart-unit-width: 45px; + --flowchart-spacing: 0.5rem; + --flowchart-column-gap: calc(1.5 * var(--flowchart-spacing)); + --flowchart-top-label-space: 26px; +} +.arrow.thick { + --arrow-thickness: 6px; + --arrow-head-size: 10px; +} + +.deflist-flowchart ul, +ul.deflist-flowchart { + display: flex; + flex-direction: column; + justify-content: space-between; + height: 100%; + grid-column-gap: var(--flowchart-column-gap); + margin: 0; + padding: 0; +} + +.deflist-flowchart { + margin: 1em 0; + + p:first-child { + margin-top: 0; + } + + p:last-child { + margin-bottom: 0; + } + + li, + li ul + { + margin: 0; + padding: 0; + } + + li:empty:not([class]) + { + display: None; + } + + li { + list-style: none; + } + + .arrow-down::after, + .arrow-up::after, + .arrow-multiple.arrow-down::before, + .arrow-multiple.arrow-up::before, + .arrow-cycle::after, + .arrow-cycle::before { + content: ""; + } + + .arrow-down, + .arrow-up, + .arrow-cycle + { + --arrow-head-size-clamped: calc(min(var(--arrow-head-size), var(--arrow-length) / 2)); + + display: flex; + justify-content: center; + align-items: center; + flex-grow: 1; + min-height: var(--arrow-length); + width: 100%; + margin: calc(2 * var(--flowchart-spacing)) auto; + position: relative; + z-index: 1; + padding: calc(var(--arrow-length) / 4) 0; + + &::before, &::after { + --actual-arrow-length: max(var(--arrow-length), 100%); + --arrow-tail-gradient: + linear-gradient( + 45deg, + transparent calc(50% - var(--arrow-thickness)/2), + var(--arrow-color) calc(50% - var(--arrow-thickness)/2), + var(--arrow-color) calc(50% + var(--arrow-thickness)/2), + transparent calc(50% + var(--arrow-thickness)/2) + ); + --arrow-head-gradient: + linear-gradient( + -45deg, + var(--arrow-color) var(--arrow-head-size-clamped), + transparent var(--arrow-head-size-clamped) + ); + height: calc(var(--actual-arrow-length)/1.4142); + width: auto; + aspect-ratio: 1; + padding: 0; + display: inline-block; + transform: rotate(45deg); + background-image: + var(--arrow-tail-gradient), + var(--arrow-head-gradient); + position: absolute; + top: 0; + left: 50%; + transform-origin: 0 0; + z-index: -1; + } + + &.arrow-tail { + &::before, &::after { + background-image: + var(--arrow-tail-gradient); + } + } + + > p { + background: linear-gradient( + transparent, + var(--flowchart-bg-color) var(--arrow-fade-dist), + var(--flowchart-bg-color) calc(100% - var(--arrow-fade-dist)), + transparent, + ); + line-height: 1.5; + z-index: 10; + } + } + + .arrow-down:not(.arrow-tail), + .arrow-cycle { + padding-bottom: calc(var(--arrow-head-size-clamped) + var(--arrow-length) / 4); + } + + .arrow-up:not(.arrow-tail), + .arrow-cycle { + padding-top: calc(var(--arrow-head-size-clamped) + var(--arrow-length) / 4); + } + + .arrow-cycle, .arrow-multiple { + &::after { + translate: calc(0.5 * var(--arrow-multiple-gap)) 0; + } + &::before { + translate: calc(-0.5 * var(--arrow-multiple-gap)) 0; + } + } + + .arrow-up::after, + .arrow-multiple.arrow-up::before, + .arrow-cycle::before + { + transform: rotate(-135deg); + translate: 0 calc(var(--actual-arrow-length) + 2 * var(--flowchart-spacing) + var(--arrow-head-size-clamped) / 2); + } + + .arrow-cycle::before { + translate: + calc(-0.5 * var(--arrow-multiple-gap)) + 140%; + } + + .arrow-aside { + margin-left: calc(8 * var(--arrow-head-size-clamped)); + &::after { + left: calc(-4 * var(--arrow-head-size-clamped)); + } + } + + .arrow-multiple-combine { + &::before { + content: ""; + width: var(--arrow-multiple-gap); + border: var(--arrow-thickness) solid var(--arrow-color); + height: calc(var(--arrow-length) / 2); + background: var(--flowchart-bg-color); + transform: none; + left: auto; + z-index: 2; + } + + &.arrow-down { + padding-top: calc(0.75 * var(--arrow-length) - var(--arrow-head-size-clamped) / 2); + padding-bottom: calc(0.5 * var(--arrow-head-size-clamped) + 0.25 * var(--arrow-length)); + &::before { + border-top: 1px solid var(--flowchart-bg-color); + } + } + + &.arrow-up { + &::before { + border-bottom: 1px solid var(--flowchart-bg-color); + top: auto; + bottom: -1px; + } + } + } + + .arrow-tail { + &.arrow-down { + margin-bottom: 0; + } + &.arrow-up { + margin-top: 0; + } + } + + .arrow-head { + &.arrow-up { + margin-bottom: 0; + } + &.arrow-down { + margin-top: 0; + } + } + + .arrow-combine, .arrow-combine-left, .arrow-combine-right { + &.arrow-down.arrow-tail, &.arrow-up.arrow-head { + --arrow-combine-gradient-angle: 0deg; + padding-bottom: calc(0.5 * var(--arrow-thickness)); + margin-bottom: calc(-0.5 * var(--arrow-thickness)); + } + &.arrow-up.arrow-tail, &.arrow-down.arrow-head { + --arrow-combine-gradient-angle: 180deg; + padding-top: calc(0.5 * var(--arrow-thickness)); + margin-top: calc(-0.5 * var(--arrow-thickness)); + } + background-image: + linear-gradient( + var(--arrow-combine-gradient-angle), + var(--arrow-color) var(--arrow-thickness), + transparent var(--arrow-thickness) + ); + background-repeat: no-repeat; + + width: calc(max(100% + 2 * var(--flowchart-column-gap), var(--flowchart-unit-width))); + margin-left: calc(-1 * var(--flowchart-column-gap)); + + &.arrow-combine-left, &.arrow-combine-right { + background-size: 50%; + + &.arrow-multiple { + background-size: calc(50% + 0.5 * var(--arrow-multiple-gap)); + } + } + + &.arrow-combine-right { + background-position-x: 100%; + } + } + + > ul > li { + &.arrow-down, + &.arrow-up, + &.arrow-cycle { + width: calc(100% - var(--flowchart-top-label-space)); + margin-left: 0; + } + } + + dl { + display: flex; + flex-direction: row-reverse; + margin: 0; + padding: 0 var(--flowchart-spacing); + } + dt { + display: inline-block; + writing-mode: vertical-rl; + margin-top: .25rem; + flex-grow: 0; + width: var(--flowchart-top-label-space); + font-size: 1.1em; + } + dd { + text-align: center; + position: relative; + border: 1px solid var(--flowchart-def-border-color); + border-radius: .25rem; + margin: 0; + display: inline-block; + flex-grow: 1; + container-type: inline-size; + container-name: flowchart; + overflow-x: auto; + } + + dd dl { + background-color: var(--flowchart-def-bg-color); + border-radius: 4px; + box-shadow: 0 6px 10px 0 rgba(0,0,0,0.14), + 0 1px 18px 0 rgba(0,0,0,0.12), + 0 3px 5px -1px rgba(0,0,0,0.4); + display: block; + margin: 0 auto; + padding: calc(var(--flowchart-spacing) / 2); + max-width: calc(100cqw - 2 * var(--flowchart-spacing)); + min-width: calc(2 * var(--flowchart-unit-width) + var(--flowchart-column-gap)); + } + dd dt { + writing-mode: horizontal-tb; + display: block; + margin-top: 0; + width: unset; + font-size: unset; + } + dd dd { + border: none; + display: block; + container-type: unset; + overflow-x: unset; + padding: calc(var(--flowchart-spacing) / 2); + } + + dd > ul { + width: fit-content; + padding: var(--flowchart-spacing); + margin: 0 auto; + overflow: hidden; + } + + dd dd > ul { + min-width: unset; + padding: 0; + margin: 0; + } + + dl a, a { + font-weight: bold; + } + + div.flowchart-sidebyside > ul:only-child { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: space-between; + } + + .flowchart-spacer { + height: 100%; + flex-shrink: 9999; + min-height: calc(2 * var(--flowchart-spacing)) + } + + .width-1 { + width: calc(var(--flowchart-unit-width)); + } + .width-2 { + width: calc(2 * var(--flowchart-unit-width) + var(--flowchart-column-gap)); + } + .width-3 { + width: calc(3 * var(--flowchart-unit-width) + 2 * var(--flowchart-column-gap)); + } + .width-4 { + width: calc(4 * var(--flowchart-unit-width) + 3 * var(--flowchart-column-gap)); + } + .width-5 { + width: calc(5 * var(--flowchart-unit-width) + 4 * var(--flowchart-column-gap)); + } + .width-6 { + width: calc(6 * var(--flowchart-unit-width) + 5 * var(--flowchart-column-gap)); + } + .width-7 { + width: calc(7 * var(--flowchart-unit-width) + 6 * var(--flowchart-column-gap)); + } + .width-8 { + width: calc(8 * var(--flowchart-unit-width) + 7 * var(--flowchart-column-gap)); + } + .width-9 { + width: calc(9 * var(--flowchart-unit-width) + 8 * var(--flowchart-column-gap)); + } + .width-10 { + width: calc(10 * var(--flowchart-unit-width) + 9 * var(--flowchart-column-gap)); + } + li { + &.width-2, + &.width-3, + &.width-4, + &.width-5, + &.width-6, + &.width-7, + &.width-8, + &.width-9, + &.width-10, + &.width-full { + > dl { + max-width: unset; + } + } + } +} diff --git a/docs/_static/API.svg b/docs/_static/API.svg new file mode 100644 index 0000000..9c2cb31 --- /dev/null +++ b/docs/_static/API.svg @@ -0,0 +1 @@ + diff --git a/docs/_static/CLI.svg b/docs/_static/CLI.svg new file mode 100644 index 0000000..3d170a9 --- /dev/null +++ b/docs/_static/CLI.svg @@ -0,0 +1 @@ + diff --git a/docs/_static/Cookbook.svg b/docs/_static/Cookbook.svg new file mode 100644 index 0000000..d2f72b4 --- /dev/null +++ b/docs/_static/Cookbook.svg @@ -0,0 +1 @@ + diff --git a/docs/_static/Download.svg b/docs/_static/Download.svg new file mode 100644 index 0000000..3e425ca --- /dev/null +++ b/docs/_static/Download.svg @@ -0,0 +1 @@ + diff --git a/docs/_static/OFE-color-icon.svg b/docs/_static/OFE-color-icon.svg new file mode 100644 index 0000000..0a58ca5 --- /dev/null +++ b/docs/_static/OFE-color-icon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/docs/_static/Rocket.svg b/docs/_static/Rocket.svg new file mode 100644 index 0000000..ae1ed81 --- /dev/null +++ b/docs/_static/Rocket.svg @@ -0,0 +1 @@ + diff --git a/docs/_static/Showcase.svg b/docs/_static/Showcase.svg new file mode 100644 index 0000000..953eb0d --- /dev/null +++ b/docs/_static/Showcase.svg @@ -0,0 +1,75 @@ + + + + diff --git a/docs/_static/Tutorial.svg b/docs/_static/Tutorial.svg new file mode 100644 index 0000000..a42592d --- /dev/null +++ b/docs/_static/Tutorial.svg @@ -0,0 +1 @@ + diff --git a/docs/_static/UserGuide.svg b/docs/_static/UserGuide.svg new file mode 100644 index 0000000..e8cf53a --- /dev/null +++ b/docs/_static/UserGuide.svg @@ -0,0 +1 @@ + diff --git a/docs/_templates/autosummary/base.rst b/docs/_templates/autosummary/base.rst new file mode 100644 index 0000000..cdb86a6 --- /dev/null +++ b/docs/_templates/autosummary/base.rst @@ -0,0 +1,5 @@ +.. title:: {{ objname }} + +.. currentmodule:: {{ module }} + +.. auto{{ objtype }}:: {{ objname }} diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst new file mode 100644 index 0000000..cdb86a6 --- /dev/null +++ b/docs/_templates/autosummary/class.rst @@ -0,0 +1,5 @@ +.. title:: {{ objname }} + +.. currentmodule:: {{ module }} + +.. auto{{ objtype }}:: {{ objname }} diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..d3f9db6 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,254 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +from importlib.metadata import version +from inspect import cleandoc +from pathlib import Path + +import git +import nbformat +import nbsphinx +from packaging.version import parse + +sys.path.insert(0, os.path.abspath("../")) + + +os.environ["SPHINX"] = "True" + +# -- Project information ----------------------------------------------------- + +project = "OpenFE Analysis" +copyright = "2022, The OpenFE Development Team" +author = "The OpenFE Development Team" +version = f"{parse(version('openfe_analysis')).major}.{parse(version('openfe_analysis')).minor}" + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", + "sphinx_click.ext", + "sphinxcontrib.autodoc_pydantic", + "sphinx_toolbox.collapse", + "sphinx.ext.autosectionlabel", + "sphinx_design", + "sphinx.ext.intersphinx", + "sphinx.ext.autosummary", + "docs._ext.sass", + "myst_parser", + "nbsphinx", + "nbsphinx_link", + "sphinx.ext.mathjax", +] +suppress_warnings = ["config.cache"] # https://github.com/sphinx-doc/sphinx/issues/12300 + +intersphinx_mapping = { + "python": ("https://docs.python.org/3.9", None), + "numpy": ("https://numpy.org/doc/stable", None), + "scikit.learn": ("https://scikit-learn.org/stable", None), + "openmm": ("https://docs.openmm.org/latest/api-python/", None), + "rdkit": ("https://www.rdkit.org/docs", None), + "openeye": ("https://docs.eyesopen.com/toolkits/python/", None), + "mdtraj": ("https://www.mdtraj.org/1.9.5/", None), + "openff.units": ("https://docs.openforcefield.org/projects/units/en/stable", None), + "gufe": ("https://gufe.openfree.energy/en/latest/", None), +} + +autoclass_content = "both" +# Make sure labels are unique +# https://www.sphinx-doc.org/en/master/usage/extensions/autosectionlabel.html#confval-autosectionlabel_prefix_document +autosectionlabel_prefix_document = True + +autodoc_pydantic_model_show_json = False + +autodoc_default_options = { + "members": True, + "member-order": "bysource", + "inherited-members": "GufeTokenizable,BaseModel", + "undoc-members": True, + "special-members": "__call__", +} +toc_object_entries_show_parents = "hide" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [ + "_build", + "**/Thumbs.db", + "**/.DS_Store", + "_ext", + "_sass", + "**/README.md", + "ExampleNotebooks", +] + +autodoc_mock_imports = [ + "cinnabar", + "dill", + "MDAnalysis", + "matplotlib", + "mdtraj", + "openmmforcefields", + "openmmtools", + "pymbar", + "openff.interchange", + "openmmforcefields", + "psutil", + "py3Dmol", + "zstandard", +] + +# Extensions for the myst parser +myst_enable_extensions = [ + "dollarmath", + "colon_fence", + "smartquotes", + "replacements", + "deflist", + "attrs_inline", +] +myst_heading_anchors = 3 + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "ofe_sphinx_theme" +html_theme_options = { + "logo": {"text": "OpenFE docs"}, + "icon_links": [ + { + "name": "GitHub", + "url": "https://github.com/OpenFreeEnergy/openfe_analysis", + "icon": "fa-brands fa-square-github", + "type": "fontawesome", + } + ], + "accent_color": "cantina-purple", + "navigation_with_keys": False, +} +html_logo = "_static/OFE-color-icon.svg" +html_favicon = "_static/OFE-color-icon.svg" +# temporary fix, see https://github.com/pydata/pydata-sphinx-theme/issues/1662 +html_sidebars = { + "installation": [], + "CHANGELOG": [], +} +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_static_path = ['_static'] + + +# replace macros +rst_prolog = """ +.. |rdkit.mol| replace:: :class:`rdkit.Chem.rdchem.Mol` +""" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] +html_css_files = [ + "css/custom.css", + "css/custom-api.css", + "css/deflist-flowchart.css", +] + +# custom-api.css is compiled from custom-api.scss +sass_src_dir = "_sass" +sass_out_dir = "_static/css" + +# Clone or update ExampleNotebooks +example_notebooks_path = Path("ExampleNotebooks") +try: + if example_notebooks_path.exists(): + repo = git.Repo(example_notebooks_path) + try: + repo.remote("origin").pull() + except git.exc.GitCommandError: + # cannot pull if on a tag + pass + else: + repo = git.Repo.clone_from( + "https://github.com/OpenFreeEnergy/ExampleNotebooks.git", + branch="2025.12.04", + to_path=example_notebooks_path, + ) +except Exception as e: + from sphinx.util.logging import getLogger + + filename = e.__traceback__.tb_frame.f_code.co_filename + lineno = e.__traceback__.tb_lineno + getLogger("sphinx.ext.openfe_git").warning( + f"Getting ExampleNotebooks failed in {filename} line {lineno}: {e}" + ) + + +# First, create links at top of notebook pages +# All notebooks are in ExampleNotebooks repo, so link to that +# Finally, add sphinx reference anchor in prolog so that we can make refs +nbsphinx_prolog = cleandoc(r""" + {%- set gh_repo = "OpenFreeEnergy/ExampleNotebooks" -%} + {%- set gh_branch = "main" -%} + {%- set path = env.doc2path(env.docname, base=None) -%} + {%- if path.endswith(".nblink") -%} + {%- set path = env.metadata[env.docname]["nbsphinx-link-target"] -%} + {%- endif -%} + {%- if path.startswith("ExampleNotebooks/") -%} + {%- set path = path.replace("ExampleNotebooks/", "", 1) -%} + {%- endif -%} + {%- set gh_url = + "https://www.github.com/" + ~ gh_repo + ~ "/blob/" + ~ gh_branch + ~ "/" + ~ path + -%} + {%- set dl_url = + "https://raw.githubusercontent.com/" + ~ gh_repo + ~ "/" + ~ gh_branch + ~ "/" + ~ path + -%} + + .. container:: ofe-top-of-notebook + + .. button-link:: {{gh_url}} + :color: primary + :shadow: + :outline: + + :octicon:`mark-github` View on GitHub + + .. button-link:: {{dl_url}} + :color: primary + :shadow: + :outline: + + :octicon:`download` Download Notebook + + .. _{{ env.doc2path(env.docname, base=None) }}: +""") diff --git a/docs/environment.yaml b/docs/environment.yaml new file mode 100644 index 0000000..e85ad3c --- /dev/null +++ b/docs/environment.yaml @@ -0,0 +1,36 @@ +name: openfe_analysis-docs +channels: +- https://conda.anaconda.org/conda-forge + +# explicit pins to speed up build: +dependencies: +- autodoc-pydantic >= 2.1 +- docutils == 0.20 +- gitpython +- libsass +- myst-parser +- nbsphinx +- nbsphinx-link +- openff-toolkit-base == 0.17.0 +- openff-units == 0.3.1 +- packaging +- pip +- plugcli >= 0.2.1 +- python +- pydantic >=2.0.0, <2.12.0 # https://github.com/openforcefield/openff-interchange/issues/1346 +- sphinx ==7.2.6 # TODO: debug "duplicate object" warning with later versions +- sphinx-click +- sphinx-design +- sphinx-toolbox +- threadpoolctl +- tqdm +- pip: + - git+https://github.com/OpenFreeEnergy/ofe-sphinx-theme@v0.3.1 + # pip install these so that we can make sure docs build on main while these packages' docs are under development + +# These are added automatically by RTD, so we include them here +# for a consistent environment. +- mock +- pillow +# - sphinx +# - sphinx_rtd_theme diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..f42d80c --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,26 @@ +.. template taken from SciPy who took it from Pandas (keep the chain going) + +.. module:: openfe_analysis + +========================================== +Welcome to OpenFE Analysis' documentation! +========================================== + +The **OpenFE Analysis** toolkit provides a free and open-source framework for analyzing alchemical free energy calculations. + +.. grid:: 1 2 2 4 + :gutter: 3 + + .. grid-item-card:: :fas:`code` Python API + :text-align: center + :link: reference/api/index + :link-type: doc + + Comprehensive details of the **openfe** Python API. + + +.. toctree:: + :maxdepth: 2 + :hidden: + + reference/index diff --git a/docs/reference/api/generated/openfe_analysis.rst b/docs/reference/api/generated/openfe_analysis.rst new file mode 100644 index 0000000..743b7b6 --- /dev/null +++ b/docs/reference/api/generated/openfe_analysis.rst @@ -0,0 +1,37 @@ +openfe\_analysis package +======================== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + openfe_analysis.utils + +Submodules +---------- + +openfe\_analysis.reader module +------------------------------ + +.. automodule:: openfe_analysis.reader + :members: + :undoc-members: + :show-inheritance: + +openfe\_analysis.rmsd module +---------------------------- + +.. automodule:: openfe_analysis.rmsd + :members: + :undoc-members: + :show-inheritance: + +openfe\_analysis.transformations module +--------------------------------------- + +.. automodule:: openfe_analysis.transformations + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/api/generated/openfe_analysis.utils.rst b/docs/reference/api/generated/openfe_analysis.utils.rst new file mode 100644 index 0000000..df59c30 --- /dev/null +++ b/docs/reference/api/generated/openfe_analysis.utils.rst @@ -0,0 +1,29 @@ +openfe\_analysis.utils package +============================== + +Submodules +---------- + +openfe\_analysis.utils.multistate module +---------------------------------------- + +.. automodule:: openfe_analysis.utils.multistate + :members: + :undoc-members: + :show-inheritance: + +openfe\_analysis.utils.serialization module +------------------------------------------- + +.. automodule:: openfe_analysis.utils.serialization + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: openfe_analysis.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/api/index.rst b/docs/reference/api/index.rst new file mode 100644 index 0000000..1d15575 --- /dev/null +++ b/docs/reference/api/index.rst @@ -0,0 +1,10 @@ +.. _api: + +OpenFE Analysis API Reference +============================= + +.. toctree:: + :maxdepth: 2 + + generated/openfe_analysis.rst + generated/openfe_analysis.utils.rst diff --git a/docs/reference/index.rst b/docs/reference/index.rst new file mode 100644 index 0000000..c2a34f1 --- /dev/null +++ b/docs/reference/index.rst @@ -0,0 +1,9 @@ +Reference +========= + +This contains details of the Python API. + +.. toctree:: + :maxdepth: 2 + + api/index diff --git a/src/openfe_analysis/rmsd.py b/src/openfe_analysis/rmsd.py index 7d2af13..427ef1a 100644 --- a/src/openfe_analysis/rmsd.py +++ b/src/openfe_analysis/rmsd.py @@ -14,22 +14,44 @@ def make_Universe(top: pathlib.Path, trj: nc.Dataset, state: int) -> mda.Universe: - """Makes a Universe and applies some transformations + """ + Construct an MDAnalysis Universe from a MultiState NetCDF trajectory + and apply standard analysis transformations. + + The Universe is created using the custom ``FEReader`` to extract a + single state from a multistate simulation. Identifies two AtomGroups: - - protein, defined as having standard amino acid names, then filtered - down to CA + - protein, defined as having standard amino acid names, then filtered down to CA - ligand, defined as resname UNK - Then applies some transformations. + Depending on whether a protein is present, a sequence of trajectory + transformations is applied: If a protein is present: - - prevents the protein from jumping between periodic images - - moves the ligand to the image closest to the protein - - aligns the entire system to minimise the protein RMSD + - prevents the protein from jumping between periodic images (class:`NoJump`) + - moves the ligand to the image closest to the protein (:class:`Minimiser`) + - aligns the entire system to minimise the protein RMSD (:class:`Aligner`) - If only a ligand: + If only a ligand is present: - prevents the ligand from jumping between periodic images + - Aligns the ligand to minimize its RMSD + + Parameters + ---------- + top : pathlib.Path or Topology + Path to a topology file (e.g. PDB) or an already-loaded MDAnalysis + topology object. + trj : netCDF4.Dataset + Open NetCDF dataset produced by + ``openmmtools.multistate.MultiStateReporter``. + state : int + Thermodynamic state index to extract from the multistate trajectory. + + Returns + ------- + MDAnalysis.Universe + A Universe with trajectory transformations applied. """ u = mda.Universe( top, From 5c60e835928c5b060b7f7fa9f600d5eee7ad80cf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 10:25:39 +0000 Subject: [PATCH 2/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/openfe_analysis/tests/conftest.py | 28 +++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/openfe_analysis/tests/conftest.py b/src/openfe_analysis/tests/conftest.py index 5fa2db4..19961eb 100644 --- a/src/openfe_analysis/tests/conftest.py +++ b/src/openfe_analysis/tests/conftest.py @@ -1,6 +1,6 @@ +import pathlib from importlib import resources -import pathlib import pooch import pytest @@ -9,41 +9,49 @@ path=POOCH_CACHE, base_url="doi:10.5281/zenodo.17916322", registry={ - "openfe_analysis_simulation_output.tar.gz":"md5:09752f2c4e5b7744d8afdee66dbd1414", - "openfe_analysis_skipped.tar.gz": "md5:3840d044299caacc4ccd50e6b22c0880", + "openfe_analysis_simulation_output.tar.gz": "md5:09752f2c4e5b7744d8afdee66dbd1414", + "openfe_analysis_skipped.tar.gz": "md5:3840d044299caacc4ccd50e6b22c0880", }, ) + @pytest.fixture(scope="session") def rbfe_output_data_dir() -> pathlib.Path: ZENODO_RBFE_DATA.fetch("openfe_analysis_simulation_output.tar.gz", processor=pooch.Untar()) - result_dir = pathlib.Path(POOCH_CACHE) / "openfe_analysis_simulation_output.tar.gz.untar/openfe_analysis_simulation_output/" + result_dir = ( + pathlib.Path(POOCH_CACHE) + / "openfe_analysis_simulation_output.tar.gz.untar/openfe_analysis_simulation_output/" + ) return result_dir + @pytest.fixture(scope="session") def rbfe_skipped_data_dir() -> pathlib.Path: ZENODO_RBFE_DATA.fetch("openfe_analysis_skipped.tar.gz", processor=pooch.Untar()) - result_dir = pathlib.Path(POOCH_CACHE) / "openfe_analysis_skipped.tar.gz.untar/openfe_analysis_skipped/" + result_dir = ( + pathlib.Path(POOCH_CACHE) / "openfe_analysis_skipped.tar.gz.untar/openfe_analysis_skipped/" + ) return result_dir + @pytest.fixture(scope="session") def simulation_nc(rbfe_output_data_dir) -> pathlib.Path: - return rbfe_output_data_dir/"simulation.nc" + return rbfe_output_data_dir / "simulation.nc" @pytest.fixture(scope="session") def simulation_skipped_nc(rbfe_skipped_data_dir) -> pathlib.Path: - return rbfe_skipped_data_dir/"simulation.nc" + return rbfe_skipped_data_dir / "simulation.nc" @pytest.fixture(scope="session") def hybrid_system_pdb(rbfe_output_data_dir) -> pathlib.Path: - return rbfe_output_data_dir/"hybrid_system.pdb" + return rbfe_output_data_dir / "hybrid_system.pdb" @pytest.fixture(scope="session") -def hybrid_system_skipped_pdb(rbfe_skipped_data_dir)->pathlib.Path: - return rbfe_skipped_data_dir/"hybrid_system.pdb" +def hybrid_system_skipped_pdb(rbfe_skipped_data_dir) -> pathlib.Path: + return rbfe_skipped_data_dir / "hybrid_system.pdb" @pytest.fixture(scope="session") From ffe13da32b4ff9b802588e79c21c7bae4b71e978 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Thu, 29 Jan 2026 11:33:24 +0100 Subject: [PATCH 3/7] Small fixes --- docs/.DS_Store | Bin 6148 -> 0 bytes docs/_ext/.sass.py.swp | Bin 12288 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/.DS_Store delete mode 100644 docs/_ext/.sass.py.swp diff --git a/docs/.DS_Store b/docs/.DS_Store deleted file mode 100644 index 88fb60ff3e07be0388022b1add1d07525b11792d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5Z-NTn^J@v6nYGJEtpm*6fdFH7cim+m6(vC!I&*gVh*K{v%Zi|;`2DO zyEy~{-bCyS?0&QJvzz%K`@GcX4{{<)$Z(ddq&R~829dzDBR4?@^tR6Z*g=bL>yGQ zA6!Sv!ZQ!fMUweZvRuoAC|p9w-A$B)qL_<32~(NtDu>ZG`kp!5Y$mhm$U3#h+mW@I zO>EFlrrT}bI6OK&yY!ypmqffNA~|p_WnW_j@1WFbdUe-HERsjCS2rh3JQvlq#+s)ifcf&l= zXWVYOd>tEld~PCOGtFcY%4U%Is_DsP-Bdy;Hyi##1UqCIuncUSfgS9?{(aNrzsK3l zAJ{d&^-$K+GGH073|Iy%1C{~HfMvikU>UgS7|_`^_8PLjrONzd^}cQ0dv$ByECZGS z%YbFTGGH073|Iy%1C{~HfMvikU>Udx84v+uuiwVlueT$4{QrOS_y1oz8M_923VZ^5 z0K5-e0wnM}@F4KxeT;nuya!wc-UiMA5|{-J0Z#!tfh#*0`vUkJco%pFxC}f8><4xM z+kv0&W$bI^j{{flX6y&xd*A}_7H}ST1=s^z zxr?zcfs4QyU>-OCJOuo?ow09#%fNZy6!0|A0uBPZfro+L?quvI;49!w;27{IaPFb&!lclL5 z3xt+|)8O4AiYdHOo=S_{m#V(%B7(q!TNw4cB@q|0<`}!Q&{?59rH3)5FG*nn(oscW#*43!?nLx~bgXid&TUaS=!_6S_~SF0>~TjniIF z=58RnMXwe*^D0Vue8uw;F_4~jwqn6?9K+~wY)Qt$BJnl$jE8B?bw5%ZzrvFVZKG?< z$UKlCS7ctp&b9dQtRE%I^%kVdt1D32E!CspU-MP9Z8S_{keE!gJ6Hr;HMtxq?WKz| zMq<1iQ|7MRDDqnSM0XQQpIJ~kuYtrWY`x8&n6y~aEjf=1WM=$k(hNaC*bEc~0`%G# z7Q<(_`C%eSD~e@}QCPYvV;V;~rZfxzW%k4=o;QdBB*-h3xu~*%s)0ZXv4_u+<~dCh zBDgY7$J0dgs$w90cZ24QeH9v}(6LwD(RP)YOz;OI!(di7yPi>M>nE6SXqzb}6XR8=zML>Coa%e-Q%W1*uZ z>FJb|NLkh0(~<6bstChqx#qao&@unD4O(FoOU6o;0-(FK(e)cqjWDu`LLQ;0l@^IF ziB9UGtD2}Rp|;33Op?opu^EyoOpCniAI2LZL*9)In~&#aL5w1dwqVl;6m-)NBTkGK z)=6@;gYcEZR0=2;WfGxe%3BDSY-=>TNfd$@GXzaZs;eh%q&(48 zXI)S3$-kD4Z58+G+MV_}{SxH3K2Ep!y~Xpp739yv{n zqv}SrHZn7XJXV7f_Rv@y`A|Aeh$?K^{aJNK-Ka`I4>Rfq)xc<-4Q>`%M$NFWIO>jU zXr1Lis>YuYA&k+U^q3(tOC~(jW>Wi4;@F z;7}&8V!q#r|6;;44Oh~8k&klw^=FzY2sMxPMLk$ I Date: Thu, 29 Jan 2026 11:33:42 +0100 Subject: [PATCH 4/7] Small fixes --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index f42d80c..2595f4b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -16,7 +16,7 @@ The **OpenFE Analysis** toolkit provides a free and open-source framework for an :link: reference/api/index :link-type: doc - Comprehensive details of the **openfe** Python API. + Comprehensive details of the **openfe_analysis** Python API. .. toctree:: From 3b36a89f37900cfd64046d273bd923f1052d353d Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Thu, 29 Jan 2026 11:41:21 +0100 Subject: [PATCH 5/7] Update readthedocs --- .readthedocs.yaml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 76717c6..501592f 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,24 +1,19 @@ -# .readthedocs.yaml -# Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - -# Required version: 2 build: - os: ubuntu-20.04 + os: "ubuntu-24.04" tools: - python: "mambaforge-4.10" + python: "miniconda3-3.12-24.9" sphinx: configuration: docs/conf.py fail_on_warning: true conda: - environment: environment.yml + environment: docs/environment.yaml python: - # Install our python package before building the docs so setuptools-scm generates the version for RTD to find. + # Install our python package before building the docs install: - method: pip path: . From af0cbaf3988378adf37685fef484c6888496d88f Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Thu, 29 Jan 2026 11:45:28 +0100 Subject: [PATCH 6/7] add docs badge to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f182bf6..7c8b701 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Logo](https://img.shields.io/badge/OSMF-OpenFreeEnergy-%23002f4a)](https://openfree.energy/) [![CI](https://github.com/OpenFreeEnergy/openfe_analysis/actions/workflows/ci.yaml/badge.svg)](https://github.com/OpenFreeEnergy/openfe_analysis/actions/workflows/ci.yaml) [![Coverage](https://codecov.io/gh/OpenFreeEnergy/openfe_analysis/graph/badge.svg?token=krb231ftki)](https://codecov.io/gh/OpenFreeEnergy/openfe_analysis) +[![documentation](https://readthedocs.org/projects/openfe/badge/?version=stable)](https://docs.openfree.energy/en/stable/?badge=stable) [![Powered by MDAnalysis](https://img.shields.io/badge/powered%20by-MDAnalysis-orange.svg?logoWidth=16&logo=data:image/x-icon;base64,AAABAAEAEBAAAAEAIAAoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJD+XwCY/fEAkf3uAJf97wGT/a+HfHaoiIWE7n9/f+6Hh4fvgICAjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACT/yYAlP//AJ///wCg//8JjvOchXly1oaGhv+Ghob/j4+P/39/f3IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJH8aQCY/8wAkv2kfY+elJ6al/yVlZX7iIiI8H9/f7h/f38UAAAAAAAAAAAAAAAAAAAAAAAAAAB/f38egYF/noqAebF8gYaagnx3oFpUUtZpaWr/WFhY8zo6OmT///8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICAn46Ojv+Hh4b/jouJ/4iGhfcAAADnAAAA/wAAAP8AAADIAAAAAwCj/zIAnf2VAJD/PAAAAAAAAAAAAAAAAICAgNGHh4f/gICA/4SEhP+Xl5f/AwMD/wAAAP8AAAD/AAAA/wAAAB8Aov9/ALr//wCS/Z0AAAAAAAAAAAAAAACBgYGOjo6O/4mJif+Pj4//iYmJ/wAAAOAAAAD+AAAA/wAAAP8AAABhAP7+FgCi/38Axf4fAAAAAAAAAAAAAAAAiIiID4GBgYKCgoKogoB+fYSEgZhgYGDZXl5e/m9vb/9ISEjpEBAQxw8AAFQAAAAAAAAANQAAADcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjo6Mb5iYmP+cnJz/jY2N95CQkO4pKSn/AAAA7gAAAP0AAAD7AAAAhgAAAAEAAAAAAAAAAACL/gsAkv2uAJX/QQAAAAB9fX3egoKC/4CAgP+NjY3/c3Nz+wAAAP8AAAD/AAAA/wAAAPUAAAAcAAAAAAAAAAAAnP4NAJL9rgCR/0YAAAAAfX19w4ODg/98fHz/i4uL/4qKivwAAAD/AAAA/wAAAP8AAAD1AAAAGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALGxsVyqqqr/mpqa/6mpqf9KSUn/AAAA5QAAAPkAAAD5AAAAhQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADkUFBSuZ2dn/3V1df8uLi7bAAAATgBGfyQAAAA2AAAAMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0AAADoAAAA/wAAAP8AAAD/AAAAWgC3/2AAnv3eAJ/+dgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9AAAA/wAAAP8AAAD/AAAA/wAKDzEAnP3WAKn//wCS/OgAf/8MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQAAANwAAADtAAAA7QAAAMAAABUMAJn9gwCe/e0Aj/2LAP//AQAAAAAAAAAA)](https://www.mdanalysis.org) ## Quickstart From ece3d15a49ab46d193d040c6383c9d9d52f182d9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:21:02 +0000 Subject: [PATCH 7/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/openfe_analysis/tests/conftest.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/openfe_analysis/tests/conftest.py b/src/openfe_analysis/tests/conftest.py index 949fee2..3b3edc0 100644 --- a/src/openfe_analysis/tests/conftest.py +++ b/src/openfe_analysis/tests/conftest.py @@ -33,14 +33,12 @@ def rbfe_output_data_dir() -> pathlib.Path: return cached_dir - @pytest.fixture(scope="session") def rbfe_skipped_data_dir() -> pathlib.Path: cached_dir = _fetch_and_untar("openfe_analysis_skipped") return cached_dir - @pytest.fixture(scope="session") def simulation_nc(rbfe_output_data_dir) -> pathlib.Path: return rbfe_output_data_dir / "simulation.nc"