# Select an app version ## Goal Call a specific version of a PlayMolecule app, instead of the latest-by-default. ## Minimal example ```python from playmolecule.apps import proteinprepare # Always whatever version is installed as latest ed = proteinprepare(outdir="out", pdbid="3ptb") # Pinned to v1 ed = proteinprepare.v1.proteinprepare(outdir="out", pdbid="3ptb") ``` ## Why The unqualified app symbol (`proteinprepare`) is an alias for the latest installed version. That's convenient for exploration, but it means an {py:func}`~playmolecule.update_apps` call can change your script's behavior without your code changing. For anything reproducible — published results, CI pipelines, batch sweeps — call the version explicitly. ## How versions are exposed When PlayMolecule discovers an app, it builds a submodule per version: ```text playmolecule.apps. # alias for latest playmolecule.apps..v1 # explicit version 1 playmolecule.apps..v2 # explicit version 2 ... ``` Each version submodule exposes the same set of callable functions plus `artifacts`, `datasets`, `files`, and `__manifest__`. The `tests` namespace lives on each function (e.g. `proteinprepare.v1.proteinprepare.tests`), not on the submodule itself. Parameters and defaults can differ between versions — that's the whole point of versioning. ## List versions installed ```python import playmolecule.apps.proteinprepare as pp [name for name in dir(pp) if name.startswith("v") and name[1:].isdigit()] ``` Or look at the qualified paths in {py:func}`~playmolecule.describe_apps`: ```text ProteinPrepare playmolecule.apps.proteinprepare.v1.proteinprepare ProteinPrepare playmolecule.apps.proteinprepare.v2.proteinprepare ``` ## Compare versions before upgrading ```python help(proteinprepare.v1.proteinprepare) help(proteinprepare.v2.proteinprepare) ``` Each version's function carries its own manifest-derived docstring, so `help` shows you exactly what differs between them — useful before an upgrade. ## Gotchas - The "latest" alias is computed at import time by natural sort of version strings. `v10` correctly sorts after `v9`. - Pinning to a version that isn't installed raises `AttributeError`. Catch it explicitly if your script must run against installs of unknown vintage. - Pinning a version doesn't pin the container image's runtime dependencies, only the manifest contract. Image SHAs change when Acellera ships fixes; combine version pinning with [`update_apps()`](update-installed-apps.md) discipline for full reproducibility. ## See also - [Apps and manifests](../explanation/apps-and-manifests.md) - [Update installed apps](update-installed-apps.md) - {py:func}`~playmolecule.describe_apps`