meerschaum 2.3.0rc3__py3-none-any.whl → 2.3.1__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 (34) hide show
  1. meerschaum/__init__.py +2 -3
  2. meerschaum/_internal/arguments/__init__.py +1 -1
  3. meerschaum/_internal/arguments/_parse_arguments.py +33 -22
  4. meerschaum/_internal/arguments/_parser.py +4 -7
  5. meerschaum/_internal/docs/index.py +265 -8
  6. meerschaum/_internal/entry.py +42 -4
  7. meerschaum/_internal/shell/Shell.py +84 -72
  8. meerschaum/actions/__init__.py +21 -11
  9. meerschaum/actions/show.py +5 -5
  10. meerschaum/actions/start.py +71 -1
  11. meerschaum/api/routes/_actions.py +48 -1
  12. meerschaum/config/_paths.py +1 -0
  13. meerschaum/config/_version.py +1 -1
  14. meerschaum/config/static/__init__.py +2 -0
  15. meerschaum/connectors/__init__.py +1 -2
  16. meerschaum/connectors/api/APIConnector.py +6 -1
  17. meerschaum/connectors/api/_actions.py +77 -1
  18. meerschaum/connectors/api/_pipes.py +85 -84
  19. meerschaum/jobs/_Job.py +38 -6
  20. meerschaum/jobs/__init__.py +5 -3
  21. meerschaum/jobs/{_SystemdExecutor.py → systemd.py} +39 -22
  22. meerschaum/plugins/_Plugin.py +1 -1
  23. meerschaum/plugins/__init__.py +2 -1
  24. meerschaum/utils/daemon/StdinFile.py +1 -0
  25. meerschaum/utils/daemon/_names.py +14 -12
  26. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/METADATA +1 -1
  27. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/RECORD +33 -34
  28. meerschaum/jobs/_LocalExecutor.py +0 -88
  29. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/LICENSE +0 -0
  30. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/NOTICE +0 -0
  31. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/WHEEL +0 -0
  32. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/entry_points.txt +0 -0
  33. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/top_level.txt +0 -0
  34. {meerschaum-2.3.0rc3.dist-info → meerschaum-2.3.1.dist-info}/zip-safe +0 -0
meerschaum/__init__.py CHANGED
@@ -24,7 +24,7 @@ from meerschaum.utils.packages import attempt_import
24
24
  from meerschaum.core.Pipe import Pipe
25
25
  from meerschaum.plugins import Plugin
26
26
  from meerschaum.utils.venv import Venv
27
- from meerschaum.jobs import Job, Executor, make_executor
27
+ from meerschaum.jobs import Job, make_executor
28
28
  from meerschaum.connectors import get_connector, Connector, make_connector
29
29
  from meerschaum.utils import get_pipes
30
30
  from meerschaum.utils.formatting import pprint
