Implement timelapse containers with nested member scans - #114
Merged
Merged
Conversation
Define the abstract timelapse contract before any backend implements it: a TimeLapse groups temporal member scans plus shared metadata. Adds the TimeLapse base class, the Series alias, abstract DB timelapse methods (create/get/list/delete), and Scan.get_timelapse/get_series navigation.
Exclude the .junie plan/draft directory and the large real_plant dataset downloaded via test_database.py (150MB of image fixtures) from version control.
Store a timelapse as a top-level directory holding a timelapse.json marker
and its scans nested under <db>/{tl_id}/{scan_id}/. Standalone scans stay
at the root, and new plantdb still opens old flat databases.
Adds TimeLapse and Series FSDB implementations (create/get/list/delete,
member scan management, metadata, dict-style access), timelapse path and
marker helpers, ID validation, dual-read scan loading (_load_scan_at plus
nested discovery in _load_scans/_load_scan), nested scan directory creation,
_timelapse delete with a non-recursive guard, chronological scan sorting by
timelapse.scheduled with index tie-break, and immutable timelapse.id in
metadata updates. Scan/timelapse creation reject cross-namespace collisions.
…hcheck The healthcheck previously treated each root directory as a scan. It now descends into timelapse containers (marked by timelapse.json) and validates their child scans, and reports the correct total scan count.
Adds /timelapses, /timelapses/{id} and /timelapses/{id}/scans resources with
URL builders in api_endpoints, plus timelapse_id and sort filtering on the
existing scan list and table endpoints.
Adds create/get/list/delete_timelapse methods to PlantDBClient and
timelapse_id/sort filter parameters on scan listing. Filesystem sync now
detects timelapse membership from scan metadata and preserves the nested
<db>/{tl_id}/{scan_id}/ layout across local, HTTP and SFTP transfers.
Tests the abstract and FSDB TimeLapse lifecycle (CRUD, sorting, immutable timelapse.id, collision guards), timelapse path/id validation and nested scan loading, the timelapse REST endpoints, the PlantDBClient SDK methods, and nested-layout preservation during local sync.
- Extend `create_timelapse`, `get_timelapse`, `list_timelapses`, and `delete_timelapse` docstrings with concrete doctest-style examples.
…se docstrings - Delete the `Series` alias for `TimeLapse` in `db.py`. - Remove the `Scan.get_series` method and its documentation. - Refine the `TimeLapse` class docstring to reference only a timelapse object. - Update `Scan.get_timelapse` docstring to reflect the parent timelapse instance.
…fixtures Rewrite the romi import test to source data from the shared dummy dataset instead of the hand-committed testscan fixtures, then retire those fixtures and ignore the rest of testdata so large datasets are not tracked.
…pse_id Collapse the timelapse-specific validator into a single tightened _is_valid_id used by scans, filesets, files and timelapses: 128-char cap, no dots, no leading separator, precompiled regex.
Add dedicated TimeLapseNotFound/Exists errors, persist owner and scans index in timelapse markers, register/unregister member scans on create/delete, refresh last_modified, and expose owner/scans via to_dict and item access.
Switch timelapse handlers from scan errors to the dedicated timelapse errors so missing/existing timelapses return the right status, and assert owner and scans in API responses.
jlegrand62
self-requested a review
September 4, 2026 14:19
jlegrand62
approved these changes
Sep 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds end-to-end support for timelapses — named containers holding a set of member scans with a shared owner and chronological index — spanning the database layer, the REST API, the Python client, and the CLI.
The implementation enables users to group temporally-related scans into logical containers while maintaining compatibility with existing workflows.
A timelapse is a directory in the FSDB root identified by a
timelapse.jsonmarker. Each member scan carries ametadata.timelapse.id(andindex) reference. The marker is maintained append/remove-only (never rebuilt on load) and records the container's owner, the ordered list of member scans, and alast_modifiedtimestamp.Highlights
create_timelapse/get_timelapse/delete_timelapse+TimeLapsecontainer class; dedicatedTimeLapseNotFoundError/TimeLapseExistsError; member scans are registered/unregistered in the marker on create/delete; owner is set on first registration and kept on conflict;last_modifiedrefreshed on each mutation./api/v1/timelapsesREST endpoints (list, CRUD, member scans) with auth/rate-limit integration; API handlers map the dedicated timelapse errors to the correct HTTP statuses._is_valid_id(128-char cap, no dots, no leading separator, precompiled regex), removing the timelapse-specific validator.client,commons,server).Tests
Backend (
test_fsdb.py,test_file_ops.py,test_validation.py), REST API (test_timelapse_api.py), and client sync tests were added/updated. The romi import test now sources from the shared dummy dataset instead of hand-committed fixtures (those legacy fixtures are removed andtestdata/is ignored exceptromidb).Breaking / notes
_is_valid_idnow rejects dots and caps length at 128 chars (previously allowed dots and up to 255).see also https://codimd.math.cnrs.fr/J0ZAYUJMTRqHXNKQ9SqzNw#Timelapse-Detailed-Implementation-Plan-ltdbgttl_idscan_id