Skip to content

API Reference

Basic Usage

from pathlib import Path
from ox.cli import parse_file

log = parse_file(Path("training.ox"))

for session in log.sessions:
    print(f"{session.date}: {session.name}")
    for movement in session.movements:
        print(f"  {movement.name}: {movement.total_reps} reps")

Data Structures

All are frozen dataclasses with slots=True.

TrainingLog

Attribute Type
sessions tuple[TrainingSession, ...]
notes tuple[Note, ...]
weigh_ins tuple[WeighIn, ...]
queries tuple[StoredQuery, ...]
movement_definitions tuple[MovementDefinition, ...]
diagnostics tuple[Diagnostic, ...]

Properties: completed_sessions, planned_sessions

Methods: movements(name=None), movement_history(name), most_recent_session(name)

TrainingSession

Attribute Type
date datetime.date
name str \| None
flag str ("*", "!", "W")
movements tuple[Movement, ...]
notes tuple[Note, ...]

Movement

Attribute Type
name str
sets list[TrainingSet]
note str \| None

Properties: total_reps, top_set_weight

Methods: total_volume(), to_ox(compact_reps=False)

TrainingSet

Attribute Type
reps int
weight Quantity \| None

Properties: volume (reps × weight, or None for BW)

MovementDefinition

Attribute Type
name str
equipment str \| None
tags tuple[str, ...]
note str \| None
url str \| None

Parsed from @movement blocks. Used by the LSP for name completion; queryable directly off the log.

WeighIn

Attribute Type
date datetime.date
weight Quantity
time_of_day str \| None
scale str \| None

Note

Attribute Type
text str
date datetime.date \| None

StoredQuery

Attribute Type
name str
sql str
date datetime.date

Diagnostic

Attribute Type
line int
col int
end_line int
end_col int
message str
severity str ("error" or "warning")

Working with Units

ox uses pint for weights:

weight = movement.sets[0].weight

weight.to('kg')          # convert
weight.magnitude         # numeric value
weight.units             # unit object

from ox.units import ureg
if weight > 100 * ureg.pound:
    print("Heavy!")

Database Layer

Load into SQLite for complex queries:

from ox.db import create_db

conn = create_db(log)
rows = conn.execute("""
    SELECT movement_name, SUM(reps * weight_magnitude) AS volume
    FROM training
    WHERE movement_name = 'squat'
    GROUP BY movement_name
""").fetchall()
conn.close()

Tables: sessions, movements, sets, notes, session_notes, weigh_ins, queries

Views: training (denormalized join of sessions/movements/sets)

Round-trip Serialization

session.to_ox()     # serialize session to .ox format
movement.to_ox()    # serialize movement
note.to_ox()        # serialize note

Plugin API

Plugins receive a PluginContext and return one of three result types. All are frozen dataclasses in ox.plugins.

PluginContext

Attribute Type
db sqlite3.Connection
log TrainingLog

TableResult

Attribute Type
columns list[str]
rows list[tuple]

TextResult

Attribute Type
text str

PlotResult

Attribute Type
lines list[str]

See Plugins for a walkthrough of writing a plugin and registering it via register().