From 5c1eb9d7ba400db44dd59a9f8286e147edc22ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Brunner?= Date: Thu, 19 Dec 2024 12:17:03 +0100 Subject: [PATCH 1/2] Be sure that the config file exists --- tilecloud_chain/multitilestore.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tilecloud_chain/multitilestore.py b/tilecloud_chain/multitilestore.py index 31b3fa2fa..603f28212 100644 --- a/tilecloud_chain/multitilestore.py +++ b/tilecloud_chain/multitilestore.py @@ -29,7 +29,11 @@ def __init__(self, get_store: Callable[[str, str], TileStore | None]) -> None: self.stores: dict[tuple[str, str], _DatedStore | None] = {} def _get_store(self, config_file: str, layer: str) -> TileStore | None: - mtime = Path(config_file).stat().st_mtime + config_path = Path(config_file) + if not config_path.exists(): + logger.warning("Config file %s does not exist", config_file) + return None + mtime = config_path.stat().st_mtime store = self.stores.get((config_file, layer)) if store is not None and store.mtime != mtime: store = None From 71cfde6755c670c27f2fe3354cd228536f322093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Brunner?= Date: Thu, 19 Dec 2024 14:37:17 +0100 Subject: [PATCH 2/2] Multi action will reload the action on file change, better representation --- tilecloud_chain/__init__.py | 45 ++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/tilecloud_chain/__init__.py b/tilecloud_chain/__init__.py index 05c3cc7a8..cc9950671 100644 --- a/tilecloud_chain/__init__.py +++ b/tilecloud_chain/__init__.py @@ -19,6 +19,7 @@ from argparse import ArgumentParser, Namespace from collections.abc import Callable, Iterable, Iterator from concurrent.futures import ThreadPoolExecutor +from dataclasses import dataclass from datetime import datetime, timedelta from fractions import Fraction from hashlib import sha1 @@ -1542,6 +1543,14 @@ def __call__(self, tile: Tile) -> Tile | None: return None +@dataclass +class _DatedAction: + """Dated action.""" + + mtime: float + action: Callable[[Tile], Tile | None] + + class MultiAction: """ Used to perform an action based on the tile's layer name. @@ -1554,21 +1563,47 @@ def __init__( get_action: Callable[[str, str], Callable[[Tile], Tile | None] | None], ) -> None: self.get_action = get_action - self.actions: dict[tuple[str, str], Callable[[Tile], Tile | None] | None] = {} + self.actions: dict[tuple[str, str], _DatedAction | None] = {} + + def _get_action(self, config_file: str, layer: str) -> Callable[[Tile], Tile | None] | None: + """Get the action based on the tile's layer name.""" + config_path = pathlib.Path(config_file) + if not config_path.exists(): + _LOGGER.warning("Config file %s does not exist", config_file) + return None + mtime = config_path.stat().st_mtime + action = self.actions.get((config_file, layer)) + if action is not None and action.mtime != mtime: + action = None + if action is None: + action_item = self.get_action(config_file, layer) + if action_item is not None: + action = _DatedAction(mtime, action_item) + self.actions[(config_file, layer)] = action + return action.action if action is not None else None def __call__(self, tile: Tile) -> Tile | None: """Run the action.""" layer = tile.metadata["layer"] config_file = tile.metadata["config_file"] - action = self.actions.get((config_file, layer)) - if action is None: - action = self.get_action(config_file, layer) - self.actions[(config_file, layer)] = action + action = self._get_action(config_file, layer) if action: _LOGGER.debug("[%s] Run action %s.", tile.tilecoord, action) return action(tile) return tile + def __str__(self) -> str: + """Return a string representation of the object.""" + actions = {str(action) for action in self.actions.values()} + keys = {f"{config_file}:{layer}" for config_file, layer in self.actions} + return f"{self.__class__.__name__}({', '.join(actions)} - {', '.join(keys)})" + + def __repr__(self) -> str: + """Return a string representation of the object.""" + actions = {repr(action) for action in self.actions.values()} + keys = {f"{config_file}:{layer}" for config_file, layer in self.actions} + return f"{self.__class__.__name__}({', '.join(actions)} - {', '.join(keys)})" + class HashLogger: """Log the tile size and hash."""