Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 0.9.5

- Unified export schema/version markers to 0.9.5 across session JSON, bundle manifest, compatibility report, SQL header and CowLog header.
- Preserved backward import compatibility for 0.9.1 schemas while adding acceptance for 0.9.5 schemas.
- Carried forward v0.9.3 review queue filtering/export consistency and batch assignment behavior.

## 0.9.4

- Restored Django runtime target to 6.0.3.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# PyBehaviorLog 0.9.4
# PyBehaviorLog 0.9.5

PyBehaviorLog is an ASGI-first behavioral observation platform built with Django 6.0.3. It is designed for research teams who need video-assisted coding, live observations, structured ethograms, review workflows, and exportable analytics without being locked into a desktop-only workflow.

## What is in this 0.9.4 archive
## What is in this 0.9.5 archive

This version extends the earlier CowLog/BORIS-inspired foundations with:

Expand Down
2 changes: 1 addition & 1 deletion tracker/tests/test_compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,4 @@ def test_export_endpoints_for_compatibility_formats(self):
)
self.assertEqual(response.status_code, 200)
payload = json.loads(response.content.decode('utf-8'))
self.assertEqual(payload['schema'], 'pybehaviorlog-0.9.1-session-compatibility-report')
self.assertEqual(payload['schema'], 'pybehaviorlog-0.9.5-session-compatibility-report')
4 changes: 2 additions & 2 deletions tracker/tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def test_build_statistics_subjects_transitions_and_integrity(self):

def test_build_project_statistics_and_payloads(self):
payload = build_ethogram_payload(self.project)
self.assertEqual(payload['schema'], 'pybehaviorlog-0.9.1-ethogram')
self.assertEqual(payload['schema'], 'pybehaviorlog-0.9.5-ethogram')
imported_categories, _, imported_behaviors = import_ethogram_payload(
self.project, payload, replace_existing=False
)
Expand All @@ -132,7 +132,7 @@ def test_build_project_statistics_and_payloads(self):

