Skip to content

Improve BORIS/CowLog compatibility: flexible schemas, richer parsing, timecode/frame-rate handling, and exports#37

Merged
Smartappli merged 2 commits intomainfrom
codex/adapter-code-pour-compatibilite-avec-boris-et-cowlog
Apr 27, 2026
Merged

Improve BORIS/CowLog compatibility: flexible schemas, richer parsing, timecode/frame-rate handling, and exports#37
Smartappli merged 2 commits intomainfrom
codex/adapter-code-pour-compatibilite-avec-boris-et-cowlog

Conversation

@Smartappli
Copy link
Copy Markdown
Owner

Motivation

  • Broaden and stabilize interoperability with BORIS and CowLog payloads by accepting newer schema versions, mapping-style object rows, and multiple-observation payloads.
  • Improve fidelity of time parsing and frame-rate handling to correctly interpret SMPTE/frame timecodes, ISO8601 durations, comma decimals and metadata-declared FPS.
  • Preserve metadata, annotations and observation context when importing and export relevant metadata when exporting CowLog-compatible text.

Description

  • Add flexible schema recognition helpers (_schema_matches, _is_supported_*) and coerce functions (_coerce_object_rows) to accept both mapping and list representations for events, annotations and segments.
  • Extend time parsing _decimal and normalize frame-rate handling with _normalize_frame_rate_token to parse ISO8601 durations, HH:MM:SS:FF (with fps), SMPTE semicolon formats and comma decimals.
  • Enhance parse_cowlog_results_text and parse_tabular_session_rows to detect metadata lines, parse CowLog annotation metadata, accept semicolon-delimited rows, use shlex-based tokenization, and emit metadata, annotations and frame_rate information in the import report.
  • Merge multiple BORIS observations into a single session while preserving per-observation context by annotating event comments and annotation titles, and persist imported media/observation notes into session.notes using _append_note_line.
  • Apply CowLog metadata to session notes and persist FPS into ObservationVariableValue when present, and include observer/fps/annotations in session_export_cowlog_txt output.
  • Replace rigid schema checks across project/session/ethogram import paths with regex-based acceptance to support newer schema variants.
  • Add a new plan.md outlining further BORIS/CowLog compatibility work.

