meerschaum 2.2.6__py3-none-any.whl → 2.3.0.dev1__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.
Files changed (61) hide show
  1. meerschaum/__init__.py +4 -1
  2. meerschaum/__main__.py +10 -5
  3. meerschaum/_internal/arguments/_parser.py +44 -15
  4. meerschaum/_internal/entry.py +35 -14
  5. meerschaum/_internal/shell/Shell.py +155 -53
  6. meerschaum/_internal/shell/updates.py +175 -0
  7. meerschaum/actions/api.py +12 -12
  8. meerschaum/actions/attach.py +95 -0
  9. meerschaum/actions/delete.py +35 -26
  10. meerschaum/actions/register.py +19 -5
  11. meerschaum/actions/show.py +119 -148
  12. meerschaum/actions/start.py +85 -75
  13. meerschaum/actions/stop.py +68 -39
  14. meerschaum/actions/sync.py +3 -3
  15. meerschaum/actions/upgrade.py +28 -36
  16. meerschaum/api/_events.py +18 -1
  17. meerschaum/api/_oauth2.py +2 -0
  18. meerschaum/api/_websockets.py +2 -2
  19. meerschaum/api/dash/jobs.py +5 -2
  20. meerschaum/api/routes/__init__.py +1 -0
  21. meerschaum/api/routes/_actions.py +122 -44
  22. meerschaum/api/routes/_jobs.py +340 -0
  23. meerschaum/api/routes/_pipes.py +25 -25
  24. meerschaum/config/_default.py +1 -0
  25. meerschaum/config/_formatting.py +1 -0
  26. meerschaum/config/_paths.py +5 -0
  27. meerschaum/config/_shell.py +84 -67
  28. meerschaum/config/_version.py +1 -1
  29. meerschaum/config/static/__init__.py +9 -0
  30. meerschaum/connectors/__init__.py +9 -11
  31. meerschaum/connectors/api/APIConnector.py +18 -1
  32. meerschaum/connectors/api/_actions.py +60 -71
  33. meerschaum/connectors/api/_jobs.py +260 -0
  34. meerschaum/connectors/api/_misc.py +1 -1
  35. meerschaum/connectors/api/_request.py +13 -9
  36. meerschaum/connectors/parse.py +23 -7
  37. meerschaum/core/Pipe/_sync.py +3 -0
  38. meerschaum/plugins/__init__.py +89 -5
  39. meerschaum/utils/daemon/Daemon.py +333 -149
  40. meerschaum/utils/daemon/FileDescriptorInterceptor.py +19 -10
  41. meerschaum/utils/daemon/RotatingFile.py +18 -7
  42. meerschaum/utils/daemon/StdinFile.py +110 -0
  43. meerschaum/utils/daemon/__init__.py +40 -27
  44. meerschaum/utils/formatting/__init__.py +83 -37
  45. meerschaum/utils/formatting/_jobs.py +118 -51
  46. meerschaum/utils/formatting/_shell.py +6 -0
  47. meerschaum/utils/jobs/_Job.py +684 -0
  48. meerschaum/utils/jobs/__init__.py +245 -0
  49. meerschaum/utils/misc.py +18 -17
  50. meerschaum/utils/packages/__init__.py +21 -15
  51. meerschaum/utils/packages/_packages.py +2 -2
  52. meerschaum/utils/prompt.py +20 -7
  53. meerschaum/utils/schedule.py +21 -15
  54. {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/METADATA +9 -9
  55. {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/RECORD +61 -54
  56. {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/WHEEL +1 -1
  57. {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/LICENSE +0 -0
  58. {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/NOTICE +0 -0
  59. {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/entry_points.txt +0 -0
  60. {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/top_level.txt +0 -0
  61. {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/zip-safe +0 -0
@@ -7,86 +7,133 @@ Print jobs information.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
- from meerschaum.utils.typing import List, Optional, Any
11
- from meerschaum.utils.daemon import (
12
- Daemon,
13
- get_daemons,
14
- get_running_daemons,
15
- get_stopped_daemons,
16
- get_paused_daemons,
10
+
11
+ from datetime import datetime, timezone
12
+
13
+ import meerschaum as mrsm
14
+ from meerschaum.utils.typing import List, Optional, Any, is_success_tuple, Dict
15
+ from meerschaum.utils.jobs import (
16
+ Job,
17
+ get_jobs,
18
+ get_running_jobs,
19
+ get_stopped_jobs,
20
+ get_paused_jobs,
17
21
  )
22
+ from meerschaum.config import get_config
23
+
18
24
 
19
25
  def pprint_jobs(
20
- daemons: List[Daemon],
21
- nopretty: bool = False,
22
- ):
26
+ jobs: Dict[str, Job],
27
+ nopretty: bool = False,
28
+ ):
23
29
  """Pretty-print a list of Daemons."""
24
30
  from meerschaum.utils.formatting import make_header
25
31
 
26
- running_daemons = get_running_daemons(daemons)
27
- paused_daemons = get_paused_daemons(daemons)
28
- stopped_daemons = get_stopped_daemons(daemons)
32
+ running_jobs = get_running_jobs(jobs=jobs)
33
+ paused_jobs = get_paused_jobs(jobs=jobs)
34
+ stopped_jobs = get_stopped_jobs(jobs=jobs)
35
+ executor_keys = (list(jobs.values())[0].executor_keys if jobs else None) or 'local'
29
36
 
30
37
  def _nopretty_print():
31
38
  from meerschaum.utils.misc import print_options
32
- if running_daemons:
39
+ if running_jobs:
33
40
  if not nopretty:
34
41
  print('\n' + make_header('Running jobs'))
35
- for d in running_daemons:
36
- pprint_job(d, nopretty=nopretty)
42
+ for name, job in running_jobs.items():
43
+ pprint_job(job, nopretty=nopretty)
37
44
 
38
- if paused_daemons:
45
+ if paused_jobs:
39
46
  if not nopretty:
40
47
  print('\n' + make_header('Paused jobs'))
41
- for d in paused_daemons:
42
- pprint_job(d, nopretty=nopretty)
48
+ for name, job in paused_jobs.items():
49
+ pprint_job(job, nopretty=nopretty)
43
50
 
44
- if stopped_daemons:
51
+ if stopped_jobs:
45
52
  if not nopretty:
46
53
  print('\n' + make_header('Stopped jobs'))
47
- for d in stopped_daemons:
48
- pprint_job(d, nopretty=nopretty)
54
+ for name, job in stopped_jobs.items():
55
+ pprint_job(job, nopretty=nopretty)
49
56
 
50
57
  def _pretty_print():
51
- from meerschaum.utils.formatting import get_console, UNICODE, ANSI
58
+ from meerschaum.utils.formatting import get_console, UNICODE, ANSI, format_success_tuple
52
59
  from meerschaum.utils.packages import import_rich, attempt_import
53
60
  rich = import_rich()
54
- rich_table, rich_text, rich_box = attempt_import('rich.table', 'rich.text', 'rich.box')
61
+ rich_table, rich_text, rich_box, rich_json, rich_panel, rich_console = attempt_import(
62
+ 'rich.table', 'rich.text', 'rich.box', 'rich.json', 'rich.panel', 'rich.console',
63
+ )
55
64
  table = rich_table.Table(
56
- title = rich_text.Text('Jobs'),
57
- box = (rich_box.ROUNDED if UNICODE else rich_box.ASCII),
58
- show_lines = True,
59
- show_header = ANSI,
65
+ title=rich_text.Text(f"\nJobs on Executor '{executor_keys}'"),
66
+ box=(rich_box.ROUNDED if UNICODE else rich_box.ASCII),
67
+ show_lines=True,
68
+ show_header=ANSI,
60
69
  )
61
70
  table.add_column("Name", justify='right', style=('magenta' if ANSI else ''))
62
71
  table.add_column("Command")
63
72
  table.add_column("Status")
64
73
 
65
- for d in running_daemons:
66
- if d.hidden:
74
+ def get_success_text(job):
75
+ success_tuple = job.result
76
+ if not is_success_tuple(success_tuple):
77
+ return rich_text.Text('')
78
+
79
+ success = success_tuple[0]
80
+ msg = success_tuple[1]
81
+ lines = msg.split('\n')
82
+ msg = '\n'.join(line.lstrip().rstrip() for line in lines)
83
+ success_tuple = success, msg
84
+ success_tuple_str = (
85
+ format_success_tuple(success_tuple, left_padding=1)
86
+ if success_tuple is not None
87
+ else None
88
+ )
89
+ success_tuple_text = (
90
+ rich_text.Text.from_ansi(success_tuple_str)
91
+ ) if success_tuple_str is not None else None
92
+
93
+ if success_tuple_text is None:
94
+ return rich_text.Text('')
95
+
96
+ return rich_text.Text('\n') + success_tuple_text
97
+
98
+
99
+ for name, job in running_jobs.items():
100
+ if job.hidden:
67
101
  continue
102
+
103
+ status_text = (
104
+ rich_text.Text(job.status, style=('green' if ANSI else ''))
105
+ if not job.is_blocking_on_stdin()
106
+ else rich_text.Text('waiting for input', style=('yellow' if ANSI else ''))
107
+ )
108
+
68
109
  table.add_row(
69
- d.daemon_id,
70
- d.label,
71
- rich_text.Text(d.status, style=('green' if ANSI else ''))
110
+ job.name,
111
+ job.label,
112
+ rich_console.Group(status_text),
72
113
  )
73
114
 
74
- for d in paused_daemons:
75
- if d.hidden:
115
+ for name, job in paused_jobs.items():
116
+ if job.hidden:
76
117
  continue
77
118
  table.add_row(
78
- d.daemon_id,
79
- d.label,
80
- rich_text.Text(d.status, style=('yellow' if ANSI else ''))
119
+ job.name,
120
+ job.label,
121
+ rich_console.Group(
122
+ rich_text.Text(job.status, style=('yellow' if ANSI else '')),
123
+ ),
81
124
  )
82
125
 
83
- for d in stopped_daemons:
84
- if d.hidden:
126
+ for name, job in stopped_jobs.items():
127
+ if job.hidden:
85
128
  continue
129
+
86
130
  table.add_row(
87
- d.daemon_id,
88
- d.label,
89
- rich_text.Text(d.status, style=('red' if ANSI else ''))
131
+ job.name,
132
+ job.label,
133
+ rich_console.Group(
134
+ rich_text.Text(job.status, style=('red' if ANSI else '')),
135
+ get_success_text(job)
136
+ ),
90
137
  )
91
138
  get_console().print(table)
92
139
 
@@ -95,15 +142,35 @@ def pprint_jobs(
95
142
 
96
143
 
97
144
  def pprint_job(
98
- daemon: Daemon,
99
- nopretty: bool = False,
100
- ):
101
- """Pretty-print a single Daemon."""
102
- if daemon.hidden:
145
+ job: Job,
146
+ nopretty: bool = False,
147
+ ):
148
+ """Pretty-print a single `Job`."""
149
+ if job.hidden:
103
150
  return
151
+
104
152
  from meerschaum.utils.warnings import info
105
153
  if not nopretty:
106
- info(f"Command for job '{daemon.daemon_id}':")
107
- print('\n' + daemon.label + '\n')
154
+ info(f"Command for job '{job.name}':")
155
+ print('\n' + job.label + '\n')
108
156
  else:
109
- print(daemon.daemon_id)
157
+ print(job.name)
158
+
159
+
160
+ def strip_timestamp_from_line(line: str) -> str:
161
+ """
162
+ Remove the leading timestamp from a job's line (if present).
163
+ """
164
+ now = datetime.now(timezone.utc)
165
+ timestamp_format = get_config('jobs', 'logs', 'timestamps', 'format')
166
+ now_str = now.strftime(timestamp_format)
167
+
168
+ date_prefix_str = line[:len(now_str)]
169
+ try:
170
+ line_timestamp = datetime.strptime(date_prefix_str, timestamp_format)
171
+ except Exception:
172
+ line_timestamp = None
173
+ if line_timestamp:
174
+ line = line[(len(now_str) + 3):]
175
+
176
+ return line
@@ -47,9 +47,15 @@ def clear_screen(debug: bool = False) -> bool:
47
47
  from meerschaum.utils.formatting import ANSI, get_console
48
48
  from meerschaum.utils.debug import dprint
49
49
  from meerschaum.config import get_config
50
+ from meerschaum.utils.daemon import running_in_daemon
50
51
  global _tried_clear_command
52
+
53
+ if running_in_daemon():
54
+ return True
55
+
51
56
  if not get_config('shell', 'clear_screen'):
52
57
  return True
58
+
53
59
  print("", end="", flush=True)
54
60
  if debug:
55
61
  dprint("Skipping screen clear.")