Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
10 changes: 5 additions & 5 deletions src/datajoint/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import platform
import subprocess

from .condition import AndList
from .condition import AndList, Not
from .errors import DataJointError, DuplicateError
from .heading import Heading
from .table import Table
Expand Down Expand Up @@ -370,8 +370,6 @@ def refresh(

# Keys that need jobs: in key_source, not in target, not in jobs
# Disable semantic_check for Job table (self) because its attributes may not have matching lineage
from .condition import Not

new_keys = (key_source - self._target).restrict(Not(self), semantic_check=False).proj()
new_key_list = new_keys.keys()

Expand All @@ -395,8 +393,10 @@ def refresh(
# 2. Re-pend success jobs if keep_completed=True
if config.jobs.keep_completed:
# Success jobs whose keys are in key_source but not in target
# Disable semantic_check for Job table operations
success_to_repend = self.completed.restrict(key_source, semantic_check=False) - self._target
# Disable semantic_check for Job table operations (job table PK has different lineage than target)
success_to_repend = self.completed.restrict(key_source, semantic_check=False).restrict(
Not(self._target), semantic_check=False
)
repend_keys = success_to_repend.keys()
for key in repend_keys:
(self & key).delete_quick()
Expand Down
42 changes: 42 additions & 0 deletions tests/integration/test_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,45 @@ def test_long_error_stack(clean_jobs, subject, experiment):
experiment.jobs.error(key, "error message", long_error_stack)
error_stack = experiment.jobs.errors.fetch1("error_stack")
assert error_stack == long_error_stack, "error stacks do not agree"


def test_populate_reserve_jobs_with_keep_completed(clean_jobs, subject, experiment):
"""Test populate(reserve_jobs=True) with keep_completed=True.

Regression test for https://github.com/datajoint/datajoint-python/issues/1379
"""
with dj.config.override(jobs={"keep_completed": True, "add_job_metadata": True}):
# Should not raise DataJointError about semantic matching
experiment.populate(reserve_jobs=True)

# Verify jobs completed successfully
assert len(experiment) > 0, "No data was populated"
assert len(experiment.jobs.errors) == 0, "Unexpected errors during populate"

# With keep_completed=True, completed jobs should be retained
assert len(experiment.jobs.completed) > 0, "Completed jobs not retained"


def test_populate_reserve_jobs_keep_completed_repend(clean_jobs, subject, experiment):
"""Test that completed jobs are re-pended when results are deleted.

Regression test for https://github.com/datajoint/datajoint-python/issues/1379
"""
with dj.config.override(jobs={"keep_completed": True, "add_job_metadata": True}):
# First populate
experiment.populate(reserve_jobs=True)
initial_count = len(experiment)
completed_count = len(experiment.jobs.completed)

assert initial_count > 0, "No data was populated"
assert completed_count > 0, "No completed jobs"

# Delete some results
first_key = experiment.keys(limit=1)[0]
(experiment & first_key).delete()

# Refresh should re-pend the deleted job
experiment.jobs.refresh()

# The job for the deleted entry should be pending again
assert len(experiment.jobs.pending) >= 1, "Deleted job not re-pended"
Loading