Targets and Sessions#
A target is the subject of a capture project — a building, patient,
specimen, or study. Its schema is a cg.Struct, and everything captured
for it lives under one directory laid out by that schema.
A target is a schema#
import capturegraph as cg
class Session(cg.Struct):
photo: cg.Image
notes: cg.String
class PlantJournal(cg.Struct):
reference: cg.Image # target-level: persists across sessions
sessions: cg.Map[cg.Date, Session] # one entry per capture
_metadata: cg.Metadata
Fields on the target struct that are not the session map persist across every session — use them for reference imagery, calibration, or one-time configuration. The session map holds the per-run data.
Sessions#
A session is one execution of the procedure. Sessions are a
cg.Map[cg.Date, ...]: each is keyed by its capture instant, which encodes
as a 16-hex-digit microsecond timestamp — the session id.
@cg.procedure(PlantJournal)
def journal(root):
root.reference |= cg.CaptureImage(label="Reference (once)")
session = root.sessions[cg.CaptureTime()] # a new session
session.photo &= cg.CaptureImage(label="Photo")
session.notes &= cg.UserInputString(label="Notes")
Keying sessions by the capture time gives you, for free:
- Chronological sorting — ids sort by capture time.
- Mergeability — captures from different devices never collide, so folders merge by copying.
- No overwrites — each run is its own entry.
On disk#
The schema fixes the layout. A PlantJournal target lands as:
PlantJournal/
├── .metadata/
│ ├── .thumbnail.heic
│ ├── .location.json
│ └── .next_notification.json
├── reference.heic # target-level field
└── sessions/
├── 00063B40E29D696A/ # one session (Time key = 16-hex id)
│ ├── photo.heic
│ └── notes.json
└── 00063B41A2C8F1B0/
└── ...
A _-prefixed field (_metadata) hides under a leading .. See
Types and Nodes for the full encoding.
Per-session collections#
A session can hold an cg.Array you append
to in a loop, or its own nested struct:
class Session(cg.Struct):
primary: cg.Image
extras: cg.Array[cg.Image] # zero or more, appended in a loop
@cg.procedure(PlantJournal)
def journal(root):
session = root.sessions[cg.CaptureTime()]
session.primary &= cg.CaptureImage(label="Primary")
with cg.while_repeat(cg.UserInputBool(label="Another?"), session.extras) as item:
item &= cg.CaptureImage(label="Extra")
Array entries store under zero-padded indices (extras/00000.heic,
extras/00001.heic).
See Also#
- Recorder and Caching —
|=,&=, path navigation - Types and Nodes — the four type forms and layout
- Loading Captures —
cg.loadover the same schema