meerschaum 2.4.10__py3-none-any.whl → 2.4.12__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 (33) hide show
  1. meerschaum/_internal/arguments/_parse_arguments.py +15 -1
  2. meerschaum/_internal/docs/index.py +1 -0
  3. meerschaum/_internal/shell/Shell.py +19 -9
  4. meerschaum/_internal/shell/ShellCompleter.py +11 -6
  5. meerschaum/actions/bootstrap.py +120 -15
  6. meerschaum/actions/clear.py +41 -30
  7. meerschaum/actions/edit.py +89 -0
  8. meerschaum/actions/start.py +3 -2
  9. meerschaum/actions/sync.py +3 -2
  10. meerschaum/api/dash/callbacks/dashboard.py +2 -1
  11. meerschaum/api/dash/callbacks/jobs.py +53 -7
  12. meerschaum/api/dash/callbacks/pipes.py +1 -1
  13. meerschaum/api/dash/jobs.py +86 -60
  14. meerschaum/api/dash/pages/__init__.py +1 -0
  15. meerschaum/api/dash/pages/job.py +21 -0
  16. meerschaum/api/routes/_jobs.py +3 -3
  17. meerschaum/config/_version.py +1 -1
  18. meerschaum/connectors/sql/_fetch.py +65 -61
  19. meerschaum/connectors/sql/_pipes.py +36 -29
  20. meerschaum/core/Pipe/_data.py +1 -1
  21. meerschaum/utils/formatting/__init__.py +32 -16
  22. meerschaum/utils/formatting/_pipes.py +1 -1
  23. meerschaum/utils/formatting/_shell.py +4 -3
  24. meerschaum/utils/prompt.py +16 -15
  25. meerschaum/utils/sql.py +107 -35
  26. {meerschaum-2.4.10.dist-info → meerschaum-2.4.12.dist-info}/METADATA +1 -1
  27. {meerschaum-2.4.10.dist-info → meerschaum-2.4.12.dist-info}/RECORD +33 -32
  28. {meerschaum-2.4.10.dist-info → meerschaum-2.4.12.dist-info}/WHEEL +1 -1
  29. {meerschaum-2.4.10.dist-info → meerschaum-2.4.12.dist-info}/LICENSE +0 -0
  30. {meerschaum-2.4.10.dist-info → meerschaum-2.4.12.dist-info}/NOTICE +0 -0
  31. {meerschaum-2.4.10.dist-info → meerschaum-2.4.12.dist-info}/entry_points.txt +0 -0
  32. {meerschaum-2.4.10.dist-info → meerschaum-2.4.12.dist-info}/top_level.txt +0 -0
  33. {meerschaum-2.4.10.dist-info → meerschaum-2.4.12.dist-info}/zip-safe +0 -0