@@ -45,13 +45,12 @@ __all__ = (
45
45
  "Venv",
46
46
  "Plugin",
47
47
  "Job",
48
- "Executor",
49
- "make_executor",
50
48
  "pprint",
51
49
  "attempt_import",
52
50
  "actions",
53
51
  "config",
54
52
  "connectors",
53
+ "jobs",
55
54
  "plugins",
56
55
  "utils",
57
56
  "SuccessTuple",
@@ -8,7 +8,7 @@ This package includes argument parsing utilities.
8
8
 
9
9
  from meerschaum._internal.arguments._parse_arguments import (
10
10
  parse_arguments, parse_line, remove_leading_action,
11
- parse_dict_to_sysargs, split_chained_sysargs,
11
+ parse_dict_to_sysargs, split_chained_sysargs, split_pipeline_sysargs,
12
12
  )
13
13
  from meerschaum._internal.arguments._parser import parser
14
14
  from meerschaum.plugins import add_plugin_argument
@@ -10,7 +10,7 @@ This module contains functions for parsing arguments
10
10
  from __future__ import annotations
11
11
  import json
12
12
  from datetime import timedelta
13
- from meerschaum.utils.typing import List, Dict, Any, Optional, Callable, SuccessTuple
13
+ from meerschaum.utils.typing import List, Dict, Any, Optional, Callable, SuccessTuple, Tuple
14
14
  from meerschaum.utils.threading import RLock
15
15
 
16
16
  _locks = {
@@ -18,10 +18,25 @@ _locks = {
18
18
  }
19
19
  _loaded_plugins_args: bool = False
20
20
 
21
+ def split_pipeline_sysargs(sysargs: List[str]) -> Tuple[List[str], List[str]]:
22
+ """
23
+ Split `sysargs` into the main pipeline and the flags following the pipeline separator (`:`).
24
+ """
25
+ from meerschaum.config.static import STATIC_CONFIG
26
+ pipeline_key = STATIC_CONFIG['system']['arguments']['pipeline_key']
27
+ if pipeline_key not in sysargs:
28
+ return sysargs, []
29
+
30
+ ### Find the index of the last occurrence of `:`.
31
+ pipeline_ix = len(sysargs) - 1 - sysargs[::-1].index(pipeline_key)
32
+ sysargs_after_pipeline_key = sysargs[pipeline_ix+1:]
33
+ sysargs = [arg for arg in sysargs[:pipeline_ix] if arg != pipeline_key]
34
+ return sysargs, sysargs_after_pipeline_key
35
+
21
36
 
22
37
  def split_chained_sysargs(sysargs: List[str]) -> List[List[str]]:
23
38
  """
24
- Split a `sysargs` list containing "and" keys (`&&`)
39
+ Split a `sysargs` list containing "and" keys (`+`)
25
40
  into a list of individual `sysargs`.
26
41
  """
27
42
  from meerschaum.config.static import STATIC_CONFIG
@@ -91,8 +106,8 @@ def parse_arguments(sysargs: List[str]) -> Dict[str, Any]:
91
106
  for i, word in enumerate(sysargs):
92
107
  is_sub_arg = False
93
108
  if not found_begin_decorator:
94
- found_begin_decorator = word.startswith(begin_decorator)
95
- found_end_decorator = word.endswith(end_decorator)
109
+ found_begin_decorator = str(word).startswith(begin_decorator)
110
+ found_end_decorator = str(word).endswith(end_decorator)
96
111
 
97
112
  if found_begin_decorator:
98
113
  ### check if sub arg is ever closed
@@ -102,15 +117,15 @@ def parse_arguments(sysargs: List[str]) -> Dict[str, Any]:
102
117
  found_begin_decorator = False
103
118
  elif found_end_decorator:
104
119
  for a in sysargs[:i]:
105
- if a.startswith(begin_decorator):
120
+ if str(a).startswith(begin_decorator):
106
121
  is_sub_arg = True
107
122
  found_begin_decorator = False
108
123
  if is_sub_arg:
109
124
  ### remove decorators
110
125
  sa = word
111
- if sa.startswith(begin_decorator):
126
+ if str(sa).startswith(begin_decorator):
112
127
  sa = sa[len(begin_decorator):]
113
- if sa.endswith(end_decorator):
128
+ if str(sa).endswith(end_decorator):
114
129
  sa = sa[:-1 * len(end_decorator)]
115
130
  sub_arguments.append(sa)
116
131
  ### remove sub-argument from action list
@@ -129,7 +144,7 @@ def parse_arguments(sysargs: List[str]) -> Dict[str, Any]:
129
144
  except Exception as e:
130
145
  _action = []
131
146
  for a in filtered_sysargs:
132
- if a.startswith('-'):
147
+ if str(a).startswith('-'):
133
148
  break
134
149
  _action.append(a)
135
150
  args_dict = {'action': _action, 'sysargs': sysargs}
@@ -249,20 +264,10 @@ def parse_dict_to_sysargs(
249
264
  from meerschaum.config.static import STATIC_CONFIG
250
265
  from meerschaum.utils.warnings import warn
251
266
 
252
- and_key = STATIC_CONFIG['system']['arguments']['and_key']
253
- if (line := args_dict.get('line', None)):
254
- return shlex.split(line)
255
-
256
- if (_sysargs := args_dict.get('sysargs', None)):
257
- return _sysargs
258
-
259
267
  action = args_dict.get('action', None)
260
- if action and and_key in action:
261
- warn(f"Cannot determine flags from chained actions:\n{args_dict}")
262
-
263
268
  sysargs: List[str] = []
264
269
  sysargs.extend(action or [])
265
- allow_none_args = {'location_keys'}
270
+ allow_none_args = {'location_keys', 'begin', 'end', 'executor_keys'}
266
271
 
267
272
  triggers = get_arguments_triggers()
268
273
 
@@ -273,12 +278,18 @@ def parse_dict_to_sysargs(
273
278
  ### Add boolean flags
274
279
  if isinstance(args_dict[a], bool):
275
280
  if args_dict[a] is True:
276
- sysargs += [t[0]]
281
+ sysargs.extend([t[0]])
277
282
  else:
278
283
  ### Add list flags
279
284
  if isinstance(args_dict[a], (list, tuple)):
280
285
  if len(args_dict[a]) > 0:
281
- sysargs += [t[0]] + list(args_dict[a])
286
+ sysargs.extend(
287
+ [t[0]]
288
+ + [
289
+ str(item)
290
+ for item in args_dict[a]
291
+ ]
292
+ )
282
293
 
283
294
  ### Add dict flags
284
295
  elif isinstance(args_dict[a], dict):
@@ -287,7 +298,7 @@ def parse_dict_to_sysargs(
287
298
 
288
299
  ### Account for None and other values
289
300
  elif (args_dict[a] is not None) or (args_dict[a] is None and a in allow_none_args):
290
- sysargs += [t[0], args_dict[a]]
301
+ sysargs += [t[0], str(args_dict[a])]
291
302
 
292
303
  return sysargs
293
304
 
@@ -125,7 +125,7 @@ def parse_version(sysargs: List[str]):
125
125
  return print(doc)
126
126
 
127
127
 
128
- def parse_name(name_str: str) -> str:
128
+ def parse_name(name_str: str) -> Union[str, None]:
129
129
  """
130
130
  Ensure that `--name` is not an empty string.
131
131
  """
@@ -215,13 +215,10 @@ groups['jobs'].add_argument(
215
215
  help=("Restart a job if not stopped manually."),
216
216
  )
217
217
  groups['jobs'].add_argument(
218
- '--systemd', action='store_true',
219
- help=("Create a job via systemd. Shorthand for `-e systemd`."),
220
- )
221
- groups['jobs'].add_argument(
222
- '--executor-keys', '--executor', '-e', type=parse_executor_keys,
218
+ '-e', '--executor-keys', type=parse_executor_keys,
223
219
  help=(
224
- "Execute jobs on an API instance or via systemd."
220
+ "Execute jobs locally or remotely. "
221
+ "Supported values are 'local', 'systemd', and 'api:{label}'."
225
222
  ),
226
223
  )
227
224
  groups['jobs'].add_argument(
@@ -36,8 +36,9 @@ For your convenience, the following classes and functions may be imported from t
36
36
  <li><code>meerschaum.Connector</code></li>
37
37
  <li><code>meerschaum.Pipe</code></li>
38
38
  <li><code>meerschaum.Plugin</code></li>
39
- <li><code>meerschaum.SuccessTuple</code></li>
39
+ <li><code>meerschaum.Job</code></li>
40
40
  <li><code>meerschaum.Venv</code></li>
41
+ <li><code>meerschaum.SuccessTuple</code></li>
41
42
  </ul>
42
43
 
43
44
  </div>
@@ -54,6 +55,7 @@ For your convenience, the following classes and functions may be imported from t
54
55
  <li><code>meerschaum.make_connector()</code></li>
55
56
  <li><code>meerschaum.pprint()</code></li>
56
57
  <li><code>meerschaum.attempt_import()</code></li>
58
+ <li><code>meerschaum.entry()</code></li>
57
59
  </ul>
58
60
 
59
61
  </div>
@@ -61,7 +63,10 @@ For your convenience, the following classes and functions may be imported from t
61
63
 
62
64
  ### Examples
63
65
 
64
- #### Build a Connector
66
+ <details>
67
+ <summary><b>Build a Connector</b></summary>
68
+
69
+ Get existing connectors or build a new one in-memory with the `meerschaum.get_connector()` factory function:
65
70
 
66
71
  ```python
67
72
  import meerschaum as mrsm
@@ -80,9 +85,14 @@ sql_conn.to_sql(df, 'foo')
80
85
  print(sql_conn.read('foo'))
81
86
  # foo
82
87
  # 0 1
88
+
83
89
  ```
90
+ </details>
91
+
92
+ <details>
93
+ <summary><b>Create a Custom Connector Class</b></summary>
84
94
 
85
- #### Create a Custom Connector Class
95
+ Decorate your connector classes with `meerschaum.make_connector()` to designate it as a custom connector:
86
96
 
87
97
  ```python
88
98
  from datetime import datetime, timezone
@@ -113,8 +123,12 @@ foo_conn = mrsm.get_connector(
113
123
  )
114
124
  docs = foo_conn.fetch()
115
125
  ```
126
+ </details>
116
127
 
117
- #### Build a Pipe
128
+ <details>
129
+ <summary><b>Build a Pipe</b></summary>
130
+
131
+ Build a `meerschaum.Pipe` in-memory:
118
132
 
119
133
  ```python
120
134
  from datetime import datetime
@@ -135,7 +149,23 @@ print(df)
135
149
  # 2 2024-01-01 3 96
136
150
  ```
137
151
 
138
- #### Get Registered Pipes
152
+ Add `temporary=True` to skip registering the pipe in the pipes table.
153
+
154
+ </details>
155
+
156
+ <details>
157
+ <summary><b>Get Registered Pipes</b></summary>
158
+
159
+ The `meerschaum.get_pipes()` function returns a dictionary hierarchy of pipes by connector, metric, and location:
160
+
161
+ ```python
162
+ import meerschaum as mrsm
163
+
164
+ pipes = mrsm.get_pipes(instance='sql:temp')
165
+ pipe = pipes['foo:bar']['demo'][None]
166
+ ```
167
+
168
+ Add `as_list=True` to flatten the hierarchy:
139
169
 
140
170
  ```python
141
171
  import meerschaum as mrsm
@@ -148,8 +178,12 @@ pipes = mrsm.get_pipes(
148
178
  print(pipes)
149
179
  # [Pipe('foo:bar', 'demo', instance='sql:temp')]
150
180
  ```
181
+ </details>
151
182
 
152
- #### Access a Plugin's Module
183
+ <details>
184
+ <summary><b>Import Plugins</b></summary>
185
+
186
+ You can import a plugin's module through `meerschaum.Plugin.module`:
153
187
 
154
188
  ```python
155
189
  import meerschaum as mrsm
@@ -157,10 +191,211 @@ import meerschaum as mrsm
157
191
  plugin = mrsm.Plugin('noaa')
158
192
  with mrsm.Venv(plugin):
159
193
  noaa = plugin.module
160
- print(noaa.get_station_info('KGMU'))
161
- # {'name': 'Greenville Downtown Airport', 'geometry': {'type': 'Point', 'coordinates': [-82.35004, 34.84873]}}
162
194
  ```
163
195
 
196
+ If your plugin has submodules, use `meerschaum.plugins.from_plugin_import`:
197
+
198
+ ```python
199
+ from meerschaum.plugins import from_plugin_import
200
+ get_defined_pipes = from_plugin_import('compose.utils.pipes', 'get_defined_pipes')
201
+ ```
202
+
203
+ Import multiple plugins with `meerschaum.plugins.import_plugins`:
204
+
205
+ ```python
206
+ from meerschaum.plugins import import_plugins
207
+ noaa, compose = import_plugins('noaa', 'compose')
208
+ ```
209
+
210
+ </details>
211
+
212
+ <details>
213
+ <summary><b>Create a Job</b></summary>
214
+
215
+ Create a `meerschaum.Job` with `name` and `sysargs`:
216
+
217
+ ```python
218
+ import meerschaum as mrsm
219
+
220
+ job = mrsm.Job('syncing-engine', 'sync pipes --loop')
221
+ success, msg = job.start()
222
+ ```
223
+
224
+ Pass `executor_keys` as the connectors keys of an API instance to create a remote job:
225
+
226
+ ```python
227
+ import meerschaum as mrsm
228
+
229
+ job = mrsm.Job(
230
+ 'foo',
231
+ 'sync pipes -s daily',
232
+ executor_keys='api:main',
233
+ )
234
+ ```
235
+
236
+ </details>
237
+
238
+ <details>
239
+ <summary><b>Import from a Virtual Environment</b></summary>
240
+ Use the `meerschaum.Venv` context manager to activate a virtual environment:
241
+ ```python
242
+ import meerschaum as mrsm
243
+
244
+ with mrsm.Venv('noaa'):
245
+ import requests
246
+
247
+ print(requests.__file__)
248
+ # /home/bmeares/.config/meerschaum/venvs/noaa/lib/python3.12/site-packages/requests/__init__.py
249
+ ```
250
+
251
+ To import packages which may not be installed, use `meerschaum.attempt_import()`:
252
+
253
+ ```python
254
+ import meerschaum as mrsm
255
+
256
+ requests = mrsm.attempt_import('requests', venv='noaa')
257
+ print(requests.__file__)
258
+ # /home/bmeares/.config/meerschaum/venvs/noaa/lib/python3.12/site-packages/requests/__init__.py
259
+ ```
260
+
261
+ </details>
262
+
263
+ <details>
264
+ <summary><b>Run Actions</b></summary>
265
+
266
+ Run `sysargs` with `meerschaum.entry()`:
267
+
268
+ ```python
269
+ import meerschaum as mrsm
270
+
271
+ success, msg = mrsm.entry('show pipes + show version : x2')
272
+ ```
273
+
274
+ Use `meerschaum.actions.get_action()` to access an action function directly:
275
+
276
+ ```python
277
+ from meerschaum.actions import get_action
278
+
279
+ show_pipes = get_action(['show', 'pipes'])
280
+ success, msg = show_pipes(connector_keys=['plugin:noaa'])
281
+ ```
282
+
283
+ Get a dictionary of available subactions with `meerschaum.actions.get_subactions()`:
284
+
285
+ ```python
286
+ from meerschaum.actions import get_subactions
287
+
288
+ subactions = get_subactions('show')
289
+ success, msg = subactions['pipes']()
290
+ ```
291
+
292
+ </details>
293
+
294
+ <details>
295
+ <summary><b>Create a Plugin</b></summary>
296
+
297
+ Run `bootstrap plugin` to create a new plugin:
298
+
299
+ ```
300
+ mrsm bootstrap plugin example
301
+ ```
302
+
303
+ This will create `example.py` in your plugins directory (default `~/.config/meerschaum/plugins/`, Windows: `%APPDATA%\Meerschaum\plugins`). You may paste the example code from the "Create a Custom Action" example below.
304
+
305
+ Open your plugin with `edit plugin`:
306
+
307
+ ```
308
+ mrsm edit plugin example
309
+ ```
310
+
311
+ *Run `edit plugin` and paste the example code below to try out the features.*
312
+
313
+ See the [writing plugins guide](https://meerschaum.io/reference/plugins/writing-plugins/) for more in-depth documentation.
314
+
315
+ </details>
316
+
317
+ <details>
318
+ <summary><b>Create a Custom Action</b></summary>
319
+
320
+ Decorate a function with `meerschaum.actions.make_action` to designate it as an action. Subactions will be automatically detected if not decorated:
321
+
322
+ ```python
323
+ from meerschaum.actions import make_action
324
+
325
+ @make_action
326
+ def sing():
327
+ print('What would you like me to sing?')
328
+ return True, "Success"
329
+
330
+ def sing_tune():
331
+ return False, "I don't know that song!"
332
+
333
+ def sing_song():
334
+ print('Hello, World!')
335
+ return True, "Success"
336
+
337
+ ```
338
+
339
+ Use `meerschaum.plugins.add_plugin_argument()` to create new parameters for your action:
340
+
341
+ ```python
342
+ from meerschaum.plugins import make_action, add_plugin_argument
343
+
344
+ add_plugin_argument(
345
+ '--song', type=str, help='What song to sing.',
346
+ )
347
+
348
+ @make_action
349
+ def sing_melody(action=None, song=None):
350
+ to_sing = action[0] if action else song
351
+ if not to_sing:
352
+ return False, "Please tell me what to sing!"
353
+
354
+ return True, f'~I am singing {to_sing}~'
355
+ ```
356
+
357
+ ```
358
+ mrsm sing melody lalala
359
+
360
+ mrsm sing melody --song do-re-mi
361
+ ```
362
+
363
+ </details>
364
+
365
+ <details>
366
+ <summary><b>Add a Page to the Web Dashboard</b></summary>
367
+ Use the decorators `meerschaum.plugins.dash_plugin()` and `meerschaum.plugins.web_page()` to add new pages to the web dashboard:
368
+
369
+ ```python
370
+ from meerschaum.plugins import dash_plugin, web_page
371
+
372
+ @dash_plugin
373
+ def init_dash(dash_app):
374
+
375
+ import dash.html as html
376
+ import dash_bootstrap_components as dbc
377
+ from dash import Input, Output, no_update
378
+
379
+ ### Routes to '/dash/my-page'
380
+ @web_page('/my-page', login_required=False)
381
+ def my_page():
382
+ return dbc.Container([
383
+ html.H1("Hello, World!"),
384
+ dbc.Button("Click me", id='my-button'),
385
+ html.Div(id="my-output-div"),
386
+ ])
387
+
388
+ @dash_app.callback(
389
+ Output('my-output-div', 'children'),
390
+ Input('my-button', 'n_clicks'),
391
+ )
392
+ def my_button_click(n_clicks):
393
+ if not n_clicks:
394
+ return no_update
395
+ return html.P(f'You clicked {n_clicks} times!')
396
+ ```
397
+ </details>
398
+
164
399
  ## Submodules
165
400
 
166
401
  <details>
@@ -206,6 +441,28 @@ with mrsm.Venv(plugin):
206
441
 
207
442
  </details>
208
443
 
444
+ <details>
445
+ <summary>
446
+ `meerschaum.jobs`<br>
447
+ Start background jobs.
448
+ </summary>
449
+
450
+ - `meerschaum.jobs.Job`
451
+ - `meerschaum.jobs.Executor`
452
+ - `meerschaum.jobs.systemd.SystemdExecutor`
453
+ - `meerschaum.jobs.get_jobs()`
454
+ - `meerschaum.jobs.get_filtered_jobs()`
455
+ - `meerschaum.jobs.get_running_jobs()`
456
+ - `meerschaum.jobs.get_stopped_jobs()`
457
+ - `meerschaum.jobs.get_paused_jobs()`
458
+ - `meerschaum.jobs.get_restart_jobs()`
459
+ - `meerschaum.jobs.make_executor()`
460
+ - `meerschaum.jobs.check_restart_jobs()`
461
+ - `meerschaum.jobs.start_check_jobs_thread()`
462
+ - `meerschaum.jobs.stop_check_jobs_thread()`
463
+
464
+ </details>
465
+
209
466
  <details>
210
467
  <summary>
211
468
  `meerschaum.plugins`<br>
@@ -32,7 +32,10 @@ if (_STATIC_CONFIG['environment']['systemd_log_path']) in os.environ:
32
32
  if _systemd_stdin_path:
33
33
  sys.stdin = _StdinFile(_systemd_stdin_path)
34
34
 
35
- def entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
35
+ def entry(
36
+ sysargs: Optional[List[str]] = None,
37
+ _patch_args: Optional[Dict[str, Any]] = None,
38
+ ) -> SuccessTuple:
36
39
  """
37
40
  Parse arguments and launch a Meerschaum action.
38
41
 
@@ -41,14 +44,23 @@ def entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
41
44
  A `SuccessTuple` indicating success.
42
45
  """
43
46
  import shlex
47
+ import json
44
48
  from meerschaum.utils.formatting import make_header
45
- from meerschaum._internal.arguments import parse_arguments, split_chained_sysargs
49
+ from meerschaum._internal.arguments import (
50
+ parse_arguments,
51
+ split_chained_sysargs,
52
+ split_pipeline_sysargs,
53
+ )
46
54
  from meerschaum.config.static import STATIC_CONFIG
47
55
  if sysargs is None:
48
56
  sysargs = []
49
57
  if not isinstance(sysargs, list):
50
58
  sysargs = shlex.split(sysargs)
51
59
 
60
+ pipeline_key = STATIC_CONFIG['system']['arguments']['pipeline_key']
61
+ escaped_pipeline_key = STATIC_CONFIG['system']['arguments']['escaped_pipeline_key']
62
+ sysargs, pipeline_args = split_pipeline_sysargs(sysargs)
63
+
52
64
  has_daemon = '-d' in sysargs or '--daemon' in sysargs
53
65
  has_start_job = sysargs[:2] == ['start', 'job']
54
66
  chained_sysargs = (
@@ -56,10 +68,32 @@ def entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
56
68
  if has_daemon or has_start_job
57
69
  else split_chained_sysargs(sysargs)
58
70
  )
71
+ if pipeline_args:
72
+ chained_sysargs = [
73
+ ['start', 'pipeline']
74
+ + [str(arg) for arg in pipeline_args]
75
+ + (
76
+ ['--params', json.dumps(_patch_args)]
77
+ if _patch_args
78
+ else []
79
+ )
80
+ + ['--sub-args', shlex.join(sysargs)]
81
+ ]
82
+
59
83
  results: List[SuccessTuple] = []
60
84
 
61
85
  for _sysargs in chained_sysargs:
86
+ if escaped_pipeline_key in _sysargs:
87
+ _sysargs = [
88
+ pipeline_key
89
+ if _arg == escaped_pipeline_key
90
+ else _arg
91
+ for _arg in _sysargs
92
+ ]
93
+
62
94
  args = parse_arguments(_sysargs)
95
+ if _patch_args:
96
+ args.update(_patch_args)
63
97
  argparse_exception = args.get(
64
98
  STATIC_CONFIG['system']['arguments']['failure_key'],
65
99
  None,
@@ -76,7 +110,7 @@ def entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
76
110
  )
77
111
  )
78
112
 
79
- entry_success, entry_msg = entry_with_args(**args)
113
+ entry_success, entry_msg = entry_with_args(_patch_args=_patch_args, **args)
80
114
  if not entry_success:
81
115
  return entry_success, entry_msg
82
116
 
@@ -106,6 +140,7 @@ def entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
106
140
 
107
141
  def entry_with_args(
108
142
  _actions: Optional[Dict[str, Callable[[Any], SuccessTuple]]] = None,
143
+ _patch_args: Optional[Dict[str, Any]] = None,
109
144
  **kw
110
145
  ) -> SuccessTuple:
111
146
  """Execute a Meerschaum action with keyword arguments.
@@ -119,12 +154,15 @@ def entry_with_args(
119
154
  from meerschaum.utils.venv import active_venvs, deactivate_venv
120
155
  from meerschaum.config.static import STATIC_CONFIG
121
156
 
157
+ if _patch_args:
158
+ kw.update(_patch_args)
159
+
122
160
  and_key = STATIC_CONFIG['system']['arguments']['and_key']
123
161
  escaped_and_key = STATIC_CONFIG['system']['arguments']['escaped_and_key']
124
162
  if and_key in (sysargs := kw.get('sysargs', [])):
125
163
  if '-d' in sysargs or '--daemon' in sysargs:
126
164
  sysargs = [(arg if arg != and_key else escaped_and_key) for arg in sysargs]
127
- return entry(sysargs)
165
+ return entry(sysargs, _patch_args=_patch_args)
128
166
 
129
167
  if kw.get('trace', None):
130
168
  from meerschaum.utils.misc import debug_trace