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
16 changes: 11 additions & 5 deletions pluto/op.py
Original file line number Diff line number Diff line change
Expand Up @@ -1164,12 +1164,18 @@ def _teardown(self, code: Union[int, None], update_status: bool) -> None:
wait=True,
)
if not sync_completed:
# stop() SIGTERMs the sync process on timeout, and its
# unthrottled drain usually empties the queue before we
# read the count here — so only warn when records are
# genuinely still unsent (avoids a contradictory
# "0 records may not have been uploaded").
pending = self._sync_manager.get_pending_count()
logger.warning(
f'{tag}: Sync did not complete within timeout, '
f'{pending} records may not have been uploaded. '
f'Data is preserved in {self._sync_manager.db_path}'
)
if pending > 0:
logger.warning(
f'{tag}: Sync did not complete within timeout, '
f'{pending} records may not have been uploaded. '
f'Data is preserved in {self._sync_manager.db_path}'
)
self._sync_manager.close()
self._sync_manager = None

Expand Down
2 changes: 1 addition & 1 deletion pluto/sweep.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ def _run_bayes(
except ImportError:
raise ImportError(
"sweep method='bayes' needs optuna — install it with "
'`pip install optuna` (or `pip install pluto[sweep]`).'
'`pip install optuna` (or `pip install "pluto-ml[sweep]"`).'
)
if count is None:
raise ValueError("method='bayes' needs count=<n> in pluto.agent(...)")
Expand Down
46 changes: 46 additions & 0 deletions tests/test_run_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,52 @@ def test_finish_confirmed_status_clears_error_flag(self):
assert settings._op_status == 0


class TestFinishDrainWarning:
"""finish()'s 'records may not have been uploaded' warning must not fire when
the SIGTERM drain already emptied the queue (pending == 0) — otherwise it
prints a contradictory '0 records may not have been uploaded' that reads like
data loss at the moment nothing was lost.
"""

def _noop_op(self):
from pluto.op import Op
from pluto.sets import Settings

settings = Settings()
settings.mode = 'noop'
settings.sync_process_enabled = False # don't spawn a real sync subprocess
op = Op(config={}, settings=settings)
op.start()
return op

def _warns(self, op):
from unittest.mock import patch

with patch('pluto.op.logger.warning') as warn:
op.finish()
return ' '.join(str(c.args[0]) for c in warn.call_args_list if c.args)

def test_no_warning_when_drain_emptied_queue(self):
from unittest.mock import MagicMock

op = self._noop_op()
sm = MagicMock()
sm.stop.return_value = False # 30s wait "timed out"
sm.get_pending_count.return_value = 0 # but the drain emptied it
op._sync_manager = sm
assert 'may not have been uploaded' not in self._warns(op)

def test_warns_when_records_genuinely_pending(self):
from unittest.mock import MagicMock

op = self._noop_op()
sm = MagicMock()
sm.stop.return_value = False
sm.get_pending_count.return_value = 5 # genuinely unsent
op._sync_manager = sm
assert '5 records may not have been uploaded' in self._warns(op)


class TestExcepthookSubprocess:
"""
End-to-end test: run a script that raises an unhandled exception
Expand Down
12 changes: 12 additions & 0 deletions tests/test_sweep.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,15 @@ def test_bayes_requires_count(self, monkeypatch):
)
with pytest.raises(ValueError, match='needs count'):
pluto.agent(sid, lambda: None)


def test_bayes_missing_optuna_names_the_real_package(monkeypatch):
# When optuna isn't installed, the hint must point at the real distribution
# name (pluto-ml) — NOT `pluto`, which is an unrelated package on PyPI, so
# following the wrong hint silently installs someone else's package.
monkeypatch.setitem(sys.modules, 'optuna', None) # makes `import optuna` raise
with pytest.raises(ImportError) as exc:
sw._run_bayes('sid', {}, None, lambda: None, 1, [], 'loss')
msg = str(exc.value)
assert 'pluto-ml[sweep]' in msg
assert 'pluto[sweep]' not in msg