Artifacts and files#
PlayMolecule has two related but distinct concepts for “things that live inside an app’s container and can be used by it”: files and artifacts. They share the same underlying class hierarchy but serve different purposes.
Files: the raw inventory#
Every app declares a files block in its manifest mapping logical paths to in-container paths:
"files": {
"tests/3ptb.pdb": "/app/files/tests/3ptb.pdb",
"tests/web_content.pickle": "/app/files/tests/web_content.pickle"
}
These are exposed as app.files — a dict of file handles. You don’t usually touch this directly. It’s used internally to:
Resolve test-config paths to actual file handles (
tests/3ptb.pdb→ the bundled PDB).Resolve
artifactsentries (next section).
Artifacts: the curated, callable surface#
The artifacts block (also accepted as the older synonym datasets) declares which files are meant to be used as inputs:
"artifacts": [
{ "name": "default", "path": "datasets/model_98acc.ckpt", "description": "DeepSite final model" }
]
These appear as attributes on app.artifacts:
from playmolecule.apps import deepsite
deepsite.artifacts.default # a callable file handle
deepsite.artifacts.default.path # path inside the container
deepsite.artifacts.default.download("./local-copy")
You pass deepsite.artifacts.default directly as a function argument; PlayMolecule resolves it to the right path depending on the active execution backend (local mount, Docker bind, HTTP fetch).
The summary#
Aspect |
|
|
|---|---|---|
Source |
|
|
Access |
dict keyed by logical path |
attribute access by curated name |
Purpose |
wiring (tests, internal resolution) |
user-facing — pass into app calls |
Has |
Logical path |
Curated short name (no dots; must start with a letter) |
Has description |
Usually no |
Yes (from manifest) |
Downloadable? |
Yes ( |
Yes ( |
In short: artifacts is files filtered to the entries someone took the trouble to curate and name. Reach for artifacts unless you know you need the raw files dict.
Backend-aware file handles#
A file handle knows how to fetch its content for the active backend:
local registry — plain filesystem path;
.download()is a copy.Docker registry (Docker runtime) —
.download()shells out todocker cp.Docker registry (Apptainer runtime) —
.download()runsapptainer execagainst the cached SIF and copies out.HTTP backend —
.download()issues an authenticated GET to the backend.
You don’t pick which one you got — the handle does the right thing for the current registry/runtime, which is why example code can use app.artifacts.Foo uniformly across installations.
When you’d actually use .download()#
The download() path is for outside-the-app consumers — say, you want to do an analysis in your own notebook with the same reference data the app uses. For arguments to the app, just pass the handle directly; don’t download first.
Gotchas#
Two artifacts in the same app cannot share a name. If they do, the loader overwrites silently.
download()to a path that already exists will overwrite a file or wipe-and-recreate a directory. There is no “keep existing” mode.For Docker / Apptainer files,
download()shells out — it’s slow for many small files. Prefer a singledownload()of a directory over a loop of per-file downloads.