meerschaum 2.3.0rc1__py3-none-any.whl → 2.3.0rc2__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.
@@ -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,
11
+ parse_dict_to_sysargs, split_chained_sysargs,
12
12
  )
13
13
  from meerschaum._internal.arguments._parser import parser
14
14
  from meerschaum.plugins import add_plugin_argument
@@ -19,6 +19,44 @@ _locks = {
19
19
  _loaded_plugins_args: bool = False
20
20
 
21
21
 
22
+ def split_chained_sysargs(sysargs: List[str]) -> List[List[str]]:
23
+ """
24
+ Split a `sysargs` list containing "and" keys (`&&`)
25
+ into a list of individual `sysargs`.
26
+ """
27
+ from meerschaum.config.static import STATIC_CONFIG
28
+ and_key = STATIC_CONFIG['system']['arguments']['and_key']
29
+
30
+ if not sysargs or and_key not in sysargs:
31
+ return [sysargs]
32
+
33
+ ### Coalesce and consecutive joiners into one.
34
+ coalesce_args = []
35
+ previous_arg = None
36
+ for arg in [_arg for _arg in sysargs]:
37
+ if arg == and_key and previous_arg == and_key:
38
+ continue
39
+ coalesce_args.append(arg)
40
+ previous_arg = arg
41
+
42
+ ### Remove any joiners from the ends.
43
+ if coalesce_args[0] == and_key:
44
+ coalesce_args = coalesce_args[1:]
45
+ if coalesce_args[-1] == and_key:
46
+ coalesce_args = coalesce_args[:-1]
47
+
48
+ chained_sysargs = []
49
+ current_sysargs = []
50
+ for arg in coalesce_args:
51
+ if arg != and_key:
52
+ current_sysargs.append(arg)
53
+ else:
54
+ chained_sysargs.append(current_sysargs)
55
+ current_sysargs = []
56
+ chained_sysargs.append(current_sysargs)
57
+ return chained_sysargs
58
+
59
+
22
60
  def parse_arguments(sysargs: List[str]) -> Dict[str, Any]:
23
61
  """
24
62
  Parse a list of arguments into standard Meerschaum arguments.
@@ -206,9 +244,24 @@ def parse_dict_to_sysargs(
206
244
  args_dict: Dict[str, Any]
207
245
  ) -> List[str]:
208
246
  """Revert an arguments dictionary back to a command line list."""
247
+ import shlex
209
248
  from meerschaum._internal.arguments._parser import get_arguments_triggers
210
- sysargs = []
211
- sysargs += args_dict.get('action', [])
249
+ from meerschaum.config.static import STATIC_CONFIG
250
+ from meerschaum.utils.warnings import warn
251
+
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
+ 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
+ sysargs: List[str] = []
264
+ sysargs.extend(action or [])
212
265
  allow_none_args = {'location_keys'}
213
266
 
214
267
  triggers = get_arguments_triggers()
@@ -216,6 +269,7 @@ def parse_dict_to_sysargs(
216
269
  for a, t in triggers.items():
217
270
  if a == 'action' or a not in args_dict:
218
271
  continue
272
+
219
273
  ### Add boolean flags
220
274
  if isinstance(args_dict[a], bool):
221
275
  if args_dict[a] is True:
@@ -40,31 +40,68 @@ def entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
40
40
  -------
41
41
  A `SuccessTuple` indicating success.
42
42
  """
43
- from meerschaum._internal.arguments import parse_arguments
43
+ import shlex
44
+ from meerschaum.utils.formatting import make_header
45
+ from meerschaum._internal.arguments import parse_arguments, split_chained_sysargs
44
46
  from meerschaum.config.static import STATIC_CONFIG
45
47
  if sysargs is None:
46
48
  sysargs = []
47
49
  if not isinstance(sysargs, list):
48
- import shlex
49
50
  sysargs = shlex.split(sysargs)
50
- args = parse_arguments(sysargs)
51
- argparse_exception = args.get(
52
- STATIC_CONFIG['system']['arguments']['failure_key'],
53
- None,
51
+
52
+ has_daemon = '-d' in sysargs or '--daemon' in sysargs
53
+ has_start_job = sysargs[:2] == ['start', 'job']
54
+ chained_sysargs = (
55
+ [sysargs]
56
+ if has_daemon or has_start_job
57
+ else split_chained_sysargs(sysargs)
54
58
  )
55
- if argparse_exception is not None:
56
- args_text = args.get('text', '')
57
- if not args_text.startswith('show arguments'):
58
- return (
59
- False,
59
+ results: List[SuccessTuple] = []
60
+
61
+ for _sysargs in chained_sysargs:
62
+ args = parse_arguments(_sysargs)
63
+ argparse_exception = args.get(
64
+ STATIC_CONFIG['system']['arguments']['failure_key'],
65
+ None,
66
+ )
67
+ if argparse_exception is not None:
68
+ args_text = args.get('text', '')
69
+ if not args_text.startswith('show arguments'):
70
+ return (
71
+ False,
72
+ (
73
+ "Invalid arguments:"
74
+ + (f"\n{args_text}" if args_text else '')
75
+ + f"\n {argparse_exception}"
76
+ )
77
+ )
78
+
79
+ entry_success, entry_msg = entry_with_args(**args)
80
+ if not entry_success:
81
+ return entry_success, entry_msg
82
+
83
+ results.append((entry_success, entry_msg))
84
+
85
+ success = all(_success for _success, _ in results)
86
+ msg = (
87
+ results[0][1]
88
+ if len(results) == 1
89
+ else 'Successfully completed steps:\n\n' + '\n'.join(
90
+ [
60
91
  (
61
- "Invalid arguments:"
62
- + (f"\n{args_text}" if args_text else '')
63
- + f"\n {argparse_exception}"
92
+ make_header(shlex.join(_sysargs))
93
+ + '\n ' + _msg + '\n'
64
94
  )
65
- )
95
+ for i, ((_, _msg), _sysargs) in enumerate(zip(results, chained_sysargs))
96
+ ]
97
+ )
98
+ )
99
+ if _systemd_result_path:
100
+ import json
101
+ with open(_systemd_result_path, 'w+', encoding='utf-8') as f:
102
+ json.dump((success, msg), f)
66
103
 
67
- return entry_with_args(**args)
104
+ return success, msg
68
105
 
69
106
 
70
107
  def entry_with_args(
@@ -79,7 +116,16 @@ def entry_with_args(
79
116
  import inspect
80
117
  from meerschaum.actions import get_action, get_main_action_name
81
118
  from meerschaum._internal.arguments import remove_leading_action
82
- from meerschaum.utils.venv import Venv, active_venvs, deactivate_venv
119
+ from meerschaum.utils.venv import active_venvs, deactivate_venv
120
+ from meerschaum.config.static import STATIC_CONFIG
121
+
122
+ and_key = STATIC_CONFIG['system']['arguments']['and_key']
123
+ escaped_and_key = STATIC_CONFIG['system']['arguments']['escaped_and_key']
124
+ if and_key in (sysargs := kw.get('sysargs', [])):
125
+ if '-d' in sysargs or '--daemon' in sysargs:
126
+ sysargs = [(arg if arg != and_key else escaped_and_key) for arg in sysargs]
127
+ return entry(sysargs)
128
+
83
129
  if kw.get('trace', None):
84
130
  from meerschaum.utils.misc import debug_trace
85
131
  debug_trace()
@@ -159,11 +205,6 @@ def entry_with_args(
159
205
  for venv in [venv for venv in active_venvs]:
160
206
  deactivate_venv(venv, debug=kw.get('debug', False), force=True)
161
207
 
162
- if _systemd_result_path:
163
- import json
164
- with open(_systemd_result_path, 'w+', encoding='utf-8') as f:
165
- json.dump(result, f)
166
-
167
208
  return result
168
209
 
169
210
 
@@ -8,6 +8,8 @@ This module is the entry point for the interactive shell.
8
8
  from __future__ import annotations
9
9
  import os
10
10
  from copy import deepcopy
11
+ from itertools import chain
12
+
11
13
  from meerschaum.utils.typing import Union, SuccessTuple, Any, Callable, Optional, List, Dict
12
14
  from meerschaum.utils.packages import attempt_import
13
15
  from meerschaum.config import __doc__, __version__ as version, get_config
@@ -30,6 +32,12 @@ from meerschaum._internal.shell.ShellCompleter import ShellCompleter
30
32
  _clear_screen = get_config('shell', 'clear_screen', patch=True)
31
33
  from meerschaum.utils.misc import string_width, remove_ansi
32
34
  from meerschaum.jobs import get_executor_keys_from_context
35
+ from meerschaum.config.static import STATIC_CONFIG
36
+ from meerschaum._internal.arguments._parse_arguments import (
37
+ split_chained_sysargs,
38
+ parse_arguments,
39
+ parse_line,
40
+ )
33
41
 
34
42
  patch = True
35
43
  ### remove default cmd2 commands
@@ -63,6 +71,8 @@ reserved_completers = {
63
71
  ### To handle dynamic reloading, store shell attributes externally.
64
72
  ### This is because the shell object address gets lost upon reloads.
65
73
  shell_attrs = {}
74
+ AND_KEY: str = STATIC_CONFIG['system']['arguments']['and_key']
75
+ ESCAPED_AND_KEY: str = STATIC_CONFIG['system']['arguments']['escaped_and_key']
66
76
 
67
77
  def _insert_shell_actions(
68
78
  _shell: Optional['Shell'] = None,
@@ -111,7 +121,6 @@ def _completer_wrapper(
111
121
  if _check_keys is not None:
112
122
  return _check_keys
113
123
 
114
- from meerschaum._internal.arguments._parse_arguments import parse_line
115
124
  args = parse_line(line)
116
125
  if target.__name__ != 'default_action_completer':
117
126
  if len(args['action']) > 0:
@@ -149,7 +158,6 @@ def default_action_completer(
149
158
 
150
159
  def _check_complete_keys(line: str) -> Optional[List[str]]:
151
160
  from meerschaum._internal.arguments._parser import parser, get_arguments_triggers
152
- from meerschaum._internal.arguments._parse_arguments import parse_line
153
161
 
154
162
  ### TODO Add all triggers
155
163
  trigger_args = {
@@ -546,16 +554,68 @@ class Shell(cmd.Cmd):
546
554
  else:
547
555
  main_action_name = args['action'][0]
548
556
 
557
+ def _add_flag_to_sysargs(
558
+ chained_sysargs, key, value, flag, shell_key=None,
559
+ ):
560
+ shell_key = shell_key or key
561
+ shell_value = remove_ansi(shell_attrs.get(shell_key) or '')
562
+ if key == 'mrsm_instance':
563
+ default_value = get_config('meerschaum', 'instance')
564
+ elif key == 'repository':
565
+ default_value = get_config('meerschaum', 'default_repository')
566
+ elif key == 'executor_keys':
567
+ default_value = get_executor_keys_from_context()
568
+ else:
569
+ default_value = None
570
+
571
+ if shell_value == default_value:
572
+ return
573
+
574
+ for sysargs in chained_sysargs:
575
+ kwargs = parse_arguments(sysargs)
576
+ if key in kwargs:
577
+ continue
578
+ sysargs.extend([flag, value])
579
+
580
+ args['sysargs'] = list(
581
+ chain.from_iterable(
582
+ sub_sysargs + [AND_KEY]
583
+ for sub_sysargs in chained_sysargs
584
+ )
585
+ )[:-1]
586
+
587
+
549
588
  ### if no instance is provided, use current shell default,
550
589
  ### but not for the 'api' command (to avoid recursion)
551
- if 'mrsm_instance' not in args and main_action_name != 'api':
552
- args['mrsm_instance'] = str(shell_attrs['instance_keys'])
590
+ if main_action_name != 'api':
591
+ chained_sysargs = split_chained_sysargs(args['sysargs'])
592
+ chained_filtered_sysargs = split_chained_sysargs(args['filtered_sysargs'])
593
+ mrsm_instance = shell_attrs['instance_keys']
594
+ args['mrsm_instance'] = mrsm_instance
595
+ _add_flag_to_sysargs(
596
+ chained_sysargs, 'mrsm_instance', mrsm_instance, '-i', 'instance_keys',
597
+ )
598
+ _add_flag_to_sysargs(
599
+ chained_filtered_sysargs, 'mrsm_instance', mrsm_instance, '-i', 'instance_keys',
600
+ )
553
601
 
554
- if 'repository' not in args and main_action_name != 'api':
555
- args['repository'] = str(shell_attrs['repo_keys'])
602
+ repo_keys = str(shell_attrs['repo_keys'])
603
+ args['repository'] = repo_keys
604
+ _add_flag_to_sysargs(
605
+ chained_sysargs, 'repository', repo_keys, '-r', 'repo_keys',
606
+ )
607
+ _add_flag_to_sysargs(
608
+ chained_filtered_sysargs, 'repository', repo_keys, '-r', 'repo_keys',
609
+ )
556
610
 
557
- if 'executor_keys' not in args:
558
- args['executor_keys'] = remove_ansi(str(shell_attrs['executor_keys']))
611
+ executor_keys = remove_ansi(str(shell_attrs['executor_keys']))
612
+ args['executor_keys'] = remove_ansi(executor_keys)
613
+ _add_flag_to_sysargs(
614
+ chained_sysargs, 'executor_keys', executor_keys, '-e',
615
+ )
616
+ _add_flag_to_sysargs(
617
+ chained_filtered_sysargs, 'executor_keys', executor_keys, '-e',
618
+ )
559
619
 
560
620
  ### parse out empty strings
561
621
  if args['action'][0].strip("\"'") == '':
@@ -630,12 +690,12 @@ class Shell(cmd.Cmd):
630
690
  info(f"Debug mode is {'on' if shell_attrs['debug'] else 'off'}.")
631
691
 
632
692
  def do_instance(
633
- self,
634
- action: Optional[List[str]] = None,
635
- executor_keys=None,
636
- debug: bool = False,
637
- **kw: Any
638
- ) -> SuccessTuple:
693
+ self,
694
+ action: Optional[List[str]] = None,
695
+ executor_keys=None,
696
+ debug: bool = False,
697
+ **kw: Any
698
+ ) -> SuccessTuple:
639
699
  """
640
700
  Temporarily set a default Meerschaum instance for the duration of the shell.
641
701
  The default instance is loaded from the Meerschaum configuraton file
@@ -804,6 +864,7 @@ class Shell(cmd.Cmd):
804
864
  from meerschaum import get_connector
805
865
  from meerschaum.connectors.parse import parse_executor_keys
806
866
  from meerschaum.utils.warnings import warn, info
867
+ from meerschaum.jobs import get_executor_keys_from_context
807
868
 
808
869
  if action is None:
809
870
  action = []
@@ -814,6 +875,10 @@ class Shell(cmd.Cmd):
814
875
  executor_keys = ''
815
876
  if executor_keys == '':
816
877
  executor_keys = get_executor_keys_from_context()
878
+
879
+ if executor_keys == 'systemd' and get_executor_keys_from_context() != 'systemd':
880
+ warn(f"Cannot execute via `systemd`, falling back to `local`...", stack=False)
881
+ executor_keys = 'local'
817
882
 
818
883
  conn = parse_executor_keys(executor_keys, debug=debug)
819
884
 
@@ -987,7 +1052,7 @@ def input_with_sigint(_input, session, shell: Optional[Shell] = None):
987
1052
  )
988
1053
 
989
1054
  try:
990
- typ, label = shell_attrs['instance_keys'].split(':')
1055
+ typ, label = shell_attrs['instance_keys'].split(':', maxsplit=1)
991
1056
  connected = typ in connectors and label in connectors[typ]
992
1057
  except Exception as e:
993
1058
  connected = False
@@ -509,12 +509,18 @@ def _complete_delete_jobs(
509
509
  get_stopped_jobs,
510
510
  get_paused_jobs,
511
511
  get_running_jobs,
512
+ get_executor_keys_from_context,
512
513
  )
513
514
  from meerschaum.utils.misc import remove_ansi
514
515
 
515
- executor_keys = executor_keys or remove_ansi(shell_attrs.get('executor_keys', 'local'))
516
+ executor_keys = (
517
+ executor_keys
518
+ or remove_ansi(
519
+ shell_attrs.get('executor_keys', get_executor_keys_from_context())
520
+ )
521
+ )
516
522
 
517
- jobs = get_jobs(executor_keys)
523
+ jobs = get_jobs(executor_keys, include_hidden=False)
518
524
  if _get_job_method:
519
525
  method_keys = [_get_job_method] if isinstance(_get_job_method, str) else _get_job_method
520
526
  method_jobs = {}
@@ -540,11 +546,11 @@ def _complete_delete_jobs(
540
546
 
541
547
 
542
548
  def _delete_venvs(
543
- action: Optional[List[str]] = None,
544
- yes: bool = False,
545
- force: bool = False,
546
- **kwargs: Any
547
- ) -> SuccessTuple:
549
+ action: Optional[List[str]] = None,
550
+ yes: bool = False,
551
+ force: bool = False,
552
+ **kwargs: Any
553
+ ) -> SuccessTuple:
548
554
  """
549
555
  Remove virtual environments.
550
556
  Specify which venvs to remove, or remove everything at once.
@@ -82,6 +82,7 @@ def _start_api(action: Optional[List[str]] = None, **kw):
82
82
  from meerschaum.actions import actions
83
83
  return actions['api'](action=['start'], **kw)
84
84
 
85
+
85
86
  def _start_jobs(
86
87
  action: Optional[List[str]] = None,
87
88
  name: Optional[str] = None,
@@ -119,25 +120,20 @@ def _start_jobs(
119
120
  Start the job 'happy_seal' but via the `--name` flag.
120
121
  This only applies when no text follows the words 'start job'.
121
122
  """
122
- import textwrap
123
123
  from meerschaum.utils.warnings import warn, info
124
124
  from meerschaum.utils.daemon._names import get_new_daemon_name
125
125
  from meerschaum.jobs import (
126
126
  Job,
127
- get_jobs,
128
127
  get_filtered_jobs,
129
128
  get_stopped_jobs,
130
129
  get_running_jobs,
131
130
  get_paused_jobs,
132
- get_restart_jobs,
133
131
  _install_healthcheck_job,
134
132
  )
135
- from meerschaum._internal.arguments._parse_arguments import parse_arguments
136
133
  from meerschaum.actions import actions
137
134
  from meerschaum.utils.prompt import yes_no
138
135
  from meerschaum.utils.formatting import print_tuple
139
- from meerschaum.utils.formatting._jobs import pprint_job, pprint_jobs
140
- from meerschaum.utils.formatting._shell import clear_screen
136
+ from meerschaum.utils.formatting._jobs import pprint_jobs
141
137
  from meerschaum.utils.misc import items_str
142
138
 
143
139
  names = []
@@ -2,4 +2,4 @@
2
2
  Specify the Meerschaum release version.
3
3
  """
4
4
 
5
- __version__ = "2.3.0rc1"
5
+ __version__ = "2.3.0rc2"
@@ -88,6 +88,8 @@ STATIC_CONFIG: Dict[str, Any] = {
88
88
  ),
89
89
  'underscore_standin': '<UNDERSCORE>', ### Temporary replacement for parsing.
90
90
  'failure_key': '_argparse_exception',
91
+ 'and_key': '+',
92
+ 'escaped_and_key': '++',
91
93
  },
92
94
  'urls': {
93
95
  'get-pip.py': 'https://bootstrap.pypa.io/get-pip.py',
@@ -120,7 +120,6 @@ def parse_repo_keys(keys: Optional[str] = None, **kw):
120
120
  def parse_executor_keys(keys: Optional[str] = None, **kw):
121
121
  """Parse the executor keys into an APIConnector or string."""
122
122
  from meerschaum.jobs import get_executor_keys_from_context
123
- from meerschaum.config import get_config
124
123
  if keys is None:
125
124
  keys = get_executor_keys_from_context()
126
125
 
meerschaum/jobs/_Job.py CHANGED
@@ -91,6 +91,14 @@ class Job:
91
91
  if isinstance(sysargs, str):
92
92
  sysargs = shlex.split(sysargs)
93
93
 
94
+ and_key = STATIC_CONFIG['system']['arguments']['and_key']
95
+ escaped_and_key = STATIC_CONFIG['system']['arguments']['escaped_and_key']
96
+ if sysargs:
97
+ sysargs = [
98
+ (arg if arg != escaped_and_key else and_key)
99
+ for arg in sysargs
100
+ ]
101
+
94
102
  ### NOTE: 'local' and 'systemd' executors are being coalesced.
95
103
  if executor_keys is None:
96
104
  from meerschaum.jobs import get_executor_keys_from_context
@@ -831,7 +839,7 @@ class Job:
831
839
  """
832
840
  Return the job's Daemon label (joined sysargs).
833
841
  """
834
- return shlex.join(self.sysargs)
842
+ return shlex.join(self.sysargs).replace(' + ', '\n+ ')
835
843
 
836
844
  def __str__(self) -> str:
837
845
  sysargs = self.sysargs
@@ -21,7 +21,7 @@ from meerschaum.jobs import Job, Executor, make_executor
21
21
  from meerschaum.utils.typing import Dict, Any, List, SuccessTuple, Union, Optional, Callable
22
22
  from meerschaum.config.static import STATIC_CONFIG
23
23
  from meerschaum.utils.warnings import warn, dprint
24
- from meerschaum._internal.arguments._parse_arguments import parse_arguments, parse_dict_to_sysargs
24
+ from meerschaum._internal.arguments._parse_arguments import parse_arguments
25
25
 
26
26
  JOB_METADATA_CACHE_SECONDS: int = STATIC_CONFIG['api']['jobs']['metadata_cache_seconds']
27
27
 
@@ -36,11 +36,11 @@ class SystemdExecutor(Executor):
36
36
  """
37
37
  Return a list of existing jobs, including hidden ones.
38
38
  """
39
- from meerschaum.config.paths import SYSTEMD_USER_RESOURCES_PATH
39
+ from meerschaum.config.paths import SYSTEMD_ROOT_RESOURCES_PATH
40
40
  return [
41
41
  service_name[len('mrsm-'):(-1 * len('.service'))]
42
- for service_name in os.listdir(SYSTEMD_USER_RESOURCES_PATH)
43
- if service_name.startswith('mrsm-')
42
+ for service_name in os.listdir(SYSTEMD_ROOT_RESOURCES_PATH)
43
+ if service_name.startswith('mrsm-') and service_name.endswith('.service')
44
44
  ]
45
45
 
46
46
  def get_job_exists(self, name: str, debug: bool = False) -> bool:
@@ -51,10 +51,10 @@ class SystemdExecutor(Executor):
51
51
  if debug:
52
52
  dprint(f'Existing services: {user_services}')
53
53
  return name in user_services
54
-
54
+
55
55
  def get_jobs(self, debug: bool = False) -> Dict[str, Job]:
56
56
  """
57
- Return a dictionary of `systemd` Jobs (excluding hidden jobs).
57
+ Return a dictionary of `systemd` Jobs (including hidden jobs).
58
58
  """
59
59
  user_services = self.get_job_names(debug=debug)
60
60
  jobs = {
@@ -64,7 +64,6 @@ class SystemdExecutor(Executor):
64
64
  return {
65
65
  name: job
66
66
  for name, job in jobs.items()
67
- if not job.hidden
68
67
  }
69
68
 
70
69
  def get_service_name(self, name: str, debug: bool = False) -> str:
@@ -73,13 +72,20 @@ class SystemdExecutor(Executor):
73
72
  """
74
73
  return f"mrsm-{name.replace(' ', '-')}.service"
75
74
 
76
- def get_service_file_path(self, name: str, debug: bool = False) -> pathlib.Path:
75
+ def get_service_symlink_file_path(self, name: str, debug: bool = False) -> pathlib.Path:
77
76
  """
78
- Return the path to a Job's service file.
77
+ Return the path to where to create the service symlink.
79
78
  """
80
79
  from meerschaum.config.paths import SYSTEMD_USER_RESOURCES_PATH
81
80
  return SYSTEMD_USER_RESOURCES_PATH / self.get_service_name(name, debug=debug)
82
81
 
82
+ def get_service_file_path(self, name: str, debug: bool = False) -> pathlib.Path:
83
+ """
84
+ Return the path to a Job's service file.
85
+ """
86
+ from meerschaum.config.paths import SYSTEMD_ROOT_RESOURCES_PATH
87
+ return SYSTEMD_ROOT_RESOURCES_PATH / self.get_service_name(name, debug=debug)
88
+
83
89
  def get_service_logs_path(self, name: str, debug: bool = False) -> pathlib.Path:
84
90
  """
85
91
  Return the path to direct service logs to.
@@ -150,8 +156,7 @@ class SystemdExecutor(Executor):
150
156
  "\n"
151
157
  "[Service]\n"
152
158
  f"ExecStart={exec_str}\n"
153
- "KillSignal=SIGINT\n"
154
- "TimeoutStopSpec=8\n"
159
+ "KillSignal=SIGTERM\n"
155
160
  "Restart=always\n"
156
161
  "RestartPreventExitStatus=0\n"
157
162
  f"SyslogIdentifier={service_name}\n"
@@ -180,23 +185,11 @@ class SystemdExecutor(Executor):
180
185
  )
181
186
  return socket_text
182
187
 
183
- @staticmethod
184
- def clean_sysargs(sysargs: List[str]) -> List[str]:
185
- """
186
- Return a sysargs list with the executor key set to 'local'.
187
- """
188
- kwargs = parse_arguments(sysargs)
189
- _ = kwargs.pop('executor_keys', None)
190
- _ = kwargs.pop('systemd', None)
191
- return parse_dict_to_sysargs(kwargs)
192
-
193
188
  def get_hidden_job(self, name: str, sysargs: Optional[List[str]] = None, debug: bool = False):
194
189
  """
195
190
  Return the hidden "sister" job to store a job's parameters.
196
191
  """
197
192
  hidden_name = f'.systemd-{self.get_service_name(name, debug=debug)}'
198
- if sysargs:
199
- sysargs = self.clean_sysargs(sysargs)
200
193
 
201
194
  return Job(
202
195
  hidden_name,
@@ -309,6 +302,9 @@ class SystemdExecutor(Executor):
309
302
  return None
310
303
 
311
304
  pid_str = output[len('MainPID='):]
305
+ if pid_str == '0':
306
+ return None
307
+
312
308
  if is_int(pid_str):
313
309
  return int(pid_str)
314
310
 
@@ -438,19 +434,19 @@ class SystemdExecutor(Executor):
438
434
  """
439
435
  Create a job as a service to be run by `systemd`.
440
436
  """
441
-
437
+ from meerschaum.utils.misc import make_symlink
442
438
  service_name = self.get_service_name(name, debug=debug)
443
439
  service_file_path = self.get_service_file_path(name, debug=debug)
444
- service_socket_path = self.get_service_socket_path(name, debug=debug)
445
- socket_path = self.get_socket_path(name, debug=debug)
440
+ service_symlink_file_path = self.get_service_symlink_file_path(name, debug=debug)
446
441
  socket_stdin = self.get_job_stdin_file(name, debug=debug)
447
442
  _ = socket_stdin.file_handler
448
443
 
449
- job = self.get_hidden_job(name, sysargs, debug=debug)
450
-
451
- clean_sysargs = self.clean_sysargs(sysargs)
452
444
  with open(service_file_path, 'w+', encoding='utf-8') as f:
453
- f.write(self.get_service_file_text(name, clean_sysargs, debug=debug))
445
+ f.write(self.get_service_file_text(name, sysargs, debug=debug))
446
+
447
+ symlink_success, symlink_msg = make_symlink(service_file_path, service_symlink_file_path)
448
+ if not symlink_success:
449
+ return symlink_success, symlink_msg
454
450
 
455
451
  commands = [
456
452
  ['daemon-reload'],
@@ -494,6 +490,18 @@ class SystemdExecutor(Executor):
494
490
  """
495
491
  job = self.get_hidden_job(name, debug=debug)
496
492
  job.daemon._write_stop_file('quit')
493
+ sigint_success, sigint_msg = self.run_command(
494
+ ['kill', '-s', 'SIGINT', self.get_service_name(name, debug=debug)],
495
+ debug=debug,
496
+ )
497
+
498
+ loop_start = time.perf_counter()
499
+ while (time.perf_counter() - loop_start) < 5:
500
+ if self.get_job_status(name, debug=debug) == 'stopped':
501
+ return True, 'Success'
502
+
503
+ time.sleep(0.1)
504
+
497
505
  return self.run_command(
498
506
  ['stop', self.get_service_name(name, debug=debug)],
499
507
  debug=debug,
@@ -516,28 +524,25 @@ class SystemdExecutor(Executor):
516
524
  """
517
525
  from meerschaum.config.paths import SYSTEMD_LOGS_RESOURCES_PATH
518
526
 
519
- stop_success, stop_msg = self.stop_job(name, debug=debug)
520
- if not stop_success:
521
- return stop_success, stop_msg
522
-
523
- disable_success, disable_msg = self.run_command(
527
+ _ = self.stop_job(name, debug=debug)
528
+ _ = self.run_command(
524
529
  ['disable', self.get_service_name(name, debug=debug)],
525
530
  debug=debug,
526
531
  )
527
- if not disable_success:
528
- return disable_success, disable_msg
529
532
 
530
- service_file_path = self.get_service_file_path(name, debug=debug)
531
- service_socket_path = self.get_service_socket_path(name, debug=debug)
532
- socket_path = self.get_socket_path(name, debug=debug)
533
- result_path = self.get_result_path(name, debug=debug)
534
533
  service_logs_path = self.get_service_logs_path(name, debug=debug)
535
534
  logs_paths = [
536
535
  (SYSTEMD_LOGS_RESOURCES_PATH / name)
537
536
  for name in os.listdir(SYSTEMD_LOGS_RESOURCES_PATH)
538
537
  if name.startswith(service_logs_path.name + '.')
539
538
  ]
540
- paths = [service_file_path, service_socket_path, socket_path, result_path] + logs_paths
539
+ paths = [
540
+ self.get_service_file_path(name, debug=debug),
541
+ self.get_service_symlink_file_path(name, debug=debug),
542
+ self.get_socket_path(name, debug=debug),
543
+ self.get_result_path(name, debug=debug),
544
+ ] + logs_paths
545
+
541
546
  for path in paths:
542
547
  if path.exists():
543
548
  try:
@@ -547,7 +552,7 @@ class SystemdExecutor(Executor):
547
552
  return False, str(e)
548
553
 
549
554
  job = self.get_hidden_job(name, debug=debug)
550
- job.delete()
555
+ _ = job.delete()
551
556
 
552
557
  return self.run_command(['daemon-reload'], debug=debug)
553
558
 
@@ -55,10 +55,11 @@ def get_jobs(
55
55
  -------
56
56
  A dictionary mapping job names to jobs.
57
57
  """
58
- from meerschaum.connectors.parse import parse_connector_keys
58
+ from meerschaum.connectors.parse import parse_executor_keys
59
59
  include_local_and_system = (
60
60
  combine_local_and_systemd
61
- and str(executor_keys).split(':')[0] in ('None', 'local', 'systemd')
61
+ and str(executor_keys).split(':', maxsplit=1)[0] in ('None', 'local', 'systemd')
62
+ and get_executor_keys_from_context() == 'systemd'
62
63
  )
63
64
 
64
65
  def _get_local_jobs():
@@ -76,7 +77,12 @@ def get_jobs(
76
77
 
77
78
  def _get_systemd_jobs():
78
79
  conn = mrsm.get_connector('systemd')
79
- return conn.get_jobs(debug=debug)
80
+ jobs = conn.get_jobs(debug=debug)
81
+ return {
82
+ name: job
83
+ for name, job in jobs.items()
84
+ if include_hidden or not job.hidden
85
+ }
80
86
 
81
87
  if include_local_and_system:
82
88
  local_jobs = _get_local_jobs()
@@ -97,9 +103,14 @@ def get_jobs(
97
103
  return {**local_jobs, **systemd_jobs}
98
104
 
99
105
  try:
100
- _ = parse_connector_keys(executor_keys, construct=False)
101
- conn = mrsm.get_connector(executor_keys)
102
- return conn.get_jobs(debug=debug)
106
+ _ = parse_executor_keys(executor_keys, construct=False)
107
+ conn = parse_executor_keys(executor_keys)
108
+ jobs = conn.get_jobs(debug=debug)
109
+ return {
110
+ name: job
111
+ for name, job in jobs.items()
112
+ if include_hidden or not job.hidden
113
+ }
103
114
  except Exception:
104
115
  return {}
105
116
 
@@ -115,10 +126,13 @@ def get_filtered_jobs(
115
126
  Return a list of jobs filtered by the user.
116
127
  """
117
128
  from meerschaum.utils.warnings import warn as _warn
118
- jobs = get_jobs(executor_keys, include_hidden=include_hidden, debug=debug)
119
-
129
+ jobs = get_jobs(executor_keys, include_hidden=True, debug=debug)
120
130
  if not filter_list:
121
- return jobs
131
+ return {
132
+ name: job
133
+ for name, job in jobs.items()
134
+ if include_hidden or not job.hidden
135
+ }
122
136
 
123
137
  jobs_to_return = {}
124
138
  for name in filter_list:
@@ -337,17 +351,26 @@ def stop_check_jobs_thread():
337
351
  warn(f"Failed to remove check jobs lock file:\n{e}")
338
352
 
339
353
 
354
+ _context_keys = None
340
355
  def get_executor_keys_from_context() -> str:
341
356
  """
342
357
  If we are running on the host with the default root, default to `'systemd'`.
343
358
  Otherwise return `'local'`.
344
359
  """
360
+ global _context_keys
361
+
362
+ if _context_keys is not None:
363
+ return _context_keys
364
+
345
365
  from meerschaum.config.paths import ROOT_DIR_PATH, DEFAULT_ROOT_DIR_PATH
346
366
  from meerschaum.utils.misc import is_systemd_available
347
- if is_systemd_available() and ROOT_DIR_PATH == DEFAULT_ROOT_DIR_PATH:
348
- return 'systemd'
349
367
 
350
- return 'local'
368
+ _context_keys = (
369
+ 'systemd'
370
+ if is_systemd_available() and ROOT_DIR_PATH == DEFAULT_ROOT_DIR_PATH
371
+ else 'local'
372
+ )
373
+ return _context_keys
351
374
 
352
375
 
353
376
  def _install_healthcheck_job() -> SuccessTuple:
@@ -112,17 +112,14 @@ def pprint_jobs(
112
112
 
113
113
 
114
114
  for name, job in running_jobs.items():
115
- if job.hidden:
116
- continue
117
-
118
115
  status_group = [
119
116
  (
120
117
  rich_text.Text(job.status, style=('green' if ANSI else ''))
121
118
  if not job.is_blocking_on_stdin()
122
119
  else rich_text.Text('waiting for input', style=('yellow' if ANSI else ''))
123
120
  ),
124
- rich_text.Text(f'PID: {job.pid}'),
125
- ]
121
+ ] + ([rich_text.Text(f"PID: {pid}")] if (pid := job.pid) else [])
122
+
126
123
  if job.restart:
127
124
  status_group.append(rich_text.Text('(restarts)'))
128
125
 
@@ -134,9 +131,6 @@ def pprint_jobs(
134
131
  )
135
132
 
136
133
  for name, job in paused_jobs.items():
137
- if job.hidden:
138
- continue
139
-
140
134
  status_group = [
141
135
  rich_text.Text(job.status, style=('yellow' if ANSI else '')),
142
136
  ]
@@ -151,9 +145,6 @@ def pprint_jobs(
151
145
  )
152
146
 
153
147
  for name, job in stopped_jobs.items():
154
- if job.hidden:
155
- continue
156
-
157
148
  status_group = [
158
149
  rich_text.Text(job.status, style=('red' if ANSI else '')),
159
150
  ]
@@ -182,9 +173,6 @@ def pprint_job(
182
173
  nopretty: bool = False,
183
174
  ):
184
175
  """Pretty-print a single `Job`."""
185
- if job.hidden:
186
- return
187
-
188
176
  from meerschaum.utils.warnings import info
189
177
  if not nopretty:
190
178
  info(f"Command for job '{job.name}':")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: meerschaum
3
- Version: 2.3.0rc1
3
+ Version: 2.3.0rc2
4
4
  Summary: Sync Time-Series Pipes with Meerschaum
5
5
  Home-page: https://meerschaum.io
6
6
  Author: Bennett Meares
@@ -1,9 +1,9 @@
1
1
  meerschaum/__init__.py,sha256=rzLJwaiLJvc_VAOjUM6pzKlm-w8NhHrOCH99Ob1vrjY,1736
2
2
  meerschaum/__main__.py,sha256=r5UjYxH1WA6dGG9YGBPul5xOdgF3Iwl0X4dWDtXU-30,2646
3
3
  meerschaum/_internal/__init__.py,sha256=ilC7utfKtin7GAvuN34fKyUQYfPyqH0Mm3MJF5iyEf4,169
4
- meerschaum/_internal/entry.py,sha256=Le-BekTma050RSmR8LBFWbrhSwCEl7XRbE52J3pSW2A,7497
5
- meerschaum/_internal/arguments/__init__.py,sha256=HFciFQgo2ZOT19Mo6CpLhPYlpLYh2sNn1C9Lo7NMADc,519
6
- meerschaum/_internal/arguments/_parse_arguments.py,sha256=EJfxtQJcoc0DBTTUHLTbC1cwe_K_WAiNOXMLEXGQ7vE,10708
4
+ meerschaum/_internal/entry.py,sha256=D5w3j7w_pWlxfhh-vr1Ao7fzfIIEhUtXc_UTVpy-6GQ,9001
5
+ meerschaum/_internal/arguments/__init__.py,sha256=lZ6YJM5buApdEOOJz61gRdpv1ICbifbiepArBT8hztQ,542
6
+ meerschaum/_internal/arguments/_parse_arguments.py,sha256=Xf5KoHEd3LDSomyXmTb0Kr8cb60AGfCZcGPVsRcq7Kc,12374
7
7
  meerschaum/_internal/arguments/_parser.py,sha256=7vjKEuevFNE48idGz1Jj5dps1-Wq462iXDsOLQfiYcQ,14998
8
8
  meerschaum/_internal/docs/__init__.py,sha256=ZQYHWo6n0kfLLkyG36YXqTYvv2Pc7it5HZHMylT6cBA,126
9
9
  meerschaum/_internal/docs/index.py,sha256=Qovl1fI-KqCz7KtxCIWklqUGUcJ8Sbx4UKAEarrUn_A,18056
@@ -12,7 +12,7 @@ meerschaum/_internal/gui/app/__init__.py,sha256=rKUa8hHk6Fai-PDF61tQcpT1myxKcfmv
12
12
  meerschaum/_internal/gui/app/_windows.py,sha256=-VHdjTzA3V596fVqnbmTxemONSp_80-sTNJ0CTB8FwU,2632
13
13
  meerschaum/_internal/gui/app/actions.py,sha256=rx37qXf3uoa7Ou0n1cISqNFZNL0nr4wO7vSUmWO8f2E,935
14
14
  meerschaum/_internal/gui/app/pipes.py,sha256=4nAQ0rrHb_2bNgDF0Ru2YlbPaCDDzAl5beOGU4Af-4A,1596
15
- meerschaum/_internal/shell/Shell.py,sha256=NX7NQUrRf6xIl7dujbpyVoNAaVRaxhmGonGn46WRTtc,36939
15
+ meerschaum/_internal/shell/Shell.py,sha256=l6_WDD55H_KcH1auqTgadHSyWBpKnJ2FnanYapGXh5k,39437
16
16
  meerschaum/_internal/shell/ShellCompleter.py,sha256=bbG-mExNXO4pltWBOXdbMp8P2wLgy8_BgipIr5aGp5s,3114
17
17
  meerschaum/_internal/shell/ValidAutoSuggest.py,sha256=bARjOWMidz0dvMelLUe6yRPto5l3gcEHYHqFDjoh22I,1280
18
18
  meerschaum/_internal/shell/__init__.py,sha256=vXQoQPEVlYiUYai1b5AwQAlTnja6A2cSABnqXhzlS7I,281
@@ -28,7 +28,7 @@ meerschaum/actions/bootstrap.py,sha256=9D3cBHzgZbZyWy-Y7iQgk9bpTbKEhumFKbIIThZgP
28
28
  meerschaum/actions/clear.py,sha256=OoFZE0bK5m8s3GLNZcixuVT0DMj1izXVxGCATcmUGbI,4851
29
29
  meerschaum/actions/copy.py,sha256=hLRc81oVBjnV22lpeSDb-HsDX2on9K2u6C1H8qJITNQ,6844
30
30
  meerschaum/actions/deduplicate.py,sha256=puYyxeFYEUy1Sd2IOcZB2e6MrNxAZl2bTLmNzFDkCiw,1167
31
- meerschaum/actions/delete.py,sha256=j_GiWsBTt_-1zZukkP8YJEf20AqkAiGgJM0NcOc3Vsc,18710
31
+ meerschaum/actions/delete.py,sha256=GRokg2NRzlow2UMYXNs9xwBu-9AuJdK6kAxsxgwp-E0,18823
32
32
  meerschaum/actions/drop.py,sha256=Hd5h4rrWd7qL2rTqglsTonUsEoH7qQlsfqNFSHGeqr0,2453
33
33
  meerschaum/actions/edit.py,sha256=6d1Y8Ejd4zQWVARvx04cvbGyRA2r4ihJXWqMFiFX0aM,11740
34
34
  meerschaum/actions/install.py,sha256=jdhOrR_KlvinTKr0YJNkUHsnh5EY6OzA7cRq0Vnp1oU,7494
@@ -44,7 +44,7 @@ meerschaum/actions/sh.py,sha256=fLfTJaacKu4sjLTRqEzzYlT2WbbdZBEczsKb6F-qAek,2026
44
44
  meerschaum/actions/show.py,sha256=JAyDWFUVDoRY--ehFEsrso7vrj_wdoxgqL6z-bIF6os,28158
45
45
  meerschaum/actions/sql.py,sha256=wYofwk1vGO96U2ncigGEfMtYMZeprz2FR1PRRZhkAPI,4311
46
46
  meerschaum/actions/stack.py,sha256=7ODAxzmCx8i9AHxvkbr5ZtzUNPpY-iqlSVo4rZHMOw4,5900
47
- meerschaum/actions/start.py,sha256=tPN_Sl4lQPmLllRTzKH5ZCNsvyC9Nd5ImAB2f0T3LaI,17708
47
+ meerschaum/actions/start.py,sha256=e0Ca01VRSu5BQDMec8C9A6c9yfSX6LpIkCTecxa1u8Q,17489
48
48
  meerschaum/actions/stop.py,sha256=5fdUw70YN-yuUWrC-NhA88cxr9FZ5NbssbQ8xXO8nFU,4632
49
49
  meerschaum/actions/sync.py,sha256=AkH-1O5bkUC-UElQGr0lRhrX-z18ZY2nBPSy9EsW1Kc,17506
50
50
  meerschaum/actions/tag.py,sha256=SJf5qFW0ccLXjqlTdkK_0MCcrCMdg6xhYrhKdco0hdA,3053
@@ -140,7 +140,7 @@ meerschaum/config/_preprocess.py,sha256=-AEA8m_--KivZwTQ1sWN6LTn5sio_fUr2XZ51BO6
140
140
  meerschaum/config/_read_config.py,sha256=WFZKIXZMDe_ca0ES7ivgM_mnwShvFxLdoeisT_X5-h0,14720
141
141
  meerschaum/config/_shell.py,sha256=46_m49Txc5q1rGfCgO49ca48BODx45DQJi8D0zz1R18,4245
142
142
  meerschaum/config/_sync.py,sha256=oK2ZujO2T1he08BXCFyiniBUevNGWSQKXLcS_jRv_7Y,4155
143
- meerschaum/config/_version.py,sha256=72j-dU_H0nKu_aipfQemECmHjrsxky5_Tu3bUnQZup4,74
143
+ meerschaum/config/_version.py,sha256=bfQh2_v-HpBVdlfw2zoIhMos9XaCBgtxmAFNwHxb3HM,74
144
144
  meerschaum/config/paths.py,sha256=JjibeGN3YAdSNceRwsd42aNmeUrIgM6ndzC8qZAmNI0,621
145
145
  meerschaum/config/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
146
  meerschaum/config/stack/__init__.py,sha256=Yt7GNzC_hz7iUDZ4gVho_lugJO2DnXgnMtsMG_ReoRg,9114
@@ -148,10 +148,10 @@ meerschaum/config/stack/grafana/__init__.py,sha256=LNXQw2FvHKrD68RDhqDmi2wJjAHaK
148
148
  meerschaum/config/stack/mosquitto/__init__.py,sha256=-OwOjq8KiBoSH_pmgCAAF3Dp3CRD4KgAEdimZSadROs,186
149
149
  meerschaum/config/stack/mosquitto/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
150
150
  meerschaum/config/stack/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
151
- meerschaum/config/static/__init__.py,sha256=LJmBS3hPMGJoi51OBRoACfpKECucTiC5R3FwghlioFw,4987
151
+ meerschaum/config/static/__init__.py,sha256=CvyWdb4B97PFjtNQx0mcz7g-kSbmDElipULUaKYav7k,5052
152
152
  meerschaum/connectors/Connector.py,sha256=utNV3Fy5DhUVbQE-vtm7enH5rH2gxQERmgmP7PUzH30,6682
153
153
  meerschaum/connectors/__init__.py,sha256=b1RdpMUNWtA5Q4KbymeUt9HtEiMWUHf0BBXzcl4itkc,12557
154
- meerschaum/connectors/parse.py,sha256=MdCKHpEO3m9evB1sYd969qZgdoRp-BByPi9FvQzUCUs,4352
154
+ meerschaum/connectors/parse.py,sha256=sDeI2OIS9Inwhbn9jkFAXxOPnmmAHqsuHiiHfWjVnSA,4307
155
155
  meerschaum/connectors/poll.py,sha256=gIY9TvFBqMvMNQvR0O2No7koLLz2PjfExBr_Dsosgpg,7363
156
156
  meerschaum/connectors/api/APIConnector.py,sha256=xe1Bsbnh5PBNR2r5yr6iqJ1UozEKXWJBZnUU0qdXC7c,4934
157
157
  meerschaum/connectors/api/__init__.py,sha256=JwKrGtuE5aOd2VnsRwudFBYyBf5IxczOwPVdNvCUgSQ,205
@@ -201,10 +201,10 @@ meerschaum/core/Plugin/__init__.py,sha256=UXg64EvJPgI1PCxkY_KM02-ZmBm4FZpLPIQR_u
201
201
  meerschaum/core/User/_User.py,sha256=CApB7Y0QJL6S9QOCCfrG4SbPuPXJ9AsAYQ5pASMP_Aw,6527
202
202
  meerschaum/core/User/__init__.py,sha256=lJ7beIZTG9sO4dAi3367fFBl17dXYEWHKi7HoaPlDyk,193
203
203
  meerschaum/jobs/_Executor.py,sha256=ZUsQl0hgU0HW_F9bQCfm8KwrdyTBLCrfxsSnbJOwtWI,1575
204
- meerschaum/jobs/_Job.py,sha256=V8CDNc4hlkMrF0B8DCiNRxU2n2yLdU41OtHU367WUCY,28433
204
+ meerschaum/jobs/_Job.py,sha256=a0bND2kun57FZk8lthO7J6SQseVpkGhn7hmCo0_am-E,28759
205
205
  meerschaum/jobs/_LocalExecutor.py,sha256=v_zvU1vgJDy-iiztXS5gnMayJ0UZnW48qJj3OSB6o-k,2195
206
- meerschaum/jobs/_SystemdExecutor.py,sha256=eBqbkhQmwxwAcX5QoOHJyYJahGS0_uSd8BtbNJomd1E,20832
207
- meerschaum/jobs/__init__.py,sha256=6Vfwpxs64Y4aou70n0HTzZPvCdw_obb6x0FdUuljvwY,10046
206
+ meerschaum/jobs/_SystemdExecutor.py,sha256=Us3MH3KmAJxjLJPJPmegBlZy8HExgRIylNPb7Wro-qk,20933
207
+ meerschaum/jobs/__init__.py,sha256=Lhox8AboqyKmRyq13elSHq85rSDEuz0AQkoFW3PVzr8,10662
208
208
  meerschaum/plugins/_Plugin.py,sha256=q1B4gVAO2BGA-PIR0HI3-O9q1n8BaT7tSANIyW7gUPg,34084
209
209
  meerschaum/plugins/__init__.py,sha256=3Hg9yyfkN0TxPPTnlt6pi53znjRIAR92WpG3zEKYm10,26152
210
210
  meerschaum/plugins/bootstrap.py,sha256=qg9MQ1YAU8ShwGqWDl38WjiXLIxDPl95pSIGDLN9rOw,11423
@@ -233,7 +233,7 @@ meerschaum/utils/daemon/_names.py,sha256=Prf7xA2GWDbKR_9Xq9_5RTTIf9GNWY3Yt0s4tEU
233
233
  meerschaum/utils/dtypes/__init__.py,sha256=JR9PViJTzhukZhq0QoPIs73HOnXZZr8OmfhAAD4OAUA,6261
234
234
  meerschaum/utils/dtypes/sql.py,sha256=IkEOyB63je-rCLHM6WwFzGbCerYk1zobL1cXkWqmTa4,14638
235
235
  meerschaum/utils/formatting/__init__.py,sha256=NcNPxXRSnKZAIBxAD0ictCjVBzYzFtOwpf2CDMfr4_Y,15354
236
- meerschaum/utils/formatting/_jobs.py,sha256=ezUAqEetTxFNoontyJq8fbqg8ntzYgq_AdNRpPZzPAw,6817
236
+ meerschaum/utils/formatting/_jobs.py,sha256=izsqPJhTtUkXUUtWnbXtReYsUYwulXtci3pBj72Ne64,6637
237
237
  meerschaum/utils/formatting/_pipes.py,sha256=wy0iWJFsFl3X2VloaiA_gp9Yx9w6tD3FQZvAQAqef4A,19492
238
238
  meerschaum/utils/formatting/_pprint.py,sha256=tgrT3FyGyu5CWJYysqK3kX1xdZYorlbOk9fcU_vt9Qg,3096
239
239
  meerschaum/utils/formatting/_shell.py,sha256=jsjf_GMXBpGNBbpT7skTUZrHZl5HooFzffRDc4hz5Tc,3786
@@ -242,11 +242,11 @@ meerschaum/utils/packages/_packages.py,sha256=GzbJ0kxW_EQogXmY4vguRkUyad42cshFs7
242
242
  meerschaum/utils/packages/lazy_loader.py,sha256=VHnph3VozH29R4JnSSBfwtA5WKZYZQFT_GeQSShCnuc,2540
243
243
  meerschaum/utils/venv/_Venv.py,sha256=sBnlmxHdAh2bx8btfVoD79-H9-cYsv5lP02IIXkyECs,3553
244
244
  meerschaum/utils/venv/__init__.py,sha256=bLAWnllKDuE_z6bLk7gLh4mI3Sp1j5hsboTqPKOQq84,24361
245
- meerschaum-2.3.0rc1.dist-info/LICENSE,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
246
- meerschaum-2.3.0rc1.dist-info/METADATA,sha256=Rc_33sXeMLhZQ14qcInaTWYrQ_N2SfvO4cR9cCbOWrI,24009
247
- meerschaum-2.3.0rc1.dist-info/NOTICE,sha256=OTA9Fcthjf5BRvWDDIcBC_xfLpeDV-RPZh3M-HQBRtQ,114
248
- meerschaum-2.3.0rc1.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
249
- meerschaum-2.3.0rc1.dist-info/entry_points.txt,sha256=5YBVzibw-0rNA_1VjB16z5GABsOGf-CDhW4yqH8C7Gc,88
250
- meerschaum-2.3.0rc1.dist-info/top_level.txt,sha256=bNoSiDj0El6buocix-FRoAtJOeq1qOF5rRm2u9i7Q6A,11
251
- meerschaum-2.3.0rc1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
252
- meerschaum-2.3.0rc1.dist-info/RECORD,,
245
+ meerschaum-2.3.0rc2.dist-info/LICENSE,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
246
+ meerschaum-2.3.0rc2.dist-info/METADATA,sha256=e_ahh83m8FwVMO1VezxSC_WnK-XJoDUNzmIkFgXbFs8,24009
247
+ meerschaum-2.3.0rc2.dist-info/NOTICE,sha256=OTA9Fcthjf5BRvWDDIcBC_xfLpeDV-RPZh3M-HQBRtQ,114
248
+ meerschaum-2.3.0rc2.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
249
+ meerschaum-2.3.0rc2.dist-info/entry_points.txt,sha256=5YBVzibw-0rNA_1VjB16z5GABsOGf-CDhW4yqH8C7Gc,88
250
+ meerschaum-2.3.0rc2.dist-info/top_level.txt,sha256=bNoSiDj0El6buocix-FRoAtJOeq1qOF5rRm2u9i7Q6A,11
251
+ meerschaum-2.3.0rc2.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
252
+ meerschaum-2.3.0rc2.dist-info/RECORD,,