experimaestro 2.0.0b4__py3-none-any.whl → 2.0.0b8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of experimaestro might be problematic. Click here for more details.

@@ -23,7 +23,7 @@ def test_database_initialization(tmp_path: Path):
23
23
  db_path = tmp_path / "workspace.db"
24
24
 
25
25
  # Initialize database
26
- db = initialize_workspace_database(db_path, read_only=False)
26
+ db, _ = initialize_workspace_database(db_path, read_only=False)
27
27
 
28
28
  # Verify all tables were created
29
29
  assert ExperimentModel.table_exists()
@@ -47,7 +47,7 @@ def test_database_initialization(tmp_path: Path):
47
47
  def test_experiment_and_run_models(tmp_path: Path):
48
48
  """Test creating experiments and runs"""
49
49
  db_path = tmp_path / "workspace.db"
50
- db = initialize_workspace_database(db_path, read_only=False)
50
+ db, _ = initialize_workspace_database(db_path, read_only=False)
51
51
 
52
52
  with db.bind_ctx(ALL_MODELS):
53
53
  # Create an experiment
@@ -79,7 +79,7 @@ def test_experiment_and_run_models(tmp_path: Path):
79
79
  def test_job_model_with_composite_key(tmp_path: Path):
80
80
  """Test job model with composite primary key (job_id, experiment_id, run_id)"""
81
81
  db_path = tmp_path / "workspace.db"
82
- db = initialize_workspace_database(db_path, read_only=False)
82
+ db, _ = initialize_workspace_database(db_path, read_only=False)
83
83
 
84
84
  with db.bind_ctx(ALL_MODELS):
85
85
  # Create experiment and run first
@@ -133,7 +133,7 @@ def test_job_model_with_composite_key(tmp_path: Path):
133
133
  def test_job_tags_model(tmp_path: Path):
134
134
  """Test run-scoped job tags (fixes GH #128)"""
135
135
  db_path = tmp_path / "workspace.db"
136
- db = initialize_workspace_database(db_path, read_only=False)
136
+ db, _ = initialize_workspace_database(db_path, read_only=False)
137
137
 
138
138
  with db.bind_ctx(ALL_MODELS):
139
139
  # Create experiment and runs
@@ -203,7 +203,7 @@ def test_job_tags_model(tmp_path: Path):
203
203
  def test_multiple_experiments_same_workspace(tmp_path: Path):
204
204
  """Test that multiple experiments can coexist in same workspace database"""
205
205
  db_path = tmp_path / "workspace.db"
206
- db = initialize_workspace_database(db_path, read_only=False)
206
+ db, _ = initialize_workspace_database(db_path, read_only=False)
207
207
 
208
208
  with db.bind_ctx(ALL_MODELS):
209
209
  # Create two experiments
@@ -249,13 +249,13 @@ def test_read_only_mode(tmp_path: Path):
249
249
  db_path = tmp_path / "workspace.db"
250
250
 
251
251
  # Create database with write mode
252
- db_write = initialize_workspace_database(db_path, read_only=False)
252
+ db_write, _ = initialize_workspace_database(db_path, read_only=False)
253
253
  with db_write.bind_ctx(ALL_MODELS):
254
254
  ExperimentModel.create(experiment_id="exp1")
255
255
  close_workspace_database(db_write)
256
256
 
257
257
  # Open in read-only mode
258
- db_read = initialize_workspace_database(db_path, read_only=True)
258
+ db_read, _ = initialize_workspace_database(db_path, read_only=True)
259
259
 
260
260
  with db_read.bind_ctx(ALL_MODELS):
261
261
  # Can read
@@ -272,7 +272,7 @@ def test_read_only_mode(tmp_path: Path):
272
272
  def test_upsert_on_conflict(tmp_path: Path):
273
273
  """Test that on_conflict works for updating existing records"""
274
274
  db_path = tmp_path / "workspace.db"