Testing

  • Added and updated unit tests in tracker/tests/* covering CowLog text parsing (timecodes, ISO durations, frame rates, metadata annotations), tabular BORIS timecodes and durations, mapping-style rows and multi-observation merges, and export checks for CowLog metadata.
  • Ran the tracker test suite (python manage.py test tracker) which executed the new tests and existing compatibility/roundtrip tests, and they passed.

Codex Task

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Enhanced BORIS and CowLog format compatibility with support for multiple timestamp formats during imports.
    • Improved metadata extraction and handling from imported observations.
    • Enhanced session annotation support in exports with better timestamp formatting.
  • Documentation

    • Added comprehensive implementation roadmap for BORIS/CowLog compatibility completion.

Walkthrough

This pull request implements comprehensive BORIS and CowLog compatibility enhancements, including improved timestamp parsing with frame rate support, enhanced CowLog plain-text parsing with metadata extraction, expanded tabular import handling, refactored session import logic with multi-observation merging, and extended CowLog export capabilities.

Changes

Cohort / File(s) Summary
Documentation
plan.md
Adds structured implementation roadmap for completing BORIS/CowLog compatibility with prioritized workstreams, execution order, and end criteria.
Compatibility Resolution
tracker/compatibility.py
Extends _resolve_event_items, _resolve_annotation_items, and _resolve_segment_items to handle dict/list variations and iterate across multiple observations, merging nested items and adding support for cowlog-results-v2 schema.
Test Suite Extensions
tracker/tests/test_compatibility.py, tracker/tests/test_helpers.py, tracker/tests/test_roundtrip.py
Adds comprehensive test coverage for CowLog/BORIS timestamp variants (ISO-8601 durations, frame timecodes, SMPTE formats), state alias mapping, metadata extraction, tabular CSV parsing with custom frame rates, schema variant imports (cowlog-results-v2, boris-observation-v4, boris-project-v4), observation merging, and roundtrip equivalence validation.
Main Implementation
tracker/views.py
Enhances timestamp parsing with frame rate support for multiple formats; improves CowLog plain-text parsing with comment/metadata extraction and FPS detection; extends tabular import for duration-based stop-time inference and frame-rate-aware decimal parsing; refactors session import with schema pattern matching, object row normalization, and cross-observation event/annotation/variable merging; expands CowLog text export to include observer metadata and session annotations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Behold! The timestamps now align,
Frame rates and formats intertwine,
BORIS and CowLog shake hands with glee,
Round-trips assured—compatibility!
From text to schema, back again,
This fuzzy code makes all friends. 🤝

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main changes: expanding BORIS/CowLog compatibility through multiple improvements including flexible schema support, enhanced time parsing, and frame-rate handling.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering motivation, detailed implementation approach, testing methodology, and alignment with the PR objectives.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/adapter-code-pour-compatibilite-avec-boris-et-cowlog
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch codex/adapter-code-pour-compatibilite-avec-boris-et-cowlog

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented Apr 27, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 4 complexity · 4 duplication

Metric Results
Complexity 4
Duplication 4

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request significantly enhances compatibility with BORIS and CowLog formats by introducing support for multi-observation merging, mapping-based event/annotation structures, and advanced timecode parsing (including ISO8601, SMPTE, and frame-based formats). Key improvements include metadata extraction from CowLog headers, automatic delimiter detection for tabular files, and expanded export capabilities. The review feedback highlights an opportunity to improve the note-appending logic to avoid potential data loss or unwanted reformatting in the session notes field, and suggests adding explicit user warnings when encountering invalid timestamps in CowLog files to aid in data diagnostics.

Comment thread tracker/views.py
Comment on lines +676 to +686
def _append_note_line(existing: str | None, line: str, *, max_length: int = 2000) -> str:
"""Append one note line while avoiding duplicate entries."""
current = (existing or '').strip()
candidate = (line or '').strip()
if not candidate:
return current[:max_length]
lines = [item.strip() for item in current.splitlines() if item.strip()]
if candidate in lines:
return '\n'.join(lines)[:max_length]
lines.append(candidate)
return '\n'.join(lines)[:max_length]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The _append_note_line function collapses all existing empty lines in the notes and hardcodes a max_length of 2000. Since ObservationSession.notes is a TextField that can store much larger amounts of data, this implementation could lead to accidental data loss or unwanted reformatting of existing user notes. It is recommended to avoid global reformatting and truncation of the entire field.

Suggested change
def _append_note_line(existing: str | None, line: str, *, max_length: int = 2000) -> str:
"""Append one note line while avoiding duplicate entries."""
current = (existing or '').strip()
candidate = (line or '').strip()
if not candidate:
return current[:max_length]
lines = [item.strip() for item in current.splitlines() if item.strip()]
if candidate in lines:
return '\n'.join(lines)[:max_length]
lines.append(candidate)
return '\n'.join(lines)[:max_length]
def _append_note_line(existing: str | None, line: str) -> str:
"""Append one note line while avoiding duplicate entries."""
current = (existing or '').strip()
candidate = (line or '').strip()
if not candidate:
return current
lines = [item.strip() for item in current.splitlines()]
if candidate in lines:
return current
return (current + '\n' + candidate).strip() if current else candidate

Comment thread tracker/views.py
Comment on lines +2183 to 2185
timestamp_decimal = _decimal(parts[0], default='NaN', frame_rate=detected_frame_rate)
if timestamp_decimal.is_nan():
continue
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Invalid timestamps in CowLog text files are silently skipped. It would be better to add a warning to the warnings list, including the line number and the invalid value, to help users diagnose issues with their data.

Suggested change
timestamp_decimal = _decimal(parts[0], default='NaN', frame_rate=detected_frame_rate)
if timestamp_decimal.is_nan():
continue
timestamp_decimal = _decimal(parts[0], default='NaN', frame_rate=detected_frame_rate)
if timestamp_decimal.is_nan():
warnings.append(
_('Line %(line)s: invalid time value “%(value)s”.')
% {'line': line_number, 'value': parts[0]}
)
continue

@Smartappli Smartappli merged commit f717e25 into main Apr 27, 2026
3 of 24 checks passed
@Smartappli Smartappli deleted the codex/adapter-code-pour-compatibilite-avec-boris-et-cowlog branch April 27, 2026 14:47
@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant