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
@@ -11,14 +11,15 @@ import time
11
11
  import json
12
12
  from io import StringIO
13
13
  from datetime import datetime
14
+
14
15
  import meerschaum as mrsm
15
16
  from meerschaum.utils.debug import dprint
16
17
  from meerschaum.utils.warnings import warn, error
17
18
  from meerschaum.utils.typing import SuccessTuple, Union, Any, Optional, Mapping, List, Dict, Tuple
18
19
 
19
20
  def pipe_r_url(
20
- pipe: mrsm.Pipe
21
- ) -> str:
21
+ pipe: mrsm.Pipe
22
+ ) -> str:
22
23
  """Return a relative URL path from a Pipe's keys."""
23
24
  from meerschaum.config.static import STATIC_CONFIG
24
25
  location_key = pipe.location_key
@@ -30,10 +31,10 @@ def pipe_r_url(
30
31
  )
31
32
 
32
33
  def register_pipe(
33
- self,
34
- pipe: mrsm.Pipe,
35
- debug: bool = False
36
- ) -> SuccessTuple:
34
+ self,
35
+ pipe: mrsm.Pipe,
36
+ debug: bool = False
37
+ ) -> SuccessTuple:
37
38
  """Submit a POST to the API to register a new Pipe object.
38
39
  Returns a tuple of (success_bool, response_dict).
39
40
  """
@@ -59,11 +60,11 @@ def register_pipe(
59
60
 
60
61
 
61
62
  def edit_pipe(
62
- self,
63
- pipe: mrsm.Pipe,
64
- patch: bool = False,
65
- debug: bool = False,
66
- ) -> SuccessTuple:
63
+ self,
64
+ pipe: mrsm.Pipe,
65
+ patch: bool = False,
66
+ debug: bool = False,
67
+ ) -> SuccessTuple:
67
68
  """Submit a PATCH to the API to edit an existing Pipe object.
68
69
  Returns a tuple of (success_bool, response_dict).
69
70
  """
@@ -89,14 +90,14 @@ def edit_pipe(
89
90
 
90
91
 
91
92
  def fetch_pipes_keys(
92
- self,
93
- connector_keys: Optional[List[str]] = None,
94
- metric_keys: Optional[List[str]] = None,
95
- location_keys: Optional[List[str]] = None,
96
- tags: Optional[List[str]] = None,
97
- params: Optional[Dict[str, Any]] = None,
98
- debug: bool = False
99
- ) -> Union[List[Tuple[str, str, Union[str, None]]]]:
93
+ self,
94
+ connector_keys: Optional[List[str]] = None,
95
+ metric_keys: Optional[List[str]] = None,
96
+ location_keys: Optional[List[str]] = None,
97
+ tags: Optional[List[str]] = None,
98
+ params: Optional[Dict[str, Any]] = None,
99
+ debug: bool = False
100
+ ) -> Union[List[Tuple[str, str, Union[str, None]]]]:
100
101
  """
101
102
  Fetch registered Pipes' keys from the API.
102
103
 
@@ -158,13 +159,13 @@ def fetch_pipes_keys(
158
159
 
159
160
 
160
161
  def sync_pipe(
161
- self,
162
- pipe: mrsm.Pipe,
163
- df: Optional[Union['pd.DataFrame', Dict[Any, Any], str]] = None,
164
- chunksize: Optional[int] = -1,
165
- debug: bool = False,
166
- **kw: Any
167
- ) -> SuccessTuple:
162
+ self,
163
+ pipe: mrsm.Pipe,
164
+ df: Optional[Union['pd.DataFrame', Dict[Any, Any], str]] = None,
165
+ chunksize: Optional[int] = -1,
166
+ debug: bool = False,
167
+ **kw: Any
168
+ ) -> SuccessTuple:
168
169
  """Sync a DataFrame into a Pipe."""
169
170
  from decimal import Decimal
170
171
  from meerschaum.utils.debug import dprint
@@ -303,10 +304,10 @@ def sync_pipe(
303
304
 
304
305
 
305
306
  def delete_pipe(
306
- self,
307
- pipe: Optional[meerschaum.Pipe] = None,
308
- debug: bool = None,
309
- ) -> SuccessTuple:
307
+ self,
308
+ pipe: Optional[meerschaum.Pipe] = None,
309
+ debug: bool = None,
310
+ ) -> SuccessTuple:
310
311
  """Delete a Pipe and drop its table."""
311
312
  if pipe is None:
312
313
  error(f"Pipe cannot be None.")
@@ -327,17 +328,17 @@ def delete_pipe(
327
328
 
328
329
 
329
330
  def get_pipe_data(
330
- self,
331
- pipe: meerschaum.Pipe,
332
- select_columns: Optional[List[str]] = None,
333
- omit_columns: Optional[List[str]] = None,
334
- begin: Union[str, datetime, int, None] = None,
335
- end: Union[str, datetime, int, None] = None,
336
- params: Optional[Dict[str, Any]] = None,
337
- as_chunks: bool = False,
338
- debug: bool = False,
339
- **kw: Any
340
- ) -> Union[pandas.DataFrame, None]:
331
+ self,
332
+ pipe: meerschaum.Pipe,
333
+ select_columns: Optional[List[str]] = None,
334
+ omit_columns: Optional[List[str]] = None,
335
+ begin: Union[str, datetime, int, None] = None,
336
+ end: Union[str, datetime, int, None] = None,
337
+ params: Optional[Dict[str, Any]] = None,
338
+ as_chunks: bool = False,
339
+ debug: bool = False,
340
+ **kw: Any
341
+ ) -> Union[pandas.DataFrame, None]:
341
342
  """Fetch data from the API."""
342
343
  r_url = pipe_r_url(pipe)
343
344
  chunks_list = []
@@ -389,10 +390,10 @@ def get_pipe_data(
389
390
 
390
391
 
391
392
  def get_pipe_id(
392
- self,
393
- pipe: meerschuam.Pipe,
394
- debug: bool = False,
395
- ) -> int:
393
+ self,
394
+ pipe: meerschuam.Pipe,
395
+ debug: bool = False,
396
+ ) -> int:
396
397
  """Get a Pipe's ID from the API."""