@@ -256,7 +256,8 @@ def parse_synonyms(
256
256
 
257
257
 
258
258
  def parse_dict_to_sysargs(
259
- args_dict: Dict[str, Any]
259
+ args_dict: Dict[str, Any],
260
+ coerce_dates: bool = True,
260
261
  ) -> List[str]:
261
262
  """Revert an arguments dictionary back to a command line list."""
262
263
  import shlex
@@ -304,6 +305,19 @@ def parse_dict_to_sysargs(
304
305
  if len(args_dict[a]) > 0:
305
306
  sysargs += [t[0], json.dumps(args_dict[a], separators=(',', ':'))]
306
307
 
308
+ ### Preserve the original datetime strings if possible
309
+ elif a in ('begin', 'end') and 'sysargs' in args_dict:
310
+ flag = t[0]
311
+ flag_ix = args_dict['sysargs'].index(flag)
312
+ if flag_ix < 0:
313
+ continue
314
+ try:
315
+ flag_val = args_dict['sysargs'][flag_ix + 1]
316
+ except IndexError:
317
+ flag_val = str(args_dict[a])
318
+
319
+ sysargs += [flag, str(flag_val)]
320
+
307
321
  ### Account for None and other values
308
322
  elif (args_dict[a] is not None) or (args_dict[a] is None and a in allow_none_args):
309
323
  sysargs += [t[0], str(args_dict[a])]
@@ -742,6 +742,7 @@ def init_dash(dash_app):
742
742
  <li><code>meerschaum.utils.sql.get_db_version()</code></li>
743
743
  <li><code>meerschaum.utils.sql.get_rename_table_queries()</code></li>
744
744
  <li><code>meerschaum.utils.sql.get_create_table_query()</code></li>
745
+ <li><code>meerschaum.utils.sql.wrap_query_with_cte()</code></li>
745
746
  <li><code>meerschaum.utils.sql.format_cte_subquery()</code></li>
746
747
  <li><code>meerschaum.utils.sql.session_execute()</code></li>
747
748
  </ul>
@@ -235,6 +235,23 @@ def get_shell_intro(with_color: bool = True) -> str:
235
235
  **get_config('shell', 'ansi', 'intro', 'rich')
236
236
  )
237
237
 
238
+ def get_shell_session():
239
+ """
240
+ Return the `prompt_toolkit` prompt session.
241
+ """
242
+ from meerschaum.config._paths import SHELL_HISTORY_PATH
243
+ if 'session' in shell_attrs:
244
+ return shell_attrs['session']
245
+
246
+ shell_attrs['session'] = prompt_toolkit_shortcuts.PromptSession(
247
+ history=prompt_toolkit_history.FileHistory(SHELL_HISTORY_PATH.as_posix()),
248
+ auto_suggest=ValidAutoSuggest(),
249
+ completer=ShellCompleter(),
250
+ complete_while_typing=True,
251
+ reserve_space_for_menu=False,
252
+ )
253
+ return shell_attrs['session']
254
+
238
255
 
239
256
  class Shell(cmd.Cmd):
240
257
  """
@@ -264,14 +281,7 @@ class Shell(cmd.Cmd):
264
281
  except AttributeError:
265
282
  pass
266
283
 
267
- from meerschaum.config._paths import SHELL_HISTORY_PATH
268
- shell_attrs['session'] = prompt_toolkit_shortcuts.PromptSession(
269
- history=prompt_toolkit_history.FileHistory(SHELL_HISTORY_PATH.as_posix()),
270
- auto_suggest=ValidAutoSuggest(),
271
- completer=ShellCompleter(),
272
- complete_while_typing=True,
273
- reserve_space_for_menu=False,
274
- )
284
+ _ = get_shell_session()
275
285
 
276
286
  super().__init__()
277
287
 
@@ -626,7 +636,7 @@ class Shell(cmd.Cmd):
626
636
  step_action_name = step_action[0] if step_action else None
627
637
  ### NOTE: For `stack`, revert argument parsing.
628
638
  step_sysargs = (
629
- parse_dict_to_sysargs(step_kwargs)
639
+ parse_dict_to_sysargs(step_kwargs, coerce_dates=False)
630
640
  if step_action_name != 'stack'
631
641
  else chained_sysargs[i]
632
642
  )
@@ -31,15 +31,18 @@ class ShellCompleter(Completer):
31
31
  ensure_readline()
32
32
  parts = document.text.split('-')
33
33
  ends_with_space = parts[0].endswith(' ')
34
- part_0_subbed_spaces = parts[0].replace(' ', '_')
35
- parsed_text = part_0_subbed_spaces + '-'.join(parts[1:])
34
+ last_action_line = parts[0].split('+')[-1]
35
+ part_0_subbed_spaces = last_action_line.replace(' ', '_')
36
+ parsed_text = (part_0_subbed_spaces + '-'.join(parts[1:]))
36
37
 
38
+ if not parsed_text:
39
+ return
37
40
 
38
41
  ### Index is the rank order (0 is closest match).
39
42
  ### Break when no results are returned.
40
43
  for i, a in enumerate(shell_actions):
41
44
  try:
42
- poss = shell.complete(parsed_text, i)
45
+ poss = shell.complete(parsed_text.lstrip('_'), i)
43
46
  if poss:
44
47
  poss = poss.replace('_', ' ')
45
48
  ### Having issues with readline on portable Windows.
@@ -50,7 +53,9 @@ class ShellCompleter(Completer):
50
53
  yield Completion(poss, start_position=(-1 * len(poss)))
51
54
  yielded.append(poss)
52
55
 
53
- args = parse_line(document.text)
56
+ line = document.text
57
+ current_action_line = line.split('+')[-1].lstrip()
58
+ args = parse_line(current_action_line)
54
59
  action_function = get_action(args['action'], _actions=shell_attrs.get('_actions', None))
55
60
  if action_function is None:
56
61
  return
@@ -74,8 +79,8 @@ class ShellCompleter(Completer):
74
79
  shell,
75
80
  complete_function_name
76
81
  )(
77
- document.text.split(' ')[-1],
78
- document.text,
82
+ current_action_line.split(' ')[-1],
83
+ current_action_line,
79
84
  0,
80
85
  0
81
86
  )
@@ -8,12 +8,15 @@ Functions for bootstrapping elements
8
8
  """
9
9
 
10
10
  from __future__ import annotations
11
+
12
+ import meerschaum as mrsm
11
13
  from meerschaum.utils.typing import Union, Any, Sequence, SuccessTuple, Optional, Tuple, List
12
14
 
15
+
13
16
  def bootstrap(
14
- action: Optional[List[str]] = None,
15
- **kw: Any
16
- ) -> SuccessTuple:
17
+ action: Optional[List[str]] = None,
18
+ **kw: Any
19
+ ) -> SuccessTuple:
17
20
  """
18
21
  Launch an interactive wizard to bootstrap pipes or connectors.
19
22
 
@@ -26,23 +29,24 @@ def bootstrap(
26
29
  'pipes' : _bootstrap_pipes,
27
30
  'connectors' : _bootstrap_connectors,
28
31
  'plugins' : _bootstrap_plugins,
32
+ 'jobs' : _bootstrap_jobs,
29
33
  }
30
34
  return choose_subaction(action, options, **kw)
31
35
 
32
36
 
33
37
  def _bootstrap_pipes(
34
- action: Optional[List[str]] = None,
35
- connector_keys: Optional[List[str]] = None,
36
- metric_keys: Optional[List[str]] = None,
37
- location_keys: Optional[List[Optional[str]]] = None,
38
- yes: bool = False,
39
- force: bool = False,
40
- noask: bool = False,
41
- debug: bool = False,
42
- mrsm_instance: Optional[str] = None,
43
- shell: bool = False,
44
- **kw: Any
45
- ) -> SuccessTuple:
38
+ action: Optional[List[str]] = None,
39
+ connector_keys: Optional[List[str]] = None,
40
+ metric_keys: Optional[List[str]] = None,
41
+ location_keys: Optional[List[Optional[str]]] = None,
42
+ yes: bool = False,
43
+ force: bool = False,
44
+ noask: bool = False,
45
+ debug: bool = False,
46
+ mrsm_instance: Optional[str] = None,
47
+ shell: bool = False,
48
+ **kw: Any
49
+ ) -> SuccessTuple:
46
50
  """
