pipelime-python 2.1.0__py3-none-any.whl → 2.3.0__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.
pipelime/__init__.py CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  __author__ = "Eyecan.ai"
4
4
  __email__ = "info@eyecan.ai"
5
- __version__ = "2.1.0"
5
+ __version__ = "2.3.0"
pipelime/cli/utils.py CHANGED
@@ -816,7 +816,9 @@ def get_user_input(text: str) -> t.Any:
816
816
  Returns:
817
817
  The parsed user input.
818
818
  """
819
- live = get_console()._live
819
+ # if there is only one live, pause it to avoid messing the prompt
820
+ live_stack = get_console()._live_stack
821
+ live = live_stack[0] if len(live_stack) == 1 else None
820
822
  if live is not None:
821
823
  live.stop()
822
824
 
@@ -878,7 +880,7 @@ class PipelimeUserAppDir:
878
880
  for i in reversed(range(1, cls.MAX_CHECKPOINTS)):
879
881
  ckpt = base_ckpt.with_name(base_ckpt.name + f"-{i}")
880
882
  if ckpt.exists():
881
- ckpt.rename(base_ckpt.with_name(base_ckpt.name + f"-{i+1}"))
883
+ ckpt.rename(base_ckpt.with_name(base_ckpt.name + f"-{i + 1}"))
882
884
 
883
885
  ckpt = base_ckpt.with_name(base_ckpt.name + "-1")
884
886
  ckpt.mkdir(parents=True, exist_ok=False)
@@ -25,11 +25,13 @@ class WatcherBackend(Enum):
25
25
 
26
26
  RICH = "rich"
27
27
  TQDM = "tqdm"
28
+ LOGURU = "loguru"
28
29
 
29
30
  def listener_key(self) -> str:
30
31
  return {
31
32
  WatcherBackend.RICH: "RICH_TABLE",
32
33
  WatcherBackend.TQDM: "TQDM_BARS",
34
+ WatcherBackend.LOGURU: "LOGURU",
33
35
  }[self]
34
36
 
35
37
 
@@ -254,8 +256,10 @@ class RunCommandBase(GraphPortForwardingCommand):
254
256
 
255
257
  PipelimeCommand._track_callback = DirectTrackCallback(callback)
256
258
 
257
- # disable annoying logging
258
- logger.disable("pipelime")
259
+ # disable annoying logging (only if we don't need it for the watcher)
260
+ if watch != WatcherBackend.LOGURU:
261
+ logger.disable("pipelime")
262
+
259
263
  exit_stack.callback(logger.enable, "pipelime")
260
264
  exit_stack.callback(PipelimeCommand._track_callback.stop_callbacks)
261
265
 
@@ -456,7 +460,8 @@ class WatchCommand(PipelimeCommand, title="watch"):
456
460
  from pipelime.utils.context_managers import CatchSignals
457
461
 
458
462
  receiver = ProgressReceiverFactory.get_receiver(
459
- self.token, **({"port": self.port} if self.port else {}) # type: ignore
463
+ self.token,
464
+ **({"port": self.port} if self.port else {}), # type: ignore
460
465
  )
461
466
  if isinstance(self.watcher, WatcherBackend):
462
467
  callback = ListenerCallbackFactory.get_callback(
@@ -0,0 +1,79 @@
1
+ import ast
2
+ import json
3
+ import os
4
+ from typing import ClassVar
5
+
6
+ from loguru import logger
7
+
8
+ from pipelime.piper.progress.listener.base import ListenerCallback
9
+ from pipelime.piper.progress.model import ProgressUpdate
10
+
11
+
12
+ class LoguruListenerCallback(ListenerCallback):
13
+ """Listener callback that sends progress updates to loguru.
14
+
15
+ Args:
16
+ show_token: Whether to include the token in the logged data.
17
+ log_extras: Extra fields to bind to the logger. Can also be set via
18
+ environment variables with the prefix PIPELIME_PROGRESS_LOG_EXTRA_
19
+ (e.g., PIPELIME_PROGRESS_LOG_EXTRA_key=value). Environment variables
20
+ take precedence over this argument.
21
+ level: Logging level to use. Can also be set via the environment variable
22
+ PIPELIME_PROGRESS_LOG_LEVEL. Defaults to "DEBUG".
23
+ """
24
+
25
+ LOG_LEVEL_ENV_VAR: ClassVar[str] = "PIPELIME_PROGRESS_LOG_LEVEL"
26
+ LOG_EXTRA_ENV_VAR_PREFIX: ClassVar[str] = "PIPELIME_PROGRESS_LOG_EXTRA_"
27
+
28
+ @classmethod
29
+ def update_data(cls, data: dict, prog: ProgressUpdate, show_token: bool) -> None:
30
+ """Update the data dictionary with the progress update"""
31
+ root = data.setdefault(prog.op_info.token, dict()) if show_token else data
32
+
33
+ chunk_data = root.setdefault(prog.op_info.node, dict()).setdefault(
34
+ str(prog.op_info.chunk), dict()
35
+ )
36
+ chunk_data["message"] = prog.op_info.message
37
+ chunk_data["total"] = prog.op_info.total
38
+ chunk_data["progress"] = prog.progress
39
+ chunk_data["finished"] = prog.finished
40
+
41
+ def __init__(
42
+ self,
43
+ show_token: bool = False,
44
+ log_extras: dict | None = None,
45
+ level: str = "DEBUG",
46
+ ) -> None:
47
+ super().__init__(show_token)
48
+
49
+ self._data: dict = dict()
50
+
51
+ # collect log extras from environment variables
52
+ env_extras = {}
53
+ for key, value in os.environ.items():
54
+ if key.startswith(self.LOG_EXTRA_ENV_VAR_PREFIX):
55
+ extra_key = key[len(self.LOG_EXTRA_ENV_VAR_PREFIX) :].lower()
56
+ try:
57
+ env_extras[extra_key] = ast.literal_eval(value)
58
+ except (ValueError, SyntaxError):
59
+ env_extras[extra_key] = value
60
+
61
+ # merge env extras with provided extras (env vars take precedence)
62
+ log_extras = log_extras or {}
63
+ self._log_extras = {**log_extras, **env_extras}
64
+
65
+ # determine log level (env var takes precedence)
66
+ self._level = os.getenv(self.LOG_LEVEL_ENV_VAR, level).upper()
67
+
68
+ def _log_data(self) -> None:
69
+ if self._data:
70
+ logger.bind(**self._log_extras).log(self._level, json.dumps(self._data))
71
+
72
+ def on_update(self, prog: ProgressUpdate) -> None:
73
+ """Called when a progress update is received"""
74
+ LoguruListenerCallback.update_data(self._data, prog, self.show_token)
75
+ self._log_data()
76
+
77
+ def on_stop(self) -> None:
78
+ """Called when the listener stops - ensures final progress is sent"""
79
+ self._log_data()
@@ -1,13 +1,15 @@
1
1
  from typing import Optional
2
+
2
3
  from pipelime.piper.progress.listener.base import ListenerCallback, ProgressReceiver
3
- from pipelime.piper.progress.listener.receiver.zmq import ZMQProgressReceiver
4
+ from pipelime.piper.progress.listener.callbacks.file import FileListenerCallback
5
+ from pipelime.piper.progress.listener.callbacks.loguru import LoguruListenerCallback
4
6
  from pipelime.piper.progress.listener.callbacks.rich_table import (
5
7
  RichTableListenerCallback,
6
8
  )
7
9
  from pipelime.piper.progress.listener.callbacks.tqdm_bars import (
8
10
  TqdmBarsListenerCallback,
9
11
  )
10
- from pipelime.piper.progress.listener.callbacks.file import FileListenerCallback
12
+ from pipelime.piper.progress.listener.receiver.zmq import ZMQProgressReceiver
11
13
 
12
14
 
13
15
  class ProgressReceiverFactory:
@@ -35,6 +37,7 @@ class ListenerCallbackFactory:
35
37
  "RICH_TABLE": RichTableListenerCallback,
36
38
  "TQDM_BARS": TqdmBarsListenerCallback,
37
39
  "FILE": FileListenerCallback,
40
+ "LOGURU": LoguruListenerCallback,
38
41
  }
39
42
 
40
43
  @classmethod
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: pipelime-python
3
- Version: 2.1.0
3
+ Version: 2.3.0
4
4
  Summary: Data workflows, cli and dataflow automation.
5
5
  Project-URL: Source, https://github.com/eyecan-ai/pipelime-python
6
6
  Project-URL: Issues, https://github.com/eyecan-ai/pipelime-python/issues
@@ -19,9 +19,10 @@ Classifier: Programming Language :: Python :: 3
19
19
  Classifier: Programming Language :: Python :: 3.10
20
20
  Classifier: Programming Language :: Python :: 3.11
21
21
  Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
22
23
  Classifier: Topic :: Scientific/Engineering
23
24
  Classifier: Topic :: Software Development
24
- Requires-Python: <3.13,>=3.10
25
+ Requires-Python: <3.14,>=3.10
25
26
  Requires-Dist: albumentations>=1.0.0
26
27
  Requires-Dist: astunparse
27
28
  Requires-Dist: deepdiff
@@ -1,5 +1,5 @@
1
1
  LICENSE,sha256=Ufc-hKELjY574QxuUAosOjRD6RO0x_Y3jtnNbjRK5pc,1525
2
- pipelime/__init__.py,sha256=XdKxm5F9mco63-Q1cyLZzd3l0CN1F4ZAfgNnW27y11g,115
2
+ pipelime/__init__.py,sha256=bT9rQeSERfVxEwn3AugYS3SczbXoOrEPBPwq57BN5Sw,115
3
3
  pipelime/choixe/__init__.py,sha256=sFXmatlOorxsGTrB0q6W8RUA0KNqnC4qiRbDRbRZrBM,52
4
4
  pipelime/choixe/xconfig.py,sha256=b3ensxAIXgLNw_mVb6_yNnvkHEEGvuJmIN120ACnQlI,15124
5
5
  pipelime/choixe/ast/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -22,7 +22,7 @@ pipelime/cli/main.py,sha256=jvK-IabaiOJBW7GxGV_175AY73V5wrr_gStRWQcD9XU,34629
22
22
  pipelime/cli/parser.py,sha256=8zUpfr5Ijed6dzjomGnT-uVC5xNjBgGl3_Gld8lTKB0,8623
23
23
  pipelime/cli/pretty_print.py,sha256=X3jld46DFC_Lmrl9Sejs5Tb5Mmv0bLfPPVdHhR-7fsU,15277
24
24
  pipelime/cli/subcommands.py,sha256=NIjzapuj_NVcljd1AWGlVt-r-HOj8noM3nohITta4dk,1705
25
- pipelime/cli/utils.py,sha256=_xF2T3mjtAQGE1tYcCFb4NuTVu9smBOgWRgevXP9Ne8,28595
25
+ pipelime/cli/utils.py,sha256=H6dXwYO489_jx6_YmvBT4B6hKPzjZDUL8cOzfLL9lhw,28738
26
26
  pipelime/cli/tui/__init__.py,sha256=9bmQNLmJHeZIQMcqbU99b7OgrdbeEJKAZ142TD6_fM0,89
27
27
  pipelime/cli/tui/tui.css,sha256=_W_Q0eDVT7hAbmBm3KsjA0GnDGheXaasnyZIYC9ZNjU,452
28
28
  pipelime/cli/tui/tui.py,sha256=79iNTPe4TvJwkZVnnf-Iqk3rT_b2lntqZon7N5Yxy48,10163
@@ -30,7 +30,7 @@ pipelime/cli/tui/utils.py,sha256=JaVAzfbdLVzrst6NzNCN5CVO0_gOREOy2142ysmmxkk,644
30
30
  pipelime/commands/__init__.py,sha256=pk6Xr0MW7FDwtqJPOyzHhz6-vYksRzMw79HlhzhRDj4,741
31
31
  pipelime/commands/general.py,sha256=xPJYj5rnS4-aBY4B5AJt9RMZ4cP7JqyQeaG8EaQGGSs,37237
32
32
  pipelime/commands/interfaces.py,sha256=aE42ysEy7YMwhzPMrTLoebeYKf4N1KSWKYWuUx_nY3Q,34348
33
- pipelime/commands/piper.py,sha256=luq7tk5Tr2i2k2KQX9h0DznF3c10yVptAY9Rtmne0YI,23771
33
+ pipelime/commands/piper.py,sha256=HkG2dt9UK1dQTq9HNGQ3rwDnabU-t8lBaqf1ED0kPiM,23946
34
34
  pipelime/commands/resume.py,sha256=AGcf8UFttxUD5_Ojq7G41NxsKRD_bjXzkqt6rgXURcg,2581
35
35
  pipelime/commands/shell.py,sha256=wrW6WGVP_05t28B3CDHQoRb812_wQr8EHOFPemAnXE0,2502
36
36
  pipelime/commands/split_ops.py,sha256=hvYYZ4ReoIn2ngkcL-tVaq5qwy1jHRCx0g0rT64lMR0,13669
@@ -69,9 +69,10 @@ pipelime/piper/progress/estimator/factory.py,sha256=153f9SxceXibIsDELkhzrHAXDVO9
69
69
  pipelime/piper/progress/estimator/naive.py,sha256=3NGGCD4IQXEORblfs3XEhERRQ8MVgTcwfl8d57ux3Ds,1382
70
70
  pipelime/piper/progress/listener/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
71
  pipelime/piper/progress/listener/base.py,sha256=OPHOOs-A0NvCtJkGLmK-r5w6TrPtZ9hCBtQ9XSO21yM,3089
72
- pipelime/piper/progress/listener/factory.py,sha256=PVLV9pbcGA6XDPTBT1hl6lgg3aM1g7MwC2yWcauFsRg,1295
72
+ pipelime/piper/progress/listener/factory.py,sha256=M4PWel_rlbwMpw0B9rWhggNbZ76Rfyb62yIq4E4u01k,1423
73
73
  pipelime/piper/progress/listener/callbacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
74
  pipelime/piper/progress/listener/callbacks/file.py,sha256=JWRJYoEtsY9mWLdBf1RoMlhTmsUbWv8kD5hOZCVcrCs,2170
75
+ pipelime/piper/progress/listener/callbacks/loguru.py,sha256=Vb8mjK1A2zXDY9o0Juh2vEHuixnpamN7TseMKsv8CMk,3041
75
76
  pipelime/piper/progress/listener/callbacks/rich_table.py,sha256=s10TM1arqMz7NTMp9kZeHe-o9HlvdxlUT5xH3_HmJ7M,3442
76
77
  pipelime/piper/progress/listener/callbacks/tqdm_bars.py,sha256=3TqKz6g79jaURplmeQg4SkJhEqVSCxK-CsT6_si82Es,1945
77
78
  pipelime/piper/progress/listener/receiver/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -113,8 +114,8 @@ pipelime/utils/context_managers.py,sha256=C3ubzFVBPNG_wu1jqKc0o1Vy1sxsZ-UzFKry2g
113
114
  pipelime/utils/deprecated.py,sha256=rBlOk3cJPZw3jB7QuIY8U3LPWLuovpj8Mfarn65GrqU,1544
114
115
  pipelime/utils/inspection.py,sha256=mpfx-wnoDrocpZ5nlh--XtqEGQEEo9WIYIlF18WXXWg,1369
115
116
  pipelime/utils/pydantic_types.py,sha256=OGw1bNdWmIRTFkF-fPBHLzAVqaTtrsaS6-mUZ8zgHSg,24955
116
- pipelime_python-2.1.0.dist-info/METADATA,sha256=fFTCHqhJSlF9tolV9gHA6L3m2-U_R0f1ncUHXV3LkRg,8509
117
- pipelime_python-2.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
118
- pipelime_python-2.1.0.dist-info/entry_points.txt,sha256=hY61hWhOC6q8tq5Qj5oOOEjZo9dtOrztO7IXylYsoTo,61
119
- pipelime_python-2.1.0.dist-info/licenses/LICENSE,sha256=Ufc-hKELjY574QxuUAosOjRD6RO0x_Y3jtnNbjRK5pc,1525
120
- pipelime_python-2.1.0.dist-info/RECORD,,
117
+ pipelime_python-2.3.0.dist-info/METADATA,sha256=QVznwKUF2I2NPMRnMYj0JxS0HihUzd7IKitKGAHccJ4,8560
118
+ pipelime_python-2.3.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
119
+ pipelime_python-2.3.0.dist-info/entry_points.txt,sha256=hY61hWhOC6q8tq5Qj5oOOEjZo9dtOrztO7IXylYsoTo,61
120
+ pipelime_python-2.3.0.dist-info/licenses/LICENSE,sha256=Ufc-hKELjY574QxuUAosOjRD6RO0x_Y3jtnNbjRK5pc,1525
121
+ pipelime_python-2.3.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.32.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any