397
398
  from meerschaum.utils.misc import is_int
398
399
  r_url = pipe_r_url(pipe)
@@ -411,10 +412,10 @@ def get_pipe_id(
411
412
 
412
413
 
413
414
  def get_pipe_attributes(
414
- self,
415
- pipe: meerschaum.Pipe,
416
- debug: bool = False,
417
- ) -> Dict[str, Any]:
415
+ self,
416
+ pipe: meerschaum.Pipe,
417
+ debug: bool = False,
418
+ ) -> Dict[str, Any]:
418
419
  """Get a Pipe's attributes from the API
419
420
 
420
421
  Parameters
@@ -437,12 +438,12 @@ def get_pipe_attributes(
437
438
 
438
439
 
439
440
  def get_sync_time(
440
- self,
441
- pipe: 'meerschaum.Pipe',
442
- params: Optional[Dict[str, Any]] = None,
443
- newest: bool = True,
444
- debug: bool = False,
445
- ) -> Union[datetime, int, None]:
441
+ self,
442
+ pipe: 'meerschaum.Pipe',
443
+ params: Optional[Dict[str, Any]] = None,
444
+ newest: bool = True,
445
+ debug: bool = False,
446
+ ) -> Union[datetime, int, None]:
446
447
  """Get a Pipe's most recent datetime value from the API.
447
448
 
448
449
  Parameters
@@ -492,10 +493,10 @@ def get_sync_time(
492
493
 
493
494
 
494
495
  def pipe_exists(
495
- self,
496
- pipe: 'meerschaum.Pipe',
497
- debug: bool = False
498
- ) -> bool:
496
+ self,
497
+ pipe: mrsm.Pipe,
498
+ debug: bool = False
499
+ ) -> bool:
499
500
  """Check the API to see if a Pipe exists.
500
501
 
501
502
  Parameters
@@ -523,9 +524,9 @@ def pipe_exists(
523
524
 
524
525
 
525
526
  def create_metadata(
526
- self,
527
- debug: bool = False
528
- ) -> bool:
527
+ self,
528
+ debug: bool = False
529
+ ) -> bool:
529
530
  """Create metadata tables.
530
531
 
531
532
  Returns
@@ -547,14 +548,14 @@ def create_metadata(
547
548
 
548
549
 
549
550
  def get_pipe_rowcount(
550
- self,
551
- pipe: 'meerschaum.Pipe',
552
- begin: Optional[datetime] = None,
553
- end: Optional[datetime] = None,
554
- params: Optional[Dict[str, Any]] = None,
555
- remote: bool = False,
556
- debug: bool = False,
557
- ) -> int:
551
+ self,
552
+ pipe: mrsm.Pipe,
553
+ begin: Optional[datetime] = None,
554
+ end: Optional[datetime] = None,
555
+ params: Optional[Dict[str, Any]] = None,
556
+ remote: bool = False,
557
+ debug: bool = False,
558
+ ) -> int:
558
559
  """Get a pipe's row count from the API.
559
560
 
560
561
  Parameters
@@ -600,10 +601,10 @@ def get_pipe_rowcount(
600
601
 
601
602
 
602
603
  def drop_pipe(
603
- self,
604
- pipe: meerschaum.Pipe,
605
- debug: bool = False
606
- ) -> SuccessTuple:
604
+ self,
605
+ pipe: mrsm.Pipe,
606
+ debug: bool = False
607
+ ) -> SuccessTuple:
607
608
  """
608
609
  Drop a pipe's table but maintain its registration.
609
610
 
@@ -644,11 +645,11 @@ def drop_pipe(
644
645
 
645
646
 
646
647
  def clear_pipe(
647
- self,
648
- pipe: meerschaum.Pipe,
649
- debug: bool = False,
650
- **kw
651
- ) -> SuccessTuple:
648
+ self,
649
+ pipe: mrsm.Pipe,
650
+ debug: bool = False,
651
+ **kw
652
+ ) -> SuccessTuple:
652
653
  """
653
654
  Delete rows in a pipe's table.
654
655
 
@@ -666,7 +667,7 @@ def clear_pipe(
666
667
  kw.pop('location_keys', None)
667
668
  kw.pop('action', None)
668
669
  kw.pop('force', None)
669
- return self.do_action(
670
+ return self.do_action_legacy(
670
671
  ['clear', 'pipes'],
671
672
  connector_keys = pipe.connector_keys,
672
673
  metric_keys = pipe.metric_key,
@@ -678,10 +679,10 @@ def clear_pipe(
678
679
 
679
680
 
680
681
  def get_pipe_columns_types(
681
- self,
682
- pipe: meerschaum.Pipe,
683
- debug: bool = False,
684
- ) -> Union[Dict[str, str], None]:
682
+ self,
683
+ pipe: mrsm.Pipe,
684
+ debug: bool = False,
685
+ ) -> Union[Dict[str, str], None]:
685
686
  """
686
687
  Fetch the columns and types of the pipe's table.
687
688
 
meerschaum/jobs/_Job.py CHANGED
@@ -62,8 +62,9 @@ class Job:
62
62
  _properties: Optional[Dict[str, Any]] = None,
63
63
  _rotating_log = None,
64
64
  _stdin_file = None,
65
- _status_hook = None,
66
- _result_hook = None,
65
+ _status_hook: Optional[Callable[[], str]] = None,
66
+ _result_hook: Optional[Callable[[], SuccessTuple]] = None,
67
+ _externally_managed: bool = False,
67
68
  ):
68
69
  """
69
70
  Create a new job to manage a `meerschaum.utils.daemon.Daemon`.
@@ -133,7 +134,10 @@ class Job:
133
134
  if _result_hook is not None:
134
135
  self._result_hook = _result_hook
135
136
 
137
+ self._externally_managed = _externally_managed
136
138
  self._properties_patch = _properties or {}
139
+ if _externally_managed:
140
+ self._properties_patch.update({'externally_managed': _externally_managed})
137
141
 
138
142
  daemon_sysargs = (
139
143
  self._daemon.properties.get('target', {}).get('args', [None])[0]
@@ -154,9 +158,6 @@ class Job:
154
158
  self._properties_patch.update({'restart': True})
155
159
  break
156
160
 
157
- if '--systemd' in self._sysargs:
158
- self._properties_patch.update({'systemd': True})
159
-
160
161
  @staticmethod
161
162
  def from_pid(pid: int, executor_keys: Optional[str] = None) -> Job:
162
163
  """
@@ -824,7 +825,11 @@ class Job:
824
825
  """
825
826
  Return a bool indicating whether this job should be displayed.
826
827
  """
827
- return self.name.startswith('_') or self.name.startswith('.')
828
+ return (
829
+ self.name.startswith('_')
830
+ or self.name.startswith('.')
831
+ or self._is_externally_managed
832
+ )
828
833
 
829
834
  def check_restart(self) -> SuccessTuple:
830
835
  """
@@ -850,6 +855,33 @@ class Job:
850
855
  """
851
856
  return shlex.join(self.sysargs).replace(' + ', '\n+ ')
852
857
 
858
+ @property
859
+ def _externally_managed_file(self) -> pathlib.Path:
860
+ """
861
+ Return the path to the externally managed file.
862
+ """
863
+ return self.daemon.path / '.externally-managed'
864
+
865
+ def _set_externally_managed(self):
866
+ """
867
+ Set this job as externally managed.
868
+ """
869
+ self._externally_managed = True
870
+ try:
871
+ self._externally_managed_file.parent.mkdir(exist_ok=True, parents=True)
872
+ self._externally_managed_file.touch()
873
+ except Exception as e:
874
+ warn(e)
875
+
876
+ @property
877
+ def _is_externally_managed(self) -> bool:
878
+ """
879
+ Return whether this job is externally managed.
880
+ """
881
+ return self.executor_keys in (None, 'local') and (
882
+ self._externally_managed or self._externally_managed_file.exists()
883
+ )
884
+
853
885
  def __str__(self) -> str:
854
886
  sysargs = self.sysargs
855
887
  sysargs_str = shlex.join(sysargs) if sysargs else ''
@@ -16,6 +16,7 @@ from meerschaum.jobs._Executor import Executor
16
16
 
17
17
  __all__ = (
18
18
  'Job',
19
+ 'systemd',
19
20
  'get_jobs',
20
21
  'get_filtered_jobs',
21
22
  'get_restart_jobs',
@@ -23,8 +24,8 @@ __all__ = (
23
24
  'get_stopped_jobs',
24
25
  'get_paused_jobs',
25
26
  'get_restart_jobs',
26
- 'Executor',
27
27
  'make_executor',
28
+ 'Executor',
28
29
  'check_restart_jobs',
29
30
  'start_check_jobs_thread',
30
31
  'stop_check_jobs_thread',
@@ -72,7 +73,8 @@ def get_jobs(
72
73
  return {
73
74
  name: job
74
75
  for name, job in jobs.items()
75
- if include_hidden or not job.hidden
76
+ if (include_hidden or not job.hidden) and not job._is_externally_managed
77
+
76
78
  }
77
79
 
78
80
  def _get_systemd_jobs():
@@ -387,7 +389,7 @@ def _install_healthcheck_job() -> SuccessTuple:
387
389
  return False, "Not running systemd."
388
390
 
389
391
  job = Job(
390
- '.local_healthcheck',
392
+ '.local-healthcheck',
391
393
  ['restart', 'jobs', '-e', 'local', '--loop'],
392
394
  executor_keys='systemd',
393
395
  )
@@ -13,6 +13,7 @@ import asyncio
13
13
  import json
14
14
  import time
15
15
  import traceback
16
+ import shutil
16
17
  from datetime import datetime, timezone
17
18
  from functools import partial
18
19
 
@@ -37,10 +38,10 @@ class SystemdExecutor(Executor):
37
38
  """
38
39
  Return a list of existing jobs, including hidden ones.
39
40
  """
40
- from meerschaum.config.paths import SYSTEMD_ROOT_RESOURCES_PATH
41
+ from meerschaum.config.paths import SYSTEMD_USER_RESOURCES_PATH
41
42
  return [
42
43
  service_name[len('mrsm-'):(-1 * len('.service'))]
43
- for service_name in os.listdir(SYSTEMD_ROOT_RESOURCES_PATH)
44
+ for service_name in os.listdir(SYSTEMD_USER_RESOURCES_PATH)
44
45
  if service_name.startswith('mrsm-') and service_name.endswith('.service')
45
46
  ]
46
47
 
@@ -73,6 +74,13 @@ class SystemdExecutor(Executor):
73
74
  """
74
75
  return f"mrsm-{name.replace(' ', '-')}.service"
75
76
 
77
+ def get_service_job_path(self, name: str, debug: bool = False) -> pathlib.Path:
78
+ """
79
+ Return the path for the job's files under the root directory.
80
+ """
81
+ from meerschaum.config.paths import SYSTEMD_JOBS_RESOURCES_PATH
82
+ return SYSTEMD_JOBS_RESOURCES_PATH / name
83
+
76
84
  def get_service_symlink_file_path(self, name: str, debug: bool = False) -> pathlib.Path:
77
85
  """
78
86
  Return the path to where to create the service symlink.
@@ -84,8 +92,10 @@ class SystemdExecutor(Executor):
84
92
  """
85
93
  Return the path to a Job's service file.
86
94
  """
87
- from meerschaum.config.paths import SYSTEMD_ROOT_RESOURCES_PATH
88
- return SYSTEMD_ROOT_RESOURCES_PATH / self.get_service_name(name, debug=debug)
95
+ return (
96
+ self.get_service_job_path(name, debug=debug)
97
+ / self.get_service_name(name, debug=debug)
98
+ )
89
99
 
90
100
  def get_service_logs_path(self, name: str, debug: bool = False) -> pathlib.Path:
91
101
  """
@@ -94,29 +104,22 @@ class SystemdExecutor(Executor):
94
104
  from meerschaum.config.paths import SYSTEMD_LOGS_RESOURCES_PATH
95
105
  return SYSTEMD_LOGS_RESOURCES_PATH / (self.get_service_name(name, debug=debug) + '.log')
96
106
 
97
- def get_service_socket_path(self, name: str, debug: bool = False) -> pathlib.Path:
98
- """
99
- Return the path to the unit file for the socket (not the socket itself).
100
- """
101
- from meerschaum.config.paths import SYSTEMD_USER_RESOURCES_PATH
102
- return SYSTEMD_USER_RESOURCES_PATH / (
103
- self.get_service_name(name, debug=debug).replace('.service', '.socket')
104
- )
105
-
106
107
  def get_socket_path(self, name: str, debug: bool = False) -> pathlib.Path:
107
108
  """
108
109
  Return the path to the FIFO file.
109
110
  """
110
- from meerschaum.config.paths import SYSTEMD_ROOT_RESOURCES_PATH
111
- return SYSTEMD_ROOT_RESOURCES_PATH / (self.get_service_name(name, debug=debug) + '.stdin')
111
+ return (
112
+ self.get_service_job_path(name, debug=debug)
113
+ / (self.get_service_name(name, debug=debug) + '.stdin')
114
+ )
112
115
 
113
116
  def get_result_path(self, name: str, debug: bool = False) -> pathlib.Path:
114
117
  """
115
118
  Return the path to the result file.
116
119
  """
117
- from meerschaum.config.paths import SYSTEMD_ROOT_RESOURCES_PATH
118
- return SYSTEMD_ROOT_RESOURCES_PATH / (
119
- self.get_service_name(name, debug=debug) + '.result.json'
120
+ return (
121
+ self.get_service_job_path(name, debug=debug)
122
+ / (self.get_service_name(name, debug=debug) + '.result.json')
120
123
  )
121
124
 
122
125
  def get_service_file_text(self, name: str, sysargs: List[str], debug: bool = False) -> str:
@@ -191,17 +194,19 @@ class SystemdExecutor(Executor):
191
194
  """
192
195
  Return the hidden "sister" job to store a job's parameters.
193
196
  """
194
- hidden_name = f'.systemd-{self.get_service_name(name, debug=debug)}'
195
-
196
- return Job(
197
- hidden_name,
197
+ job = Job(
198
+ name,
198
199
  sysargs,
199
200
  executor_keys='local',
200
201
  _rotating_log=self.get_job_rotating_file(name, debug=debug),
201
202
  _stdin_file=self.get_job_stdin_file(name, debug=debug),
202
203
  _status_hook=partial(self.get_job_status, name),
203
204
  _result_hook=partial(self.get_job_result, name),
205
+ _externally_managed=True,
204
206
  )
207
+ job._set_externally_managed()
208
+ return job
209
+
205
210
 
206
211
  def get_job_metadata(self, name: str, debug: bool = False) -> Dict[str, Any]:
207
212
  """
@@ -489,6 +494,7 @@ class SystemdExecutor(Executor):
489
494
 
490
495
  if name not in self._stdin_files:
491
496
  socket_path = self.get_socket_path(name, debug=debug)
497
+ socket_path.parent.mkdir(parents=True, exist_ok=True)
492
498
  self._stdin_files[name] = StdinFile(socket_path)
493
499
 
494
500
  return self._stdin_files[name]
@@ -504,6 +510,9 @@ class SystemdExecutor(Executor):
504
510
  socket_stdin = self.get_job_stdin_file(name, debug=debug)
505
511
  _ = socket_stdin.file_handler
506
512
 
513
+ ### Init the `externally_managed file`.
514
+ _ = self.get_hidden_job(name, debug=debug)
515
+
507
516
  with open(service_file_path, 'w+', encoding='utf-8') as f:
508
517
  f.write(self.get_service_file_text(name, sysargs, debug=debug))
509
518
 
@@ -594,6 +603,14 @@ class SystemdExecutor(Executor):
594
603
  debug=debug,
595
604
  )
596
605
 
606
+ service_job_path = self.get_service_job_path(name, debug=debug)
607
+ try:
608
+ if service_job_path.exists():
609
+ shutil.rmtree(service_job_path)
610
+ except Exception as e:
611
+ warn(e)
612
+ return False, str(e)
613
+
597
614
  service_logs_path = self.get_service_logs_path(name, debug=debug)
598
615
  logs_paths = [
599
616
  (SYSTEMD_LOGS_RESOURCES_PATH / name)
@@ -654,7 +654,7 @@ class Plugin:
654
654
  import ast, re
655
655
  ### NOTE: This technically would break
656
656
  ### if `required` was the very first line of the file.
657
- req_start_match = re.search(r'required(:\s*)?.*=', text)
657
+ req_start_match = re.search(r'\nrequired(:\s*)?.*=', text)
658
658
  if not req_start_match:
659
659
  return []
660
660
  req_start = req_start_match.start()
@@ -28,7 +28,8 @@ _locks = {
28
28
  'PLUGINS_INTERNAL_LOCK_PATH': RLock(),
29
29
  }
30
30
  __all__ = (
31
- "Plugin", "make_action", "api_plugin", "dash_plugin", "import_plugins",
31
+ "Plugin", "make_action", "api_plugin", "dash_plugin", "web_page",
32
+ "import_plugins", "from_plugin_import",
32
33
  "reload_plugins", "get_plugins", "get_data_plugins", "add_plugin_argument",
33
34
  "pre_sync_hook", "post_sync_hook",
34
35
  )
@@ -50,6 +50,7 @@ class StdinFile(io.TextIOBase):
50
50
  if self.file_path.exists():
51
51
  self.file_path.unlink()
52
52
 
53
+ self.file_path.parent.mkdir(parents=True, exist_ok=True)
53
54
  os.mkfifo(self.file_path.as_posix(), mode=0o600)
54
55
 
55
56
  self._fd = os.open(self.file_path, os.O_RDONLY | os.O_NONBLOCK)
@@ -18,7 +18,8 @@ _bank: Dict[str, Dict[str, List[str]]] = {
18
18
  'bright', 'dark', 'neon',
19
19
  ],
20
20
  'sizes': [
21
- 'big', 'small', 'large', 'huge', 'tiny', 'long', 'short', 'grand', 'mini', 'micro'
21
+ 'big', 'small', 'large', 'huge', 'tiny', 'long', 'short', 'average', 'mini', 'micro',
22
+ 'maximum', 'minimum', 'median',
22
23
  ],
23
24
  'personalities': [
24
25
  'groovy', 'cool', 'awesome', 'nice', 'fantastic', 'sweet', 'great', 'amazing',
@@ -26,29 +27,36 @@ _bank: Dict[str, Dict[str, List[str]]] = {
26
27
  ],
27
28
  'emotions': [
28
29
  'angry', 'happy', 'excited', 'suspicious', 'sad', 'thankful', 'grateful', 'satisfied',
30
+ 'peaceful', 'ferocious', 'content',
29
31
  ],
30
32
  'sensations': [
31
33
  'sleepy', 'awake', 'alert', 'thirsty', 'comfy', 'warm', 'cold', 'chilly', 'soft',
32
- 'smooth', 'chunky',
34
+ 'smooth', 'chunky', 'hungry',
33
35
  ],
34
36
  'materials': [
35
37
  'golden', 'silver', 'metal', 'plastic', 'wool', 'wooden', 'nylon', 'fuzzy', 'silky',
38
+ 'suede', 'vinyl',
36
39
  ],
37
40
  'qualities': [
38
41
  'expensive', 'cheap', 'premier', 'best', 'favorite', 'better', 'good', 'affordable',
42
+ 'organic', 'electric',
39
43
  ],
40
44
  },
41
45
  'nouns' : {
42
46
  'animals': [
43
- 'mouse', 'fox', 'horse', 'dragon', 'pig', 'hippo', 'elephant' , 'tiger', 'deer',
47
+ 'mouse', 'fox', 'horse', 'pig', 'hippo', 'elephant' , 'tiger', 'deer', 'salmon',
44
48
  'gerbil', 'snake', 'turtle', 'rhino', 'dog', 'cat', 'giraffe', 'rabbit', 'squirrel',
45
49
  'unicorn', 'lizard', 'lion', 'bear', 'gazelle', 'whale', 'dolphin', 'fish', 'butterfly',
46
50
  'ladybug', 'fly', 'shrimp', 'flamingo', 'parrot', 'tuna', 'panda', 'lemur', 'duck',
47
51
  'seal', 'walrus', 'seagull', 'iguana', 'salamander', 'kitten', 'puppy', 'octopus',
48
52
  ],
53
+ 'weather': [
54
+ 'rain', 'sun', 'snow', 'wind', 'tornado', 'hurricane', 'blizzard', 'monsoon', 'storm',
55
+ 'shower', 'hail',
56
+ ],
49
57
  'plants': [
50
58
  'tree', 'flower', 'vine', 'fern', 'palm', 'palmetto', 'oak', 'pine', 'rose', 'lily',
51
- 'ivy',
59
+ 'ivy', 'leaf', 'shrubbery', 'acorn', 'fruit',
52
60
  ],
53
61
  'foods': [
54
62
  'pizza', 'sushi', 'apple', 'banana', 'sandwich', 'burger', 'taco', 'bratwurst',
@@ -74,8 +82,6 @@ _bank: Dict[str, Dict[str, List[str]]] = {
74
82
  },
75
83
  }
76
84
 
77
- _disallow_combinations: List[Tuple[str, str]] = []
78
-
79
85
  _adjectives: List[str]= []
80
86
  for category, items in _bank['adjectives'].items():
81
87
  _adjectives += items
@@ -96,12 +102,8 @@ def generate_random_name(separator: str = '-'):
96
102
  -------
97
103
  A string containing an random adjective and random noun.
98
104
  """
99
- while True:
100
- adjective_category = random.choice(list(_bank['adjectives'].keys()))
101
- noun_category = random.choice(list(_bank['nouns'].keys()))
102
- if (adjective_category, noun_category) in _disallow_combinations:
103
- continue
104
- break
105
+ adjective_category = random.choice(list(_bank['adjectives'].keys()))
106
+ noun_category = random.choice(list(_bank['nouns'].keys()))
105
107
  return (
106
108
  random.choice(_bank['adjectives'][adjective_category])
107
109
  + separator
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: meerschaum
3
- Version: 2.3.0rc3
3
+ Version: 2.3.1
4
4
  Summary: Sync Time-Series Pipes with Meerschaum
5
5
  Home-page: https://meerschaum.io
6
6
  Author: Bennett Meares