def test_import_session_payload_v83(self):
payload = {
'schema': 'pybehaviorlog-0.9.1-session',
'schema': 'pybehaviorlog-0.9.5-session',
'workflow_status': 'validated',
'review_notes': 'Checked',
'events': [
Expand Down
2 changes: 1 addition & 1 deletion tracker/tests/test_roundtrip.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def test_cowlog_fixture_roundtrip_via_pybehaviorlog_json(self):
self.assertEqual(report['detected_format'], 'cowlog-results-v1')
import_session_payload(session, imported_payload, clear_existing=True)
exported_payload = {
'schema': 'pybehaviorlog-0.9.1-session',
'schema': 'pybehaviorlog-0.9.5-session',
'events': [
{
'time': event.timestamp_seconds,
Expand Down
6 changes: 3 additions & 3 deletions tracker/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def test_event_api_create_list_and_export_json(self):

export_response = self.client.get(reverse('tracker:session_export_json', args=[session.pk]))
self.assertEqual(export_response.status_code, 200)
self.assertIn('pybehaviorlog-0.9.1-session', export_response.content.decode('utf-8'))
self.assertIn('pybehaviorlog-0.9.5-session', export_response.content.decode('utf-8'))

def test_event_update_and_delete_api(self):
session = self.project.sessions.create(
Expand Down Expand Up @@ -242,7 +242,7 @@ def test_session_import_accepts_csv(self):
def test_project_import_boris_json_view(self):
payload = {
'schema': 'boris-project-v3',
'ethogram': {'schema': 'pybehaviorlog-0.9.1-ethogram', 'categories': [], 'modifiers': [], 'subject_groups': [], 'subjects': [], 'variables': [], 'behaviors': [{'name': 'Imported behavior', 'description': '', 'key_binding': 'i', 'color': '#0f766e', 'mode': 'point', 'sort_order': 1, 'category': None}]},
'ethogram': {'schema': 'pybehaviorlog-0.9.5-ethogram', 'categories': [], 'modifiers': [], 'subject_groups': [], 'subjects': [], 'variables': [], 'behaviors': [{'name': 'Imported behavior', 'description': '', 'key_binding': 'i', 'color': '#0f766e', 'mode': 'point', 'sort_order': 1, 'category': None}]},
'subject_groups': [{'name': 'Imported group', 'description': '', 'color': '#123456', 'sort_order': 1}],
'subjects': [{'name': 'Imported subject', 'description': '', 'key_binding': 's', 'color': '#654321', 'sort_order': 1, 'groups': ['Imported group']}],
'variables': [{'label': 'Weight', 'description': '', 'value_type': 'numeric', 'set_values': [], 'default_value': '0', 'sort_order': 1}],
Expand Down Expand Up @@ -318,7 +318,7 @@ def test_project_import_boris_json_accepts_mapping_shapes(self):
payload = {
'schema': 'boris-project-v2',
'ethogram': {
'schema': 'pybehaviorlog-0.9.1-ethogram',
'schema': 'pybehaviorlog-0.9.5-ethogram',
'categories': {'General': {'color': '#111111', 'sort_order': 1}},
'modifiers': {'Near': {'description': 'proximity', 'key': 'n', 'sort_order': 1}},
'behaviors': {'Imported code': {'description': '', 'key': 'i', 'color': '#0f766e', 'mode': 'point', 'sort_order': 1, 'category': {'name': 'General'}}},
Expand Down
27 changes: 15 additions & 12 deletions tracker/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def build_release_metadata() -> dict:
"""Return a small machine-readable release description for health and ops tooling."""
return {
'application': 'PyBehaviorLog',
'version': '0.9.4',
'version': '0.9.5',
'django_target': '6.0.3',
'python_minimum': '3.13',
'asgi': True,
Expand Down Expand Up @@ -1790,8 +1790,8 @@ def build_reproducibility_bundle(project: Project) -> dict[str, bytes]:
)

manifest = {
'schema': 'pybehaviorlog-0.9.1-bundle',
'version': '0.9.1',
'schema': 'pybehaviorlog-0.9.5-bundle',
'version': '0.9.5',
'project': {
'name': project.name,
'description': project.description,
Expand Down Expand Up @@ -2366,8 +2366,8 @@ def build_session_compatibility_report(session: ObservationSession) -> dict:
modifier_event_count = sum(1 for event in ordered_events if event.modifiers.exists())
multi_subject_event_count = sum(1 for event in ordered_events if event.subjects.count() > 1)
report = {
'schema': 'pybehaviorlog-0.9.1-session-compatibility-report',
'version': '0.9.1',
'schema': 'pybehaviorlog-0.9.5-session-compatibility-report',
'version': '0.9.5',
'session': session.title,
'boris': {
'documented_exports': [
Expand Down Expand Up @@ -2421,8 +2421,8 @@ def build_session_compatibility_report(session: ObservationSession) -> dict:
def build_project_compatibility_report(project: Project) -> dict:
"""Summarize project-level exchange coverage for BORIS and CowLog."""
return {
'schema': 'pybehaviorlog-0.9.1-project-compatibility-report',
'version': '0.9.1',
'schema': 'pybehaviorlog-0.9.5-project-compatibility-report',
'version': '0.9.5',
'project': project.name,
'counts': {
'sessions': project.sessions.count(),
Expand Down Expand Up @@ -2651,6 +2651,7 @@ def import_project_payload(
'pybehaviorlog-0.8.3-bundle',
'pybehaviorlog-0.9-bundle',
'pybehaviorlog-0.9.1-bundle',
'pybehaviorlog-0.9.5-bundle',
}:
raise ValueError(_('Unsupported project payload format.'))

Expand All @@ -2659,7 +2660,7 @@ def import_project_payload(
project,
{
**ethogram_payload,
'schema': ethogram_payload.get('schema', 'pybehaviorlog-0.9.1-ethogram'),
'schema': ethogram_payload.get('schema', 'pybehaviorlog-0.9.5-ethogram'),
},
replace_existing=False,
)
Expand Down Expand Up @@ -2870,7 +2871,7 @@ def import_project_payload(

def build_ethogram_payload(project: Project) -> dict: # pragma: no cover
return {
'schema': 'pybehaviorlog-0.9.1-ethogram',
'schema': 'pybehaviorlog-0.9.5-ethogram',
'project': {
'name': project.name,
'description': project.description,
Expand Down Expand Up @@ -2953,6 +2954,7 @@ def import_ethogram_payload(
'pybehaviorlog-0.8.3-ethogram',
'pybehaviorlog-0.9-ethogram',
'pybehaviorlog-0.9.1-ethogram',
'pybehaviorlog-0.9.5-ethogram',
'boris-project-v1',
'boris-project-v2',
'boris-project-v3',
Expand Down Expand Up @@ -3257,6 +3259,7 @@ def import_session_payload(
'pybehaviorlog-0.8.3-session',
'pybehaviorlog-0.9-session',
'pybehaviorlog-0.9.1-session',
'pybehaviorlog-0.9.5-session',
'cowlog-results-v1',
'boris-tabular-csv-v1',
'boris-tabular-tsv-v1',
Expand Down Expand Up @@ -5488,7 +5491,7 @@ def session_export_sql(request, pk: int): # pragma: no cover
"""Export session events as SQL INSERT statements for downstream analysis."""
session = get_accessible_session(request.user, pk)
lines = [
'-- PyBehaviorLog 0.9.1 SQL export',
'-- PyBehaviorLog 0.9.5 SQL export',
'BEGIN;',
'CREATE TABLE IF NOT EXISTS pybehaviorlog_event_export (project text, session text, primary_video text, synced_videos text, observer text, category text, behavior text, behavior_mode text, event_kind text, timestamp_seconds numeric(10,3), subjects text, modifiers text, comment text, created_at text);',
]
Expand Down Expand Up @@ -5525,7 +5528,7 @@ def session_export_cowlog_txt(request, pk: int): # pragma: no cover
response['Content-Disposition'] = (
f'attachment; filename="session_{session.pk}_cowlog_compatible.txt"'
)
response.write('# PyBehaviorLog 0.9.1 CowLog-compatible export\n')
response.write('# PyBehaviorLog 0.9.5 CowLog-compatible export\n')
response.write(f'# session\t{session.title}\n')
response.write(f'# project\t{session.project.name}\n')
response.write(f'# primary_video\t{session.primary_label}\n')
Expand Down Expand Up @@ -5652,7 +5655,7 @@ def session_export_tsv(request, pk: int): # pragma: no cover
def session_export_json(request, pk: int):
session = get_accessible_session(request.user, pk)
payload = {
'schema': 'pybehaviorlog-0.9.1-session',
'schema': 'pybehaviorlog-0.9.5-session',
'project': session.project.name,
'session': session.title,
'video': session.primary_label,
Expand Down
Loading