275
- db = initialize_workspace_database(db_path, read_only=False)
275
+ db, _ = initialize_workspace_database(db_path, read_only=False)
276
276
 
277
277
  with db.bind_ctx(ALL_MODELS):
278
278
  # Create experiment and run
experimaestro/tui/app.py CHANGED
@@ -4,6 +4,7 @@ import logging
4
4
  from pathlib import Path
5
5
  from typing import Optional
6
6
  from textual.app import App, ComposeResult
7
+ from textual import work
7
8
  from textual.containers import Container, Horizontal, Vertical
8
9
  from textual.widgets import (
9
10
  Header,
@@ -265,6 +266,7 @@ class ExperimentsList(Widget):
265
266
  """Initialize the experiments table"""
266
267
  table = self.query_one("#experiments-table", DataTable)
267
268
  table.add_column("ID", key="id")
269
+ table.add_column("Host", key="host")
268
270
  table.add_column("Jobs", key="jobs")
269
271
  table.add_column("Status", key="status")
270
272
  table.add_column("Started", key="started")
@@ -340,15 +342,21 @@ class ExperimentsList(Widget):
340
342
  # Format duration
341
343
  duration = format_duration(elapsed)
342
344
 
345
+ # Get hostname (may be None for older experiments)
346
+ hostname = getattr(exp, "hostname", None) or "-"
347
+
343
348
  # Update existing row or add new one
344
349
  if exp_id in existing_keys:
345
350
  table.update_cell(exp_id, "id", exp_id, update_width=True)
351
+ table.update_cell(exp_id, "host", hostname, update_width=True)
346
352
  table.update_cell(exp_id, "jobs", jobs_text, update_width=True)
347
353
  table.update_cell(exp_id, "status", status, update_width=True)
348
354
  table.update_cell(exp_id, "started", started, update_width=True)
349
355
  table.update_cell(exp_id, "duration", duration, update_width=True)
350
356
  else:
351
- table.add_row(exp_id, jobs_text, status, started, duration, key=exp_id)
357
+ table.add_row(
358
+ exp_id, hostname, jobs_text, status, started, duration, key=exp_id
359
+ )
352
360
 
353
361
  # Remove rows for experiments that no longer exist
354
362
  for old_exp_id in existing_keys - current_exp_ids:
@@ -465,6 +473,23 @@ class ViewJobLogsRequest(Message):
465
473
  self.experiment_id = experiment_id
466
474
 
467
475
 
476
+ class LogsSyncComplete(Message):
477
+ """Message sent when remote log sync is complete"""
478
+
479
+ def __init__(self, log_files: list, job_id: str) -> None:
480
+ super().__init__()
481
+ self.log_files = log_files
482
+ self.job_id = job_id
483
+
484
+
485
+ class LogsSyncFailed(Message):
486
+ """Message sent when remote log sync fails"""
487
+
488
+ def __init__(self, error: str) -> None:
489
+ super().__init__()
490
+ self.error = error
491
+
492
+
468
493
  class DeleteJobRequest(Message):
469
494
  """Message sent when user requests to delete a job"""
470
495
 
@@ -560,6 +585,10 @@ class ServicesList(Vertical):
560
585
 
561
586
  # Get services from state provider (handles live vs DB automatically)
562
587
  services = self.state_provider.get_services(self.current_experiment)
588
+ self.log.info(
589
+ f"refresh_services got {len(services)} services: "
590
+ f"{[(s.id, id(s), getattr(s, 'url', None)) for s in services]}"
591
+ )
563
592
 
564
593
  for service in services:
565
594
  service_id = service.id
@@ -596,9 +625,12 @@ class ServicesList(Vertical):
596
625
  if not service:
597
626
  return
598
627
 
628
+ self.log.info(f"Starting service {service.id} (id={id(service)})")
629
+
599
630
  try:
600
631
  if hasattr(service, "get_url"):
601
632
  url = service.get_url()
633
+ self.log.info(f"Service started, url={url}, service.url={service.url}")
602
634
  self.notify(f"Service started: {url}", severity="information")
603
635
  else:
604
636
  self.notify("Service does not support starting", severity="warning")
@@ -1888,7 +1920,7 @@ class ExperimaestroUI(App):
1888
1920
  with TabPane("Monitor", id="monitor-tab"):
1889
1921
  yield from self._compose_monitor_view()
1890
1922
  with TabPane("Logs", id="logs-tab"):
1891
- yield CaptureLog(id="logs", auto_scroll=True)
1923
+ yield CaptureLog(id="logs", auto_scroll=True, wrap=True)
1892
1924
  else:
1893
1925
  # Simple layout without logs
1894
1926
  with Vertical(id="main-container"):
@@ -1918,19 +1950,27 @@ class ExperimaestroUI(App):
1918
1950
  experiments_list = self.query_one(ExperimentsList)
1919
1951
  experiments_list.refresh_experiments()
1920
1952
 
1921
- # Register as listener for push notifications from state provider
1953
+ # Register as listener for state change notifications
1954
+ # The state provider handles its own notification strategy internally
1922
1955
  if self.state_provider:
1923
1956
  self.state_provider.add_listener(self._on_state_event)
1924
1957
  self._listener_registered = True
1925
- self.log("Registered state listener for push notifications")
1958
+ self.log("Registered state listener for notifications")
1926
1959
 
1927
1960
  def _on_state_event(self, event: StateEvent) -> None:
1928
1961
  """Handle state change events from the state provider
1929
1962
 
1930
- This is called from the state provider's thread, so we use
1931
- call_from_thread to safely update the UI.
1963
+ This may be called from the state provider's thread or the main thread,
1964
+ so we check before using call_from_thread.
1932
1965
  """
1933
- self.call_from_thread(self._handle_state_event, event)
1966
+ import threading
1967
+
1968
+ if threading.current_thread() is threading.main_thread():
1969
+ # Already in main thread, call directly
1970
+ self._handle_state_event(event)
1971
+ else:
1972
+ # From background thread, use call_from_thread
1973
+ self.call_from_thread(self._handle_state_event, event)
1934
1974
 
1935
1975
  def _handle_state_event(self, event: StateEvent) -> None:
1936
1976
  """Process state event on the main thread"""
@@ -2081,10 +2121,62 @@ class ExperimaestroUI(App):
2081
2121
  """Show orphan jobs screen"""
2082
2122
  self.push_screen(OrphanJobsScreen(self.state_provider))
2083
2123
 
2124
+ @work(thread=True, exclusive=True)
2125
+ def _sync_and_view_logs(self, job_path: Path, task_id: str) -> None:
2126
+ """Sync logs from remote and then view them (runs in worker thread)"""
2127
+ try:
2128
+ # Sync the job directory
2129
+ local_path = self.state_provider.sync_path(str(job_path))
2130
+ if not local_path:
2131
+ self.post_message(LogsSyncFailed("Failed to sync logs from remote"))
2132
+ return
2133
+
2134
+ job_path = local_path
2135
+
2136
+ # Log files are named after the last part of the task ID
2137
+ task_name = task_id.split(".")[-1]
2138
+ stdout_path = job_path / f"{task_name}.out"
2139
+ stderr_path = job_path / f"{task_name}.err"
2140
+
2141
+ # Collect existing log files
2142
+ log_files = []
2143
+ if stdout_path.exists():
2144
+ log_files.append(str(stdout_path))
2145
+ if stderr_path.exists():
2146
+ log_files.append(str(stderr_path))
2147
+
2148
+ if not log_files:
2149
+ self.post_message(
2150
+ LogsSyncFailed(f"No log files found: {task_name}.out/.err")
2151
+ )
2152
+ return
2153
+
2154
+ # Signal completion via message
2155
+ job_id = job_path.name
2156
+ self.post_message(LogsSyncComplete(log_files, job_id))
2157
+
2158
+ except Exception as e:
2159
+ self.post_message(LogsSyncFailed(str(e)))
2160
+
2161
+ def on_logs_sync_complete(self, message: LogsSyncComplete) -> None:
2162
+ """Handle successful log sync - show log viewer"""
2163
+ self.push_screen(LogViewerScreen(message.log_files, message.job_id))
2164
+
2165
+ def on_logs_sync_failed(self, message: LogsSyncFailed) -> None:
2166
+ """Handle failed log sync"""
2167
+ self.notify(message.error, severity="warning")
2168
+
2084
2169
  def on_view_job_logs(self, message: ViewJobLogs) -> None:
2085
2170
  """Handle request to view job logs - push LogViewerScreen"""
2086
2171
  job_path = Path(message.job_path)
2087
- # Log files are named after the last part of the task ID
2172
+
2173
+ # For remote monitoring, sync the job directory first (in worker thread)
2174
+ if self.state_provider.is_remote:
2175
+ self.notify("Syncing logs from remote...", timeout=5)
2176
+ self._sync_and_view_logs(job_path, message.task_id)
2177
+ return
2178
+
2179
+ # Local monitoring - no sync needed
2088
2180
  task_name = message.task_id.split(".")[-1]
2089
2181
  stdout_path = job_path / f"{task_name}.out"
2090
2182
  stderr_path = job_path / f"{task_name}.err"
experimaestro/version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '2.0.0b4'
32
- __version_tuple__ = version_tuple = (2, 0, 0, 'b4')
31
+ __version__ = version = '2.0.0b8'
32
+ __version_tuple__ = version_tuple = (2, 0, 0, 'b8')
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: experimaestro
3
- Version: 2.0.0b4
3
+ Version: 2.0.0b8
4
4
  Summary: Experimaestro is a computer science experiment manager
5
5
  Project-URL: Homepage, https://github.com/experimaestro/experimaestro-python
6
6
  Project-URL: Documentation, https://experimaestro-python.readthedocs.io/
@@ -82,11 +82,11 @@ The full documentation can be read by going to the following URL: [https://exper
82
82
 
83
83
  ## Textual interface (new in v2)
84
84
 
85
- ![Experiment screen](docs/img/tui-experiments.png)
85
+ ![Experiment screen](docs/source/img/tui-experiments.png)
86
86
 
87
- ![Jobs screen](docs/img/tui-jobs.png)
87
+ ![Jobs screen](docs/source/img/tui-jobs.png)
88
88
 
89
- ![Log screen](docs/img/tui-logs.png)
89
+ ![Log screen](docs/source/img/tui-logs.png)
90
90
 
91
91
  # Install
92
92
 
@@ -20,9 +20,9 @@ experimaestro/settings.py,sha256=ymA-W2-cNOE1W8oc7lPPxOwEz2wXSX9Q5iftw0agKcY,448
20
20
  experimaestro/taskglobals.py,sha256=A_P49RHu8FLOfoybfwcLzDcDZiUug4mLFKiAzsCof_k,1315
21
21
  experimaestro/tokens.py,sha256=IitlWi8CJprTXFTw0GJ3cf-vch-x5IyJztiik5FYC1M,18578
22
22
  experimaestro/typingutils.py,sha256=v7wS9xewF3cYOKvaBFxlTB-qplJ8olI1OaO3tAKiwIo,3678
23
- experimaestro/version.py,sha256=HyWx2o7EdD14LPtqK_PB12S5bv01Ve1GDVbJadPGzCY,712
23
+ experimaestro/version.py,sha256=xb387tRebssohFiC2cBfY1gEG-Ur9UZkojiYpRcNRbA,712
24
24
  experimaestro/xpmutils.py,sha256=S21eMbDYsHfvmZ1HmKpq5Pz5O-1HnCLYxKbyTBbASyQ,638
25
- experimaestro/cli/__init__.py,sha256=ZtU5lBsB9MwLFHvEMFipRTpCv-lOYx0JOEUWqbiG-E8,13595
25
+ experimaestro/cli/__init__.py,sha256=-ps3-5_fnqH61oRbCYZ1h-bWoLazHjLXIJP2mMYSWFY,17989
26
26
  experimaestro/cli/filter.py,sha256=0Lq9B_ZNSjVU1N6sCv-YETjAPtRVwunlfGxtG6aeBpY,5024
27
27
  experimaestro/cli/jobs.py,sha256=lnxlISYjVzdOk3lkEhIuV0MRyCO1JprTgg56R5KJ1No,10049
28
28
  experimaestro/cli/progress.py,sha256=I6qhVe-vvqA1ym6XJE75q7Hb0jGeFwgodIqfhlTrPKY,8200
@@ -45,7 +45,7 @@ experimaestro/core/objects/config.py,sha256=YXJ5_B8mmW_tVvjGGhCVQPic3iLbU1xFv6xK
45
45
  experimaestro/core/objects/config_utils.py,sha256=ZLECGkeIWdzunm8vwWsQhvcSgV1e064BgXbLiZnxSEM,1288
46
46
  experimaestro/core/objects/config_walk.py,sha256=lMK7dXMjqfDaqc4NPxenYABozKYusmJ8xhDbDFP8z5U,4980
47
47
  experimaestro/experiments/__init__.py,sha256=GcpDUIbCvhnv6rxFdAp4wTffCVNTv-InY6fbQAlTy-o,159
48
- experimaestro/experiments/cli.py,sha256=5_cNzQk6FotHeHUIl7b1zS5JRyGcoQ58gB8BCEbbvcE,13169
48
+ experimaestro/experiments/cli.py,sha256=WbeK4PNEy9cQoX_mJiLkMuu57lCLURg2I7dC3nECTmY,13345
49
49
  experimaestro/experiments/configuration.py,sha256=vVm40BJW5sZNgSDZ0oBzX15jTO9rmOewVYrm0k9iXXY,1466
50
50
  experimaestro/launcherfinder/__init__.py,sha256=qRUDyv3B9UsAM8Q31mRrZrTZox0AptwdmOY4f2K-TUo,279
51
51
  experimaestro/launcherfinder/base.py,sha256=q47SsF_cXdo5O6ZhFKn5385WVFcx8Wd-BcEpd6tRpbs,515
@@ -63,19 +63,24 @@ experimaestro/mkdocs/base.py,sha256=qHDZZFdoNRsW6RcjRB1WCSp2sOtRiBk9zFO1acK05BQ,
63
63
  experimaestro/mkdocs/metaloader.py,sha256=ItchfE3emrzKUrT-8f8WsDHNHisYzs9XDCzhWcu6VaQ,1471
64
64
  experimaestro/mkdocs/style.css,sha256=42kJ6Ozq_n4Iw5UfJ4-nO1u-HN3ELvV7Vhvj1Xkn7rQ,66
65
65
  experimaestro/scheduler/__init__.py,sha256=HssbogPCuGpKGMPZQP07XCT2-uMFRPANuPM-duMIrq4,422
66
- experimaestro/scheduler/base.py,sha256=3s47to-rd4QxlcSbPHAoSkJEo7DgQ1HJGX9dwTE1JG8,27456
66
+ experimaestro/scheduler/base.py,sha256=IMVwLUEm0hPJzfX0sb6efI1Ic1-o1Ya56mlxG8FXyqI,28269
67
67
  experimaestro/scheduler/dependencies.py,sha256=gQfmIEa8l9mMVMmBuoPfUM30eQzEozFkCQGXkbfXhaU,2406
68
68
  experimaestro/scheduler/dynamic_outputs.py,sha256=pKSm73D_XIgUHawf432JJXfQKISO34qEMf5w-nWTl-g,11187
69
- experimaestro/scheduler/experiment.py,sha256=44cjCFvyW0C6bwhuNOoKPR5HUzYCv6m0t7xPTjBRMxM,20803
70
- experimaestro/scheduler/interfaces.py,sha256=z5EzL_ghMyuvAKCSaYwPAZB_hpX6OCe95L1I7sD7Bp0,15262
69
+ experimaestro/scheduler/experiment.py,sha256=N7-903ADgqlJumgldOdS4BAI2nIcKPFUCDXqW_mHLsQ,22334
70
+ experimaestro/scheduler/interfaces.py,sha256=JG1Z6iGWosiM-TrEkxhsPz-dJ4lfPQL6dnaGjbCn-aA,16008
71
71
  experimaestro/scheduler/jobs.py,sha256=h04Vj595zxvpgvJOr-3wK_rFBvVmlYqO68gq1euI4vc,15634
72
- experimaestro/scheduler/services.py,sha256=B0JYKD3FW6SMeMOA9i46vogz-gT_p3Jr_2c8wKcPv8c,8246
72
+ experimaestro/scheduler/services.py,sha256=CVZ7YDB71qQe86oCEQWPzgRTchEtYUZWx3KxqGykhnc,13053
73
73
  experimaestro/scheduler/signal_handler.py,sha256=B4ZeSVB8O41VDdFmV4n2cyBds7wKFG3kH2Fp7cpyxa4,872
74
74
  experimaestro/scheduler/state.py,sha256=1ICn1K5gNMCEUb85vwwXLIUF6Lxqa5mbTgMzEz2pnXw,2367
75
- experimaestro/scheduler/state_db.py,sha256=x9x1Z5qgOGrz8TzzDIVMG2IBV_FK6i-oTY_z73yBT6U,13768
76
- experimaestro/scheduler/state_provider.py,sha256=fus4F5Jrxrpg7rABqciyAGc5cf6JzpWTxFPCwXsVClI,80730
77
- experimaestro/scheduler/state_sync.py,sha256=4X0WRqSXhyFNn57eSxvGZByioNw9U-vNdlsn132zGRk,32375
75
+ experimaestro/scheduler/state_db.py,sha256=HmM0PCKZoGix_VR571M4ZATag7e52KeWaFhOzBtRgRE,15855
76
+ experimaestro/scheduler/state_provider.py,sha256=X3sqdC8UnUlnveaFjMwjnEhCkHuiLpM9xp1WRpskAiE,94907
77
+ experimaestro/scheduler/state_sync.py,sha256=yrwHdGqUck_QbVCHymP5mnJHN1Z_0dILleV_vDw16KQ,34678
78
78
  experimaestro/scheduler/workspace.py,sha256=hIASgxGQtrlN4oPFDqDYXTVnxDbngirGdDyAJxJq4vg,3815
79
+ experimaestro/scheduler/remote/__init__.py,sha256=QBXrl4V09nPbwxKRtV7-uLdZCXtktWBeSAV7kB2ZWOM,1134
80
+ experimaestro/scheduler/remote/client.py,sha256=FX9ZieKfz2s7SBt1KWGOLUqwuey2EAnzasKdAB8Ifsg,31501
81
+ experimaestro/scheduler/remote/protocol.py,sha256=Rc2_nsln-xw9kMnDOMbMXSIIgIjMciYhLCg4caHZgFs,13831
82
+ experimaestro/scheduler/remote/server.py,sha256=T61yaaU-tn3Pmh0wevrozyl20Oj_D5S5S-SpKGy_nQ0,15739
83
+ experimaestro/scheduler/remote/sync.py,sha256=BgPK96EJY3AxjBmrwo53CN5fUmGED-a12ZTODkJ_mQk,4917
79
84
  experimaestro/server/__init__.py,sha256=BXLPcDRy7Bxx0xk24SF8OthvcE_rk7Afx7yVvgYvM2o,15920
80
85
  experimaestro/sphinx/__init__.py,sha256=DhFRj8MxA9XZH-TCnbl_5bYhGiF4ihiuFwQj74oPEp4,9466
81
86
  experimaestro/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -86,7 +91,7 @@ experimaestro/tests/restart.py,sha256=aAizVLvw2DaNfIzuRB13iYXOoX1Q5NkgsngumERlo2
86
91
  experimaestro/tests/restart_main.py,sha256=iAFzw0H1q9Aq7t6TrSAj236QBnYU52qx0VF-2dz6tx4,295
87
92
  experimaestro/tests/task_tokens.py,sha256=vgqUa-S_YC2Id9pGOSv40qFTwq1WGZkFhr556Z5o678,477
88
93
  experimaestro/tests/test_checkers.py,sha256=e6Rv2TlePRY__VXs0vUb6a5Aw_KIq_cs4N86VhnYHtw,407
89
- experimaestro/tests/test_cli_jobs.py,sha256=pz9X6oaYaZD4aczbOJEKpEpA9UU8KfJrROFN1MU1K7I,19349
94
+ experimaestro/tests/test_cli_jobs.py,sha256=hQimCKsgr44smvX7rxoOUS2knGBpcfvIhuwZWSSawic,19358
90
95
  experimaestro/tests/test_dependencies.py,sha256=LvpmMcfnRzQPzUIuFNCIQnJot8YBSxCA827xh9gYlq0,1890
91
96
  experimaestro/tests/test_deprecated.py,sha256=SWuc37o9E-9VsWnwNQBHWiWHdn4syeVTouMSPWyqhww,20061
92
97
  experimaestro/tests/test_environment.py,sha256=HEIV4OIBaPdGnqi8bdqkwucc2Ezr-VMnNUiA2qYVIHE,6923
@@ -106,11 +111,12 @@ experimaestro/tests/test_outputs.py,sha256=wO53O6yWVT2sBlRXHTgsv_9i_Y8X5-JnOVfrE
106
111
  experimaestro/tests/test_param.py,sha256=cmCvzpCGSNpcFAI2lfIQe2lTYBfxO8gr5I0SVXiNafQ,7346
107
112
  experimaestro/tests/test_partial_paths.py,sha256=XiYJsqP8IFW-gypvWBrXziMBBk3naXJp2-0OnEgKoUQ,9066
108
113
  experimaestro/tests/test_progress.py,sha256=Baz2z749CWmMauldMxfMr8A77w3lRNr8eDpsPn317sc,5968
114
+ experimaestro/tests/test_remote_state.py,sha256=cILubH-dF1iFMmBYLQtVsbpmfJQgDEaK7xHKOe9edGg,23217
109
115
  experimaestro/tests/test_resumable_task.py,sha256=H5plRfuQ7bhWzP9TQgGAxm6-GlbtPOTLm9WMZhvRUZ0,17080
110
116
  experimaestro/tests/test_serializers.py,sha256=DWe3gbaQP16tQawDz8uSiDpQ_nyTuYjFMvoGEwIWfhU,5302
111
117
  experimaestro/tests/test_snippets.py,sha256=rojnyDjtmAMnSuDUj6Bv9XEgdP8oQf2nVc132JF8vsM,3081
112
118
  experimaestro/tests/test_ssh.py,sha256=KS1NWltiXrJBSStY9d4mwrexeqgNGWmhxuAU_WLQDAU,1449
113
- experimaestro/tests/test_state_db.py,sha256=tnvyTkzttV3CQ0xAeWaj9F_jthxkb4-QQ94ky3eA-xk,14173
119
+ experimaestro/tests/test_state_db.py,sha256=4FfMXYCJyZCltnwKf6ITX08_xXozFJxkcCmrLVlTGzQ,14197
114
120
  experimaestro/tests/test_subparameters.py,sha256=mDDwPK-KlaZBf0uStxLOhxKElxhp_7mb1DYNJ02yfvg,5792
115
121
  experimaestro/tests/test_tags.py,sha256=VTjowJljm8sCGiEuOIDeoNO4NPJNY1pu4b7G8dWqBes,6596
116
122
  experimaestro/tests/test_tasks.py,sha256=E4LWKR_6N4bD0iONeGHQ24c4iNcXsp8l1f4jnwq0MH4,9104
@@ -147,7 +153,7 @@ experimaestro/tools/diff.py,sha256=mrI9QlZAVgMOGfyz3ryQT9wu5JBn9ndAiVk_EpCh0m4,3
147
153
  experimaestro/tools/documentation.py,sha256=O2UzjzodPqGot3YSe6NYlK7S42XpplakUdqxFpvjqHQ,9184
148
154
  experimaestro/tools/jobs.py,sha256=63bXhJ7RGdczLU_nxu2skGn-9dwgr4r5pD23qH4WeBA,3516
149
155
  experimaestro/tui/__init__.py,sha256=BTf7I5HtG7AA_vGTSG891Jjz4R3wf-cEnpaEwB6xBA4,197
150
- experimaestro/tui/app.py,sha256=isheCcyJXn_HsHwJ66o-SPs-A--xpqWRQQ90Kcvqr3U,86349
156
+ experimaestro/tui/app.py,sha256=YXysC-VZaa-PRUUKyBaVdM_4IeC1SPSM7SFgGoLl5eI,89788
151
157
  experimaestro/tui/log_viewer.py,sha256=TFybc1LsCjbaC5sUQ8WMAwP6Uzy92GknpEmYx1u0csI,6938
152
158
  experimaestro/utils/__init__.py,sha256=iuBQw4lZT9Z4BIfQg0Yl9JHdbPgkSvkTH24xREeGHiI,3113
153
159
  experimaestro/utils/asyncio.py,sha256=9r_vFQs6T6tqmymC_DbHVFhY9YVRO6X48uEuyL_ugP8,726
@@ -174,8 +180,8 @@ experimaestro/server/data/login.html,sha256=4dvhSOn6DHp_tbmzqIKrqq2uAo0sAUbgLVD0
174
180
  experimaestro/server/data/manifest.json,sha256=EpzHQZzrGh9c1Kf63nrqvI33H1cm0nLYfdh5lDm8ijI,318
175
181
  experimaestro/tui/app.tcss,sha256=KsNvixGexmGld19ztBm-Nt5IH0gbclykfYgblP38Wy4,4556
176
182
  experimaestro/sphinx/static/experimaestro.css,sha256=0rEgt1LoDdD-a_R5rVfWZ19zD1gR-1L7q3f4UibIB58,294
177
- experimaestro-2.0.0b4.dist-info/METADATA,sha256=AO2Y5aUTbMtg2R4iIbhmDRBibqP5KdWFug_LDrYPZXA,6959
178
- experimaestro-2.0.0b4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
179
- experimaestro-2.0.0b4.dist-info/entry_points.txt,sha256=S6AkrX0dM7MWcV-6QN6bazCcL18QAb-uyvmhtlI5hFI,440
180
- experimaestro-2.0.0b4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
181
- experimaestro-2.0.0b4.dist-info/RECORD,,
183
+ experimaestro-2.0.0b8.dist-info/METADATA,sha256=6xzN8WQQpLaaaTIA4Ujw7Jv4Sa7GP7a-VBYqAxj1eL8,6980
184
+ experimaestro-2.0.0b8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
185
+ experimaestro-2.0.0b8.dist-info/entry_points.txt,sha256=S6AkrX0dM7MWcV-6QN6bazCcL18QAb-uyvmhtlI5hFI,440
186
+ experimaestro-2.0.0b8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
187
+ experimaestro-2.0.0b8.dist-info/RECORD,,