Skip to content

Reloading and Caching

Flywheel SDK container objects are snapshots of server state at the time they were fetched. As your script runs — calling update(), uploading files, or waiting for gears to complete — the server state can diverge from what the local object reflects. This page covers two strategies for managing that gap: knowing when to call reload() to refresh a stale object, and caching container lookups so that the same data is not fetched more than once.

Reloading Strategies

When you call update() on a container, the local Python object is not automatically refreshed — it still reflects the state at the time it was first fetched. Similarly, containers returned by finders may not include all fields. Understanding when reload() is necessary — and when it is not — avoids both stale-data bugs and redundant requests.

When reload() is necessary

After calling update() — the SDK does not re-fetch the object after a write. Call reload() if you need the current server state immediately after updating.

Reload after updating a container
session.update(label="ses-02")
session = session.reload()  # reflects the new label

Before accessing .files or .analyses — containers returned by finders include summary fields but does not populate the full files and analyses lists by default (for response size optimization). Reload before using these lists if freshness matters.

Reload before accessing the files list
acquisition = session.acquisitions.find_first("label=T1w")
acquisition = acquisition.reload()
for f in acquisition.files:
    print(f.name, f.size)

Before reading info from a finder resultinfo may be absent or incomplete on objects returned from searches and finders. Reload to get the full payload.

Reload before reading info from a finder result
session = project.sessions.find_first("label=baseline")
session = session.reload()
print(session.info)

Avoiding unnecessary reloads

A reload() call is a full API round trip. In a loop over hundreds of sessions, an unconditional reload() doubles the total request count.

Situation Action
Container was just fetched by ID No reload needed — already fresh
Need .files or .analyses Reload before accessing
Just called update() Reload only if you need the updated fields
Reading .info from a finder result Reload before reading
Only using .id, .label, or other top-level fields from the finder No reload needed

Selectively reloading only the containers that need updated data decreases the overall request count:

Reload only when the use case requires it
for session in project.sessions.iter():
    if needs_file_list(session):
        session = session.reload()
        process_files(session.files)

Stale data detection

The SDK does not detect staleness automatically. There is no built-in version field or cache-validation header on container objects. You are responsible for tracking whether server state has changed since your last fetch.

Common signals that a container may be stale:

  • A gear has run and may have added files or updated info
  • Another process or user called update() on the same container
  • You stored a reference to a container fetched earlier in a long-running script

In long-running scripts, call reload() or re-fetch containers by ID rather than reusing objects captured at the start:

Re-fetch containers by ID in long-running scripts
for session_id in session_ids:
    session = fw.get_session(session_id)  # fresh on each iteration
    process(session)

Caching Strategies

Every call to fw.lookup(), fw.get_project(), or any finder method is an HTTP request. In scripts that reference the same containers repeatedly, storing results locally eliminates redundant round trips.

Cache container lookups

Store containers in a dictionary keyed by ID or path when you expect to reference them more than once:

Cache lookups by container ID
container_cache = {}

def get_container(container_id):
    if container_id not in container_cache:
        container_cache[container_id] = fw.get(container_id)
    return container_cache[container_id]

For path-based lookups, use the path string as the cache key:

Cache path-based lookups
lookup_cache = {}

def cached_lookup(path):
    if path not in lookup_cache:
        lookup_cache[path] = fw.lookup(path)
    return lookup_cache[path]

project = cached_lookup("my-group/my-project")

Local data structures

For multi-pass algorithms — where the same containers are looked up repeatedly — build an in-memory index from a single bulk query:

Build an in-memory index from a single bulk query
subjects_by_label = {s.label: s for s in project.subjects.iter()}

subject = subjects_by_label.get("SUB_01")

This pattern is especially useful in extract, transform, load (ETL) pipelines where you process subject or session records by label in a second pass over the data.

When to invalidate cache

A cached container object becomes stale when the server state has changed. Remove the entry from your cache — or mark it as dirty so it is re-fetched on next access — in these situations:

  • You called update() or update_info() on the container
  • You uploaded or deleted a file on the container
  • A gear run completed and may have modified the container
Invalidate a cache entry after an update
session.update(label="ses-02")
session_cache.pop(session.id, None)  # force re-fetch on next access

For long-running scripts, avoid persisting the cache across the entire run. Re-fetch containers at the start of each major work unit to ensure you are working with current data.