Skip to content

Commit bcf42d7

Browse files
authored
Merge pull request #1184 from xcube-dev/konstntokas-xxx-preload_add_params
Propagate preload params
2 parents e4db208 + 407c574 commit bcf42d7

File tree

2 files changed

+31
-39
lines changed

2 files changed

+31
-39
lines changed

CHANGES.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
`mldataset:jpeg2000:<protocol>`, where protocol is the respective file system.
1212
These openers and writers are available to any file system data store,
1313
e.g., `"file"`, `"s3"`.
14+
* Enhanced `ExecutorPreloadHandle` to propagate `preload_params` to the `preload_data`
15+
method, and renamed the `PreloadStatus` argument `stopped` to `completed`. (#1184)
16+
* Delegation of the visualization of the preload handle changed: If code runs as
17+
script, the class `PreloadDisplay` is used which visualizes the progress of the
18+
preload as a plain text; if the code is run in a Jupyter notebook cell, the class
19+
`IPyPreloadDisplay` and the progress of the preload is shown as a HTML table. (#1184)
20+
1421

1522
### Other changes
1623

xcube/core/store/preload.py

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class PreloadStatus(Enum):
2020

2121
waiting = "waiting"
2222
started = "started"
23-
stopped = "stopped"
23+
completed = "completed"
2424
cancelled = "cancelled"
2525
failed = "failed"
2626

@@ -195,10 +195,13 @@ class ExecutorPreloadHandle(PreloadHandle):
195195
def __init__(
196196
self,
197197
data_ids: tuple[str, ...],
198-
preload_data: Callable[[PreloadHandle, str], None] | None = None,
198+
preload_data: (
199+
Callable[[PreloadHandle, str, dict[str, Any]], None] | None
200+
) = None,
199201
executor: Executor | None = None,
200202
blocking: bool = True,
201203
silent: bool = False,
204+
**preload_params,
202205
):
203206
self._preload_data = preload_data
204207
self._executor = executor or ThreadPoolExecutor()
@@ -211,7 +214,9 @@ def __init__(
211214
self._lock = threading.Lock()
212215
self._futures: dict[str, Future[str]] = {}
213216
for data_id in data_ids:
214-
future: Future[str] = self._executor.submit(self._run_preload_data, data_id)
217+
future: Future[str] = self._executor.submit(
218+
self._run_preload_data, data_id, **preload_params
219+
)
215220
future.add_done_callback(self._handle_preload_data_done)
216221
self._futures[data_id] = future
217222

@@ -240,7 +245,7 @@ def notify(self, event: PreloadState):
240245
event.status is not None
241246
and event.status != state.status
242247
and state.status
243-
in (PreloadStatus.stopped, PreloadStatus.cancelled, PreloadStatus.failed)
248+
in (PreloadStatus.completed, PreloadStatus.cancelled, PreloadStatus.failed)
244249
):
245250
# Status cannot be changed
246251
return
@@ -249,7 +254,7 @@ def notify(self, event: PreloadState):
249254
if not self._silent:
250255
self._display.update()
251256

252-
def preload_data(self, data_id: str):
257+
def preload_data(self, data_id: str, **preload_params):
253258
"""Preload the data resource given by *data_id*.
254259
255260
Concurrently executes the *preload_data* passed to the constructor,
@@ -259,13 +264,14 @@ def preload_data(self, data_id: str):
259264
260265
Args:
261266
data_id: The data identifier of the data resource to be preloaded.
267+
preload_params: Specific parameters for the preloading workflow.
262268
"""
263269
if self._preload_data is not None:
264-
self._preload_data(self, data_id)
270+
self._preload_data(self, data_id, **preload_params)
265271

266-
def _run_preload_data(self, data_id: str) -> str:
272+
def _run_preload_data(self, data_id: str, **preload_params) -> str:
267273
self.notify(PreloadState(data_id, status=PreloadStatus.started))
268-
self.preload_data(data_id)
274+
self.preload_data(data_id, **preload_params)
269275
return data_id
270276

271277
def _handle_preload_data_done(self, f: Future[str]):
@@ -278,7 +284,7 @@ def _handle_preload_data_done(self, f: Future[str]):
278284
try:
279285
_value = f.result()
280286
# No exceptions, notify everything seems ok
281-
self.notify(PreloadState(data_id, status=PreloadStatus.stopped))
287+
self.notify(PreloadState(data_id, status=PreloadStatus.completed))
282288
except CancelledError as e:
283289
# Raised if future has been cancelled
284290
# while executing `_run_preload_data`
@@ -324,21 +330,23 @@ def __exit__(self, exc_type, exc_val, exc_tb):
324330

325331

326332
class PreloadDisplay(ABC):
333+
327334
@classmethod
328335
def create(
329336
cls, states: list[PreloadState], silent: bool | None = None
330337
) -> "PreloadDisplay":
331338
try:
332-
# noinspection PyUnresolvedReferences
333339
from IPython.display import display
340+
from IPython import get_ipython
334341

335-
if display is not None:
336-
try:
337-
return IPyWidgetsPreloadDisplay(states)
338-
except ImportError:
339-
return IPyPreloadDisplay(states)
340-
except ImportError:
342+
# Only use IPyGeneratorDisplay if we are actually inside a notebook
343+
shell = get_ipython().__class__.__name__
344+
if shell == "ZMQInteractiveShell":
345+
return IPyPreloadDisplay(states)
346+
except (ImportError, NameError, AttributeError):
341347
pass
348+
349+
# Default fallback: text-based display
342350
return PreloadDisplay(states)
343351

344352
def __init__(self, states: list[PreloadState]):
@@ -410,29 +418,6 @@ def log(self, message: str):
410418
self._ipy_display.display(message)
411419

412420

413-
class IPyWidgetsPreloadDisplay(IPyPreloadDisplay):
414-
def __init__(self, states: list[PreloadState]):
415-
super().__init__(states)
416-
import ipywidgets
417-
418-
self._state_table = ipywidgets.HTML(self.to_html())
419-
self._output = ipywidgets.Output() # not used yet
420-
self._container = ipywidgets.VBox([self._state_table, self._output])
421-
422-
def show(self):
423-
"""Display the widget container."""
424-
self._ipy_display.display(self._container)
425-
426-
def update(self):
427-
"""Update the display."""
428-
self._state_table.value = self.to_html()
429-
430-
def log(self, message: str):
431-
"""Log a message to the output widget."""
432-
with self._output:
433-
print(message)
434-
435-
436421
def _to_dict(obj: object):
437422
return {
438423
k: v

0 commit comments

Comments
 (0)