Apps and manifests#
A PlayMolecule “app” is a container plus a JSON manifest. The container holds the science (the actual proteinprepare Python code, for example). The manifest declares everything PlayMolecule needs to expose that container as a typed Python function: parameters, defaults, expected outputs, resource requirements, and built-in tests.
This page explains what’s in a manifest and how PlayMolecule turns it into the Python surface you import.
Anatomy of a manifest#
A manifest is a JSON document with these top-level keys. Annotated with … for omitted parts (not real JSON):
{
"container_config": { "name": "ProteinPrepare", "version": "1", "condaenvs": [...] },
"meta_keywords": ["preparation", "protein", ...],
"citations": [...],
"files": { "tests/3ptb.pdb": "/app/files/tests/3ptb.pdb", ... },
"functions": [
{
"function": "proteinprepare.apps.proteinprepare.app.main",
"env": "base",
"resources": { "ncpu": 1, "ngpu": 0 },
"outputs": { "output.pdb": "...", "details.csv": "...", "pka_plot.png": "..." },
"params": [
{ "name": "outdir", "type": "Path", "mandatory": true, ... },
{ "name": "pdbid", "type": "str", "mandatory": false, ... },
{ "name": "pH", "type": "float", "value": 7.2, ... },
...
],
"tests": {
"simple": {
"description": "Prepare 3PTB structure from RCSB",
"arguments": { "pdbid": "3ptb" },
"expected_outputs": ["output.pdb", "details.csv", "pka_plot.png"]
},
...
},
"examples": ["proteinprepare(outdir='./test', pdbid='3ptb').run()"],
"description": "ProteinPrepare prepares proteins (and nucleic acids)"
}
]
}
Each entry in functions becomes one callable on the app module.
How a manifest becomes a Python function#
When a manifest is loaded, PlayMolecule assembles a Python callable for each entry in functions, plus a set of module-level attributes on the app’s version submodule:
On the dynamic function itself:
Signature —
paramsis converted into aninspect.Signature. Each param’stype,nargs,mandatory, and defaultvaluemap ontoinspect.Parameterattributes. The function then binds incoming kwargs against that signature on every call, which is how PlayMolecule raises a typedTypeErrorwhen you mistypepdbiforpdbid.Docstring —
description,params,outputs, andexamplesare formatted into a NumPy-style docstring sohelp(app)andapp?work without any extra wiring.Tests — each entry under
testsbecomes a callable test attribute accessible asapp.tests.<name>.run().Manifest metadata — the per-function manifest entry is attached as
app.__manifest__.
On the version submodule (shared by every function in that version):
Artifacts / files — entries under
artifacts(or the older synonymdatasets) and thefilesblock become attributes on the submodule itself:someapp.v1.artifacts.<NAME>,someapp.v1.files. The full app manifest is also attached at the submodule level assomeapp.v1.__manifest__.
The end result: at the version submodule playmolecule.apps.proteinprepare.v1 you get a callable proteinprepare (the function), plus artifacts, datasets, files, and __manifest__ — everything derived from one JSON file.
Versions#
A given app can ship multiple manifests, one per version. They appear as parallel submodules:
playmolecule.apps.proteinprepare # alias for latest
playmolecule.apps.proteinprepare.v1 # explicit
playmolecule.apps.proteinprepare.v2 # explicit
The unqualified symbol is set at import time by natural-sort over the version strings (v10 sorts after v9).
Multi-function apps#
functions is a list. A single manifest can expose several entry points — for example, an app that does both “prepare” and “validate”. Each one shows up as its own attribute:
from playmolecule.apps import someapp
someapp.prepare(outdir="out", ...)
someapp.validate(outdir="out", ...)
A function literally named main is exposed under the app name instead, so you can write someapp(...) rather than someapp.main(...). That’s why proteinprepare(...) works — the manifest’s actual function is named main.
Where to put a manifest#
Docker registry — embedded as an image label.
HTTP backend — served by the backend’s
/apps/manifestsendpoint.Local registry (developer use) —
<root>/apps/<appname>/<version>/<manifest>.json(where<root>is the path afterlocal:inPM_REGISTRIES), alongside arun.shand any payload files. Useful when you’re authoring your own app and want to iterate on the manifest without publishing.
The three discovery paths produce the same app_versions data shape (see Architecture), so the resulting Python surface is identical regardless of source.
See also#
describe_apps()