47
51
  Create a new pipe.
48
52
  If no keys are provided, guide the user through the steps required.
@@ -433,6 +437,107 @@ def _bootstrap_plugins(
433
437
  return True, "Success"
434
438
 
435
439
 
440
+ def _bootstrap_jobs(
441
+ action: Optional[List[str]] = None,
442
+ executor_keys: Optional[str] = None,
443
+ debug: bool = False,
444
+ **kwargs: Any
445
+ ) -> SuccessTuple:
446
+ """
447
+ Launch an interactive wizard to create new jobs.
448
+ """
449
+ import shlex
450
+ from meerschaum.utils.prompt import prompt, yes_no
451
+ from meerschaum.actions import actions
452
+ from meerschaum.utils.formatting import print_options, make_header
453
+ from meerschaum.utils.formatting._shell import clear_screen
454
+ from meerschaum.utils.warnings import info
455
+ from meerschaum._internal.arguments import (
456
+ split_pipeline_sysargs,
457
+ split_chained_sysargs,
458
+ )
459
+ from meerschaum.utils.misc import items_str
460
+ from meerschaum._internal.shell.ShellCompleter import ShellCompleter
461
+
462
+ if not action:
463
+ action = [prompt("What is the name of the job you'd like to create?")]
464
+
465
+ new_jobs = {}
466
+ for name in action:
467
+ clear_screen(debug=debug)
468
+ job = mrsm.Job(name, executor_keys=executor_keys)
469
+ if job.exists():
470
+ edit_success, edit_msg = actions['edit'](['job', name], **kwargs)
471
+ if not edit_success:
472
+ return edit_success, edit_msg
473
+ continue
474
+
475
+ info(
476
+ "Press [Esc + Enter] to submit, [CTRL + C] to exit.\n"
477
+ " Tip: join multiple actions with `+`, add pipeline arguments with `:`.\n"
478
+ " https://meerschaum.io/reference/actions/#chaining-actions\n"
479
+ )
480
+ try:
481
+ new_sysargs_str = prompt(
482
+ f"Arguments for job '{name}':",
483
+ multiline=True,
484
+ icon=False,
485
+ completer=ShellCompleter(),
486
+ )
487
+ except KeyboardInterrupt:
488
+ return True, "Nothing was changed."
489
+
490
+ new_sysargs = shlex.split(new_sysargs_str)
491
+ new_sysargs, pipeline_args = split_pipeline_sysargs(new_sysargs)
492
+ chained_sysargs = split_chained_sysargs(new_sysargs)
493
+
494
+ if len(chained_sysargs) > 1:
495
+ print_options(
496
+ [
497
+ shlex.join(step_sysargs)
498
+ for step_sysargs in chained_sysargs
499
+ ],
500
+ header=f"Steps in Job '{name}':",
501
+ number_options=True,
502
+ **kwargs
503
+ )
504
+ else:
505
+ print('\n' + make_header(f"Action for Job '{name}':"))
506
+ print(shlex.join(new_sysargs))
507
+
508
+ if pipeline_args:
509
+ print('\n' + make_header("Pipeline Arguments:"))
510
+ print(shlex.join(pipeline_args))
511
+
512
+ if not yes_no(
513
+ (
514
+ f"Are you sure you want to create job '{name}' with the above arguments?\n"
515
+ + " The job will be started if you continue."
516
+ ),
517
+ default='n',
518
+ **kwargs
519
+ ):
520
+ return True, "Nothing was changed."
521
+
522
+ new_job = mrsm.Job(name, new_sysargs_str, executor_keys=executor_keys)
523
+ start_success, start_msg = new_job.start()
524
+ if not start_success:
525
+ return start_success, start_msg
526
+
527
+ new_jobs[name] = new_job
528
+
529
+ if not new_jobs:
530
+ return False, "No new jobs were created."
531
+
532
+ msg = (
533
+ "Successfully bootstrapped job"
534
+ + ('s' if len(new_jobs) != 1 else '')
535
+ + items_str(list(new_jobs.keys()))
536
+ + '.'
537
+ )
538
+ return True, msg
539
+
540
+
436
541
  ### NOTE: This must be the final statement of the module.
437
542
  ### Any subactions added below these lines will not
438
543
  ### be added to the `help` docstring.
@@ -6,12 +6,16 @@ Functions for clearing pipes.
6
6
  """
7
7
 
8
8
  from __future__ import annotations
9
+
10
+ from datetime import datetime
11
+ import meerschaum as mrsm
9
12
  from meerschaum.utils.typing import List, SuccessTuple, Any, Optional
10
13
 
14
+
11
15
  def clear(
12
- action: Optional[List[str]] = None,
13
- **kw: Any
14
- ) -> SuccessTuple:
16
+ action: Optional[List[str]] = None,
17
+ **kw: Any
18
+ ) -> SuccessTuple:
15
19
  """
16
20
  Clear pipes of their data, or clear the screen.
17
21
 
@@ -34,24 +38,25 @@ def clear(
34
38
 
35
39
 
36
40
  def _clear_pipes(
37
- action: Optional[List[str]] = None,
38
- begin: Optional[datetime.datetime] = None,
39
- end: Optional[datetime.datetime] = None,
40
- connector_keys: Optional[List[str]] = None,
41
- metric_keys: Optional[List[str]] = None,
42
- mrsm_instance: Optional[str] = None,
43
- location_keys: Optional[List[str]] = None,
44
- force: bool = False,
45
- debug: bool = False,
46
- **kw: Any
47
- ) -> SuccessTuple:
41
+ action: Optional[List[str]] = None,
42
+ begin: Optional[datetime] = None,
43
+ end: Optional[datetime] = None,
44
+ connector_keys: Optional[List[str]] = None,
45
+ metric_keys: Optional[List[str]] = None,
46
+ mrsm_instance: Optional[str] = None,
47
+ location_keys: Optional[List[str]] = None,
48
+ yes: bool = False,
49
+ force: bool = False,
50
+ debug: bool = False,
51
+ **kw: Any
52
+ ) -> SuccessTuple:
48
53
  """
49
54
  Clear pipes' data without dropping any tables.
50
55
 
51
56
  """
52
57
  from meerschaum import get_pipes
53
58
  from meerschaum.utils.formatting import print_tuple
54
-
59
+
55
60
  successes = {}
56
61
  fails = {}
57
62
 
@@ -61,13 +66,19 @@ def _clear_pipes(
61
66
  )
62
67
 
63
68
  if not force:
64
- if not _ask_with_rowcounts(pipes, begin=begin, end=end, debug=debug, **kw):
69
+ if not _ask_with_rowcounts(pipes, begin=begin, end=end, debug=debug, yes=yes, **kw):
65
70
  return False, "No rows were deleted."
66
71
 
67
72
  for pipe in pipes:
68
- success, msg = pipe.clear(begin=begin, end=end, debug=debug, **kw)
69
- print_tuple((success, msg))
70
- (successes if success else fails)[pipe] = msg
73
+ clear_success, clear_msg = pipe.clear(
74
+ begin=begin,
75
+ end=end,
76
+ yes=yes,
77
+ debug=debug,
78
+ **kw
79
+ )
80
+ print_tuple((clear_success, clear_msg))
81
+ (successes if clear_success else fails)[pipe] = clear_msg
71
82
 
72
83
  success = len(successes) > 0
73
84
  msg = (
@@ -79,15 +90,15 @@ def _clear_pipes(
79
90
 
80
91
 
81
92
  def _ask_with_rowcounts(
82
- pipes: List[meerschaum.Pipe],
83
- begin: Optional[datetime.datetime] = None,
84
- end: Optional[datetime.datetime] = None,
85
- yes: bool = False,
86
- nopretty: bool = False,
87
- noask: bool = False,
88
- debug: bool = False,
89
- **kw
90
- ) -> bool:
93
+ pipes: List[mrsm.Pipe],
94
+ begin: Optional[datetime] = None,
95
+ end: Optional[datetime] = None,
96
+ yes: bool = False,
97
+ nopretty: bool = False,
98
+ noask: bool = False,
99
+ debug: bool = False,
100
+ **kw
101
+ ) -> bool:
91
102
  """
92
103
  Count all of the pipes' rowcounts and confirm with the user that these rows need to be deleted.
93
104
 
@@ -109,13 +120,13 @@ def _ask_with_rowcounts(
109
120
  warn(
110
121
  f"No datetime could be determined for {pipe}!\n"
111
122
  + " THIS WILL DELETE THE ENTIRE TABLE!",
112
- stack = False
123
+ stack=False
113
124
  )
114
125
  else:
115
126
  warn(
116
127
  f"A datetime wasn't specified for {pipe}.\n"
117
128
  + f" Using column \"{_dt}\" for datetime bounds...",
118
- stack = False
129
+ stack=False
119
130
  )
120
131
 
121
132
 
@@ -7,9 +7,11 @@ Functions for editing elements belong here.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
+
10
11
  import meerschaum as mrsm
11
12
  from meerschaum.utils.typing import List, Any, SuccessTuple, Optional, Dict
12
13
 
14
+
13
15
  def edit(
14
16
  action: Optional[List[str]] = None,
15
17
  **kw: Any
@@ -24,6 +26,7 @@ def edit(
24
26
  'definition': _edit_definition,
25
27
  'users' : _edit_users,
26
28
  'plugins' : _edit_plugins,
29
+ 'jobs' : _edit_jobs,
27
30
  }
28
31
  return choose_subaction(action, options, **kw)
29
32
 
@@ -372,6 +375,92 @@ def _complete_edit_plugins(
372
375
  return possibilities
373
376
 
374
377
 
378
+ def _edit_jobs(
379
+ action: Optional[List[str]] = None,
380
+ executor_keys: Optional[str] = None,
381
+ debug: bool = False,
382
+ **kwargs: Any
383
+ ) -> mrsm.SuccessTuple:
384
+ """
385
+ Edit existing jobs.
386
+ """
387
+ import shlex
388
+ from meerschaum.jobs import get_filtered_jobs
389
+ from meerschaum.utils.prompt import prompt, yes_no
390
+ from meerschaum._internal.arguments import (
391
+ split_pipeline_sysargs,
392
+ split_chained_sysargs,
393
+ )
394
+ from meerschaum.utils.formatting import make_header, print_options
395
+ from meerschaum.utils.warnings import info
396
+ from meerschaum.actions import actions
397
+ jobs = get_filtered_jobs(executor_keys, action, debug=debug)
398
+ if not jobs:
399
+ return False, "No jobs to edit."
400
+
401
+ info(
402
+ "Press [Esc + Enter] to submit, [CTRL + C] to exit.\n"
403
+ " Tip: join multiple actions with `+`, add pipeline arguments with `:`.\n"
404
+ " https://meerschaum.io/reference/actions/#chaining-actions\n"
405
+ )
406
+
407
+ for name, job in jobs.items():
408
+ sysargs_str = shlex.join(job.sysargs)
409
+
410
+ try:
411
+ new_sysargs_str = prompt(
412
+ f"Arguments for job '{name}':",
413
+ default_editable=sysargs_str.lstrip().rstrip(),
414
+ multiline=True,
415
+ icon=False,
416
+ )
417
+ except KeyboardInterrupt:
418
+ return True, "Nothing was changed."
419
+
420
+ new_sysargs = shlex.split(new_sysargs_str)
421
+ new_sysargs, pipeline_args = split_pipeline_sysargs(new_sysargs)
422
+ chained_sysargs = split_chained_sysargs(new_sysargs)
423
+
424
+ if len(chained_sysargs) > 1:
425
+ print_options(
426
+ [
427
+ shlex.join(step_sysargs)
428
+ for step_sysargs in chained_sysargs
429
+ ],
430
+ header=f"Steps in Job '{name}':",
431
+ number_options=True,
432
+ **kwargs
433
+ )
434
+ else:
435
+ print('\n' + make_header(f"Action for Job '{name}':"))
436
+ print(shlex.join(new_sysargs))
437
+
438
+ if pipeline_args:
439
+ print('\n' + make_header("Pipeline Arguments:"))
440
+ print(shlex.join(pipeline_args))
441
+
442
+ if not yes_no(
443
+ (
444
+ f"Are you sure you want to recreate job '{name}' with the above arguments?\n"
445
+ + " The job will be started if you continue."
446
+ ),
447
+ default='n',
448
+ **kwargs
449
+ ):
450
+ return True, "Nothing was changed."
451
+
452
+ delete_success, delete_msg = job.delete()
453
+ if not delete_success:
454
+ return delete_success, delete_msg
455
+
456
+ new_job = mrsm.Job(name, new_sysargs_str, executor_keys=executor_keys)
457
+ start_success, start_msg = new_job.start()
458
+ if not start_success:
459
+ return start_success, start_msg
460
+
461
+ return True, "Success"
462
+
463
+
375
464
  ### NOTE: This must be the final statement of the module.
376
465
  ### Any subactions added below these lines will not
377
466
  ### be added to the `help` docstring.
@@ -9,6 +9,7 @@ Start subsystems (API server, logging daemon, etc.).
9
9
  from __future__ import annotations
10
10
  from meerschaum.utils.typing import SuccessTuple, Optional, List, Any, Union, Dict
11
11
 
12
+
12
13
  def start(
13
14
  action: Optional[List[str]] = None,
14
15
  **kw: Any,
@@ -375,8 +376,8 @@ def _start_gui(
375
376
  webview.create_window(
376
377
  'Meerschaum Shell',
377
378
  f'http://127.0.0.1:{port}',
378
- height = 650,
379
- width = 1000
379
+ height=650,
380
+ width=1000
380
381
  )
381
382
  webview.start(debug=debug)
382
383
  except Exception as e:
@@ -284,8 +284,9 @@ def _sync_pipes(
284
284
  from meerschaum.utils.formatting import print_pipes_results
285
285
  from meerschaum.config.static import STATIC_CONFIG
286
286
 
287
+ ### NOTE: Removed MRSM_NONINTERACTIVE check.
287
288
  noninteractive_val = os.environ.get(STATIC_CONFIG['environment']['noninteractive'], None)
288
- is_noninterative = noninteractive_val in ('1', 'true', 'True', 'yes')
289
+ _ = noninteractive_val in ('1', 'true', 'True', 'yes')
289
290
 
290
291
  run = True
291
292
  msg = ""
@@ -293,7 +294,7 @@ def _sync_pipes(
293
294
  cooldown = 2 * (min_seconds + 1)
294
295
  success_pipes, failure_pipes = [], []
295
296
  while run:
296
- _progress = progress() if shell and not is_noninterative else None
297
+ _progress = progress() if shell else None
297
298
  cm = _progress if _progress is not None else contextlib.nullcontext()
298
299
 
299
300
  lap_begin = time.perf_counter()
@@ -98,6 +98,7 @@ _paths = {
98
98
  'plugins' : pages.plugins.layout,
99
99
  'register': pages.register.layout,
100
100
  'pipes' : pages.pipes.layout,
101
+ 'job' : pages.job.layout,
101
102
  }
102
103
  _required_login = {''}
103
104
 
@@ -121,7 +122,7 @@ def update_page_layout_div(
121
122
  ----------
122
123
  pathname: str
123
124
  The path in the browser.
124
-
125
+
125
126
  session_store_data: Dict[str, Any]:
126
127
  The stored session data.
127
128