meerschaum 2.9.5__py3-none-any.whl → 3.0.0__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 (200) hide show
  1. meerschaum/__init__.py +5 -2
  2. meerschaum/_internal/__init__.py +1 -0
  3. meerschaum/_internal/arguments/_parse_arguments.py +4 -4
  4. meerschaum/_internal/arguments/_parser.py +33 -4
  5. meerschaum/_internal/cli/__init__.py +6 -0
  6. meerschaum/_internal/cli/daemons.py +103 -0
  7. meerschaum/_internal/cli/entry.py +220 -0
  8. meerschaum/_internal/cli/workers.py +435 -0
  9. meerschaum/_internal/docs/index.py +48 -2
  10. meerschaum/_internal/entry.py +50 -14
  11. meerschaum/_internal/shell/Shell.py +121 -29
  12. meerschaum/_internal/shell/__init__.py +4 -1
  13. meerschaum/_internal/static.py +359 -0
  14. meerschaum/_internal/term/TermPageHandler.py +1 -2
  15. meerschaum/_internal/term/__init__.py +40 -6
  16. meerschaum/_internal/term/tools.py +33 -8
  17. meerschaum/actions/__init__.py +6 -4
  18. meerschaum/actions/api.py +53 -13
  19. meerschaum/actions/attach.py +1 -0
  20. meerschaum/actions/bootstrap.py +8 -8
  21. meerschaum/actions/delete.py +4 -2
  22. meerschaum/actions/edit.py +171 -25
  23. meerschaum/actions/login.py +8 -8
  24. meerschaum/actions/register.py +143 -6
  25. meerschaum/actions/reload.py +22 -5
  26. meerschaum/actions/restart.py +14 -0
  27. meerschaum/actions/show.py +184 -31
  28. meerschaum/actions/start.py +166 -17
  29. meerschaum/actions/stop.py +38 -2
  30. meerschaum/actions/sync.py +7 -2
  31. meerschaum/actions/tag.py +9 -8
  32. meerschaum/actions/verify.py +5 -8
  33. meerschaum/api/__init__.py +45 -15
  34. meerschaum/api/_events.py +46 -4
  35. meerschaum/api/_oauth2.py +162 -9
  36. meerschaum/api/_tokens.py +102 -0
  37. meerschaum/api/dash/__init__.py +0 -3
  38. meerschaum/api/dash/callbacks/__init__.py +1 -0
  39. meerschaum/api/dash/callbacks/custom.py +4 -3
  40. meerschaum/api/dash/callbacks/dashboard.py +198 -118
  41. meerschaum/api/dash/callbacks/jobs.py +14 -7
  42. meerschaum/api/dash/callbacks/login.py +10 -1
  43. meerschaum/api/dash/callbacks/pipes.py +194 -14
  44. meerschaum/api/dash/callbacks/plugins.py +0 -1
  45. meerschaum/api/dash/callbacks/register.py +10 -3
  46. meerschaum/api/dash/callbacks/settings/password_reset.py +2 -2
  47. meerschaum/api/dash/callbacks/tokens.py +389 -0
  48. meerschaum/api/dash/components.py +36 -15
  49. meerschaum/api/dash/jobs.py +1 -1
  50. meerschaum/api/dash/keys.py +35 -93
  51. meerschaum/api/dash/pages/__init__.py +2 -1
  52. meerschaum/api/dash/pages/dashboard.py +1 -20
  53. meerschaum/api/dash/pages/{job.py → jobs.py} +10 -7
  54. meerschaum/api/dash/pages/login.py +2 -2
  55. meerschaum/api/dash/pages/pipes.py +16 -5
  56. meerschaum/api/dash/pages/settings/password_reset.py +1 -1
  57. meerschaum/api/dash/pages/tokens.py +53 -0
  58. meerschaum/api/dash/pipes.py +382 -95
  59. meerschaum/api/dash/sessions.py +12 -0
  60. meerschaum/api/dash/tokens.py +603 -0
  61. meerschaum/api/dash/websockets.py +1 -1
  62. meerschaum/api/dash/webterm.py +18 -6
  63. meerschaum/api/models/__init__.py +23 -3
  64. meerschaum/api/models/_actions.py +22 -0
  65. meerschaum/api/models/_pipes.py +91 -7
  66. meerschaum/api/models/_tokens.py +81 -0
  67. meerschaum/api/resources/static/js/terminado.js +3 -0
  68. meerschaum/api/resources/static/js/xterm-addon-unicode11.js +2 -0
  69. meerschaum/api/resources/templates/termpage.html +13 -0
  70. meerschaum/api/routes/__init__.py +1 -0
  71. meerschaum/api/routes/_actions.py +3 -4
  72. meerschaum/api/routes/_connectors.py +3 -7
  73. meerschaum/api/routes/_jobs.py +26 -35
  74. meerschaum/api/routes/_login.py +120 -15
  75. meerschaum/api/routes/_misc.py +5 -10
  76. meerschaum/api/routes/_pipes.py +178 -143
  77. meerschaum/api/routes/_plugins.py +38 -28
  78. meerschaum/api/routes/_tokens.py +236 -0
  79. meerschaum/api/routes/_users.py +47 -35
  80. meerschaum/api/routes/_version.py +3 -3
  81. meerschaum/api/routes/_webterm.py +3 -3
  82. meerschaum/config/__init__.py +100 -30
  83. meerschaum/config/_default.py +132 -64
  84. meerschaum/config/_edit.py +38 -32
  85. meerschaum/config/_formatting.py +2 -0
  86. meerschaum/config/_patch.py +10 -8
  87. meerschaum/config/_paths.py +133 -13
  88. meerschaum/config/_read_config.py +87 -36
  89. meerschaum/config/_sync.py +6 -3
  90. meerschaum/config/_version.py +1 -1
  91. meerschaum/config/environment.py +262 -0
  92. meerschaum/config/stack/__init__.py +37 -15
  93. meerschaum/config/static.py +18 -0
  94. meerschaum/connectors/_Connector.py +11 -6
  95. meerschaum/connectors/__init__.py +41 -22
  96. meerschaum/connectors/api/_APIConnector.py +34 -6
  97. meerschaum/connectors/api/_actions.py +2 -2
  98. meerschaum/connectors/api/_jobs.py +12 -1
  99. meerschaum/connectors/api/_login.py +33 -7
  100. meerschaum/connectors/api/_misc.py +2 -2
  101. meerschaum/connectors/api/_pipes.py +23 -32
  102. meerschaum/connectors/api/_plugins.py +2 -2
  103. meerschaum/connectors/api/_request.py +1 -1
  104. meerschaum/connectors/api/_tokens.py +146 -0
  105. meerschaum/connectors/api/_users.py +70 -58
  106. meerschaum/connectors/instance/_InstanceConnector.py +83 -0
  107. meerschaum/connectors/instance/__init__.py +10 -0
  108. meerschaum/connectors/instance/_pipes.py +442 -0
  109. meerschaum/connectors/instance/_plugins.py +159 -0
  110. meerschaum/connectors/instance/_tokens.py +317 -0
  111. meerschaum/connectors/instance/_users.py +188 -0
  112. meerschaum/connectors/parse.py +5 -2
  113. meerschaum/connectors/sql/_SQLConnector.py +22 -5
  114. meerschaum/connectors/sql/_cli.py +12 -11
  115. meerschaum/connectors/sql/_create_engine.py +12 -168
  116. meerschaum/connectors/sql/_fetch.py +2 -18
  117. meerschaum/connectors/sql/_pipes.py +295 -278
  118. meerschaum/connectors/sql/_plugins.py +29 -0
  119. meerschaum/connectors/sql/_sql.py +46 -21
  120. meerschaum/connectors/sql/_users.py +36 -2
  121. meerschaum/connectors/sql/tables/__init__.py +254 -122
  122. meerschaum/connectors/valkey/_ValkeyConnector.py +5 -7
  123. meerschaum/connectors/valkey/_pipes.py +60 -31
  124. meerschaum/connectors/valkey/_plugins.py +2 -26
  125. meerschaum/core/Pipe/__init__.py +115 -85
  126. meerschaum/core/Pipe/_attributes.py +425 -124
  127. meerschaum/core/Pipe/_bootstrap.py +54 -24
  128. meerschaum/core/Pipe/_cache.py +555 -0
  129. meerschaum/core/Pipe/_clear.py +0 -11
  130. meerschaum/core/Pipe/_data.py +96 -68
  131. meerschaum/core/Pipe/_deduplicate.py +0 -13
  132. meerschaum/core/Pipe/_delete.py +12 -21
  133. meerschaum/core/Pipe/_drop.py +11 -23
  134. meerschaum/core/Pipe/_dtypes.py +49 -19
  135. meerschaum/core/Pipe/_edit.py +14 -4
  136. meerschaum/core/Pipe/_fetch.py +1 -1
  137. meerschaum/core/Pipe/_index.py +8 -14
  138. meerschaum/core/Pipe/_show.py +5 -5
  139. meerschaum/core/Pipe/_sync.py +123 -204
  140. meerschaum/core/Pipe/_verify.py +4 -4
  141. meerschaum/{plugins → core/Plugin}/_Plugin.py +16 -12
  142. meerschaum/core/Plugin/__init__.py +1 -1
  143. meerschaum/core/Token/_Token.py +220 -0
  144. meerschaum/core/Token/__init__.py +12 -0
  145. meerschaum/core/User/_User.py +35 -10
  146. meerschaum/core/User/__init__.py +9 -1
  147. meerschaum/core/__init__.py +1 -0
  148. meerschaum/jobs/_Executor.py +88 -4
  149. meerschaum/jobs/_Job.py +149 -38
  150. meerschaum/jobs/__init__.py +3 -2
  151. meerschaum/jobs/systemd.py +8 -3
  152. meerschaum/models/__init__.py +35 -0
  153. meerschaum/models/pipes.py +247 -0
  154. meerschaum/models/tokens.py +38 -0
  155. meerschaum/models/users.py +26 -0
  156. meerschaum/plugins/__init__.py +301 -88
  157. meerschaum/plugins/bootstrap.py +510 -4
  158. meerschaum/utils/_get_pipes.py +97 -30
  159. meerschaum/utils/daemon/Daemon.py +199 -43
  160. meerschaum/utils/daemon/FileDescriptorInterceptor.py +0 -1
  161. meerschaum/utils/daemon/RotatingFile.py +63 -36
  162. meerschaum/utils/daemon/StdinFile.py +53 -13
  163. meerschaum/utils/daemon/__init__.py +47 -6
  164. meerschaum/utils/daemon/_names.py +6 -3
  165. meerschaum/utils/dataframe.py +479 -81
  166. meerschaum/utils/debug.py +49 -19
  167. meerschaum/utils/dtypes/__init__.py +476 -34
  168. meerschaum/utils/dtypes/sql.py +369 -29
  169. meerschaum/utils/formatting/__init__.py +5 -2
  170. meerschaum/utils/formatting/_jobs.py +1 -1
  171. meerschaum/utils/formatting/_pipes.py +52 -50
  172. meerschaum/utils/formatting/_pprint.py +1 -0
  173. meerschaum/utils/formatting/_shell.py +44 -18
  174. meerschaum/utils/misc.py +268 -186
  175. meerschaum/utils/packages/__init__.py +25 -40
  176. meerschaum/utils/packages/_packages.py +42 -34
  177. meerschaum/utils/pipes.py +213 -0
  178. meerschaum/utils/process.py +2 -2
  179. meerschaum/utils/prompt.py +175 -144
  180. meerschaum/utils/schedule.py +2 -1
  181. meerschaum/utils/sql.py +134 -47
  182. meerschaum/utils/threading.py +42 -0
  183. meerschaum/utils/typing.py +1 -4
  184. meerschaum/utils/venv/_Venv.py +2 -2
  185. meerschaum/utils/venv/__init__.py +7 -7
  186. meerschaum/utils/warnings.py +19 -13
  187. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/METADATA +94 -96
  188. meerschaum-3.0.0.dist-info/RECORD +289 -0
  189. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/WHEEL +1 -1
  190. meerschaum-3.0.0.dist-info/licenses/NOTICE +2 -0
  191. meerschaum/api/models/_interfaces.py +0 -15
  192. meerschaum/api/models/_locations.py +0 -15
  193. meerschaum/api/models/_metrics.py +0 -15
  194. meerschaum/config/_environment.py +0 -145
  195. meerschaum/config/static/__init__.py +0 -186
  196. meerschaum-2.9.5.dist-info/RECORD +0 -263
  197. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/entry_points.txt +0 -0
  198. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/licenses/LICENSE +0 -0
  199. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/top_level.txt +0 -0
  200. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/zip-safe +0 -0
@@ -28,6 +28,8 @@ default_formatting_config = {
28
28
  'connector' : '🔌',
29
29
  'metric' : '📊',
30
30
  'location' : '📍',
31
+ 'locked' : '🔒',
32
+ 'unlocked' : '🔓',
31
33
  'key' : '🔑',
32
34
  'idea' : '💡',
33
35
  'connected' : '🟢',
@@ -9,12 +9,13 @@ Functions for patching the configuration dictionary
9
9
  import sys
10
10
  import copy
11
11
  from meerschaum.utils.typing import Dict, Any
12
- from meerschaum.utils.warnings import warn
12
+ from meerschaum.utils.warnings import warn as _warn
13
13
 
14
14
  def apply_patch_to_config(
15
- config: Dict[str, Any],
16
- patch: Dict[str, Any],
17
- ) -> Dict[str, Any]:
15
+ config: Dict[str, Any],
16
+ patch: Dict[str, Any],
17
+ warn: bool = False,
18
+ ) -> Dict[str, Any]:
18
19
  """Patch the config dict with a new dict (cascade patching)."""
19
20
  _base = copy.deepcopy(config) if isinstance(config, dict) else {}
20
21
  if not isinstance(patch, dict):
@@ -24,7 +25,8 @@ def apply_patch_to_config(
24
25
  if base is None:
25
26
  return {}
26
27
  if not isinstance(base, dict):
27
- warn(f"Overwriting the value {base} with a dictionary:\n{patch}")
28
+ if warn:
29
+ _warn(f"Overwriting the value {base} with a dictionary:\n{patch}")
28
30
  base = {}
29
31
  for key, value in patch.items():
30
32
  if isinstance(value, dict):
@@ -37,9 +39,9 @@ def apply_patch_to_config(
37
39
 
38
40
 
39
41
  def write_patch(
40
- patch: Dict[str, Any],
41
- debug: bool = False
42
- ):
42
+ patch: Dict[str, Any],
43
+ debug: bool = False
44
+ ) -> None:
43
45
  """Write patch dict to yaml."""
44
46
  from meerschaum.utils.debug import dprint
45
47
  from meerschaum.config._paths import PATCH_DIR_PATH
@@ -9,9 +9,16 @@ Define file paths
9
9
  from __future__ import annotations
10
10
 
11
11
  from pathlib import Path
12
- import os, platform, sys, json
13
- from meerschaum.utils.typing import Union
14
- from meerschaum.config.static import STATIC_CONFIG
12
+ import contextlib
13
+ import os
14
+ import platform
15
+ import sys
16
+ import json
17
+
18
+ from typing import Union, List
19
+
20
+ from meerschaum._internal.static import STATIC_CONFIG
21
+
15
22
 
16
23
  DOT_CONFIG_DIR_PATH = Path(
17
24
  os.environ.get('XDG_CONFIG_HOME', Path.home() / '.config')
@@ -71,7 +78,7 @@ if ENVIRONMENT_PLUGINS_DIR in os.environ:
71
78
  if path_str
72
79
  ]
73
80
  )
74
- except Exception as e:
81
+ except Exception:
75
82
  PLUGINS_DIR_PATHS = []
76
83
 
77
84
  if not PLUGINS_DIR_PATHS:
@@ -82,20 +89,23 @@ if ENVIRONMENT_PLUGINS_DIR in os.environ:
82
89
  f"`export {ENVIRONMENT_PLUGINS_DIR}=./plugins:/another/path/to/plugins`\n\n"
83
90
  "or a JSON-encoded path list:\n\n"
84
91
  f"`export {ENVIRONMENT_PLUGINS_DIR}=" + "'[\"./plugins\", \"/another/path/to/plugins\"]'`"
85
- f"",
92
+ "",
86
93
  )
87
94
  sys.exit(1)
88
95
  else:
89
96
  PLUGINS_DIR_PATHS = [_ROOT_DIR_PATH / 'plugins']
90
97
 
91
98
  ### Remove duplicate plugins paths.
92
- _seen_plugins_paths, _plugins_paths_to_remove = set(), set()
93
- for _plugin_path in PLUGINS_DIR_PATHS:
94
- if _plugin_path in _seen_plugins_paths:
95
- _plugins_paths_to_remove.add(_plugin_path)
96
- _seen_plugins_paths.add(_plugin_path)
97
- for _plugin_path in _plugins_paths_to_remove:
98
- PLUGINS_DIR_PATHS.remove(_plugin_path)
99
+ def _process_plugins_dir_paths(plugins_dir_paths: List[Path]):
100
+ _seen_plugins_paths, _plugins_paths_to_remove = set(), set()
101
+ for _plugin_path in plugins_dir_paths:
102
+ if _plugin_path in _seen_plugins_paths:
103
+ _plugins_paths_to_remove.add(_plugin_path)
104
+ _seen_plugins_paths.add(_plugin_path)
105
+ for _plugin_path in _plugins_paths_to_remove:
106
+ plugins_dir_paths.remove(_plugin_path)
107
+ _process_plugins_dir_paths(PLUGINS_DIR_PATHS)
108
+
99
109
 
100
110
  ENVIRONMENT_VENVS_DIR = STATIC_CONFIG['environment']['venvs']
101
111
  if ENVIRONMENT_VENVS_DIR in os.environ:
@@ -144,11 +154,17 @@ paths = {
144
154
  'API_SECRET_KEY_PATH' : ('{API_CONFIG_RESOURCES_PATH}', '.api_secret_key'),
145
155
  'API_UVICORN_RESOURCES_PATH' : ('{API_CONFIG_RESOURCES_PATH}', 'uvicorn'),
146
156
  'API_UVICORN_CONFIG_PATH' : ('{API_UVICORN_RESOURCES_PATH}', '.thread_config.json'),
157
+
158
+ 'WEBTERM_INTERNAL_RESOURCES_PATH': ('{INTERNAL_RESOURCES_PATH}', 'webterm'),
147
159
 
148
160
  'CACHE_RESOURCES_PATH' : ('{ROOT_DIR_PATH}', '.cache'),
149
161
  'PIPES_CACHE_RESOURCES_PATH' : ('{CACHE_RESOURCES_PATH}', 'pipes'),
150
162
  'USERS_CACHE_RESOURCES_PATH' : ('{CACHE_RESOURCES_PATH}', 'users'),
151
163
  'VENVS_CACHE_RESOURCES_PATH' : ('{CACHE_RESOURCES_PATH}', 'venvs'),
164
+ 'SQL_CONN_CACHE_RESOURCES_PATH' : ('{CACHE_RESOURCES_PATH}', 'sql'),
165
+
166
+ 'CLI_RESOURCES_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'cli'),
167
+ 'CLI_LOGS_RESOURCES_PATH' : ('{CLI_RESOURCES_PATH}', 'logs'),
152
168
 
153
169
  'PLUGINS_RESOURCES_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'plugins'),
154
170
  'PLUGINS_INTERNAL_LOCK_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'plugins.lock'),
@@ -156,6 +172,11 @@ paths = {
156
172
  'PLUGINS_ARCHIVES_RESOURCES_PATH': ('{PLUGINS_RESOURCES_PATH}', '.archives'),
157
173
  'PLUGINS_TEMP_RESOURCES_PATH' : ('{PLUGINS_RESOURCES_PATH}', '.tmp'),
158
174
  'PLUGINS_INIT_PATH' : ('{PLUGINS_RESOURCES_PATH}', '__init__.py'),
175
+ 'PLUGINS_INJECTED_RESOURCES_PATH': ('{PLUGINS_RESOURCES_PATH}', '.injected'),
176
+
177
+ 'DB_RESOURCES_PATH' : ('{ROOT_DIR_PATH}', 'db'),
178
+ 'DB_INIT_RESOURCES_PATH' : ('{DB_RESOURCES_PATH}', 'initdb'),
179
+ 'DB_CREATE_EXTENSIONS_PATH' : ('{DB_INIT_RESOURCES_PATH}', 'create-extensions.sql'),
159
180
 
160
181
  'SQLITE_RESOURCES_PATH' : ('{ROOT_DIR_PATH}', 'sqlite'),
161
182
  'SQLITE_DB_PATH' : ('{SQLITE_RESOURCES_PATH}', 'mrsm_local.db'),
@@ -192,11 +213,110 @@ paths = {
192
213
 
193
214
  def set_root(root: Union[Path, str]):
194
215
  """Modify the value of `ROOT_DIR_PATH`."""
195
- paths['ROOT_DIR_PATH'] = Path(root).resolve()
216
+ paths['ROOT_DIR_PATH'] = Path(root).resolve().as_posix()
196
217
  for path_name, path_parts in paths.items():
197
218
  if isinstance(path_parts, tuple) and path_parts[0] == '{ROOT_DIR_PATH}':
198
219
  globals()[path_name] = __getattr__(path_name)
199
220
 
221
+ def set_plugins_dir_paths(plugins_dir_paths: Union[List[Path], Path, str]):
222
+ """Modify the value of `PLUGINS_DIR_PATHS`."""
223
+ global PLUGINS_DIR_PATHS
224
+ if isinstance(plugins_dir_paths, str):
225
+ if plugins_dir_paths.strip() and plugins_dir_paths.lstrip()[0] == '[':
226
+ plugins_dir_paths = json.loads(plugins_dir_paths)
227
+ else:
228
+ plugins_dir_paths = plugins_dir_paths.split(':')
229
+ plugins_dir_paths = [Path(_path).resolve() for _path in plugins_dir_paths]
230
+ if isinstance(plugins_dir_paths, Path):
231
+ plugins_dir_paths = [plugins_dir_paths.resolve()]
232
+
233
+ PLUGINS_DIR_PATHS = plugins_dir_paths
234
+ _process_plugins_dir_paths(plugins_dir_paths)
235
+
236
+ def set_venvs_dir_path(venvs_dir_path: Union[str, Path]):
237
+ """Modify the value of `VIRTENV_RESOURCES_PATH`."""
238
+ paths['VIRTENV_RESOURCES_PATH'] = Path(venvs_dir_path).resolve().as_posix()
239
+
240
+ def set_config_dir_path(config_dir_path: Union[str, Path]):
241
+ paths['CONFIG_DIR_PATH'] = Path(config_dir_path).resolve().as_posix()
242
+
243
+
244
+ @contextlib.contextmanager
245
+ def replace_root_dir(root_dir_path: Union[str, Path, None]):
246
+ """
247
+ Temporarily replace the root directory path.
248
+ """
249
+ if root_dir_path is None:
250
+ try:
251
+ yield
252
+ finally:
253
+ return
254
+
255
+ old_root = paths.get('ROOT_DIR_PATH', _ROOT_DIR_PATH)
256
+ set_root(root_dir_path)
257
+
258
+ try:
259
+ yield
260
+ finally:
261
+ set_root(old_root)
262
+
263
+ @contextlib.contextmanager
264
+ def replace_plugins_dir_paths(plugins_dir_paths: Union[List[Path], None]):
265
+ """
266
+ Temporarily replace the plugins directory paths.
267
+ """
268
+ if plugins_dir_paths is None:
269
+ try:
270
+ yield
271
+ finally:
272
+ return
273
+
274
+ old_plugins_dir_paths = PLUGINS_DIR_PATHS
275
+ set_plugins_dir_paths(plugins_dir_paths)
276
+
277
+ try:
278
+ yield
279
+ finally:
280
+ set_plugins_dir_paths(old_plugins_dir_paths)
281
+
282
+ @contextlib.contextmanager
283
+ def replace_venvs_dir_path(venvs_dir_path: Union[Path, None]):
284
+ """
285
+ Temporarily replace the virtual environments directory path.
286
+ """
287
+ if venvs_dir_path is None:
288
+ try:
289
+ yield
290
+ finally:
291
+ return
292
+
293
+ old_venvs_dir_path = paths.get('VIRTENV_RESOURCES_PATH', _VENVS_DIR_PATH)
294
+ set_venvs_dir_path(venvs_dir_path)
295
+
296
+ try:
297
+ yield
298
+ finally:
299
+ set_venvs_dir_path(old_venvs_dir_path)
300
+
301
+ @contextlib.contextmanager
302
+ def replace_config_dir_path(config_dir_path: Union[Path, None]):
303
+ """
304
+ Temporarily replace the config directory path.
305
+ """
306
+ if config_dir_path is None:
307
+ try:
308
+ yield
309
+ finally:
310
+ return
311
+
312
+ old_config_dir_path = paths.get('CONFIG_DIR_PATH', _CONFIG_DIR_PATH)
313
+ set_config_dir_path(config_dir_path)
314
+
315
+ try:
316
+ yield
317
+ finally:
318
+ set_config_dir_path(old_config_dir_path)
319
+
200
320
 
201
321
  def __getattr__(name: str) -> Path:
202
322
  if name not in paths:
@@ -8,8 +8,9 @@ Import the config yaml file
8
8
  from __future__ import annotations
9
9
  import pathlib
10
10
 
11
+ import meerschaum as mrsm
11
12
  from meerschaum.utils.typing import Optional, Dict, Any, List, Tuple, Union
12
- from meerschaum.config import get_config
13
+ from meerschaum._internal.static import STATIC_CONFIG
13
14
 
14
15
 
15
16
  def read_config(
@@ -49,11 +50,11 @@ def read_config(
49
50
  >>> read_config(keys=['meerschaum'], with_filename=True)
50
51
  >>> ({...}, ['meerschaum.yaml'])
51
52
  """
52
- import sys, shutil, os, json, itertools
53
- from meerschaum.utils.packages import attempt_import
53
+ import os
54
+ import json
55
+ import itertools
54
56
  from meerschaum.utils.yaml import yaml, _yaml
55
57
  from meerschaum.config._paths import CONFIG_DIR_PATH
56
- from meerschaum.config.static import STATIC_CONFIG
57
58
  from meerschaum.config._patch import apply_patch_to_config
58
59
  if directory is None:
59
60
  directory = CONFIG_DIR_PATH
@@ -106,20 +107,25 @@ def read_config(
106
107
  ### If default config contains symlinks, add them to the config to write.
107
108
  try:
108
109
  _default_symlinks = _default_dict[symlinks_key][mk]
109
- except Exception as e:
110
+ except KeyError:
110
111
  _default_symlinks = {}
112
+
111
113
  config[mk] = _default_dict[mk]
112
114
  if _default_symlinks:
113
115
  if symlinks_key not in config:
114
116
  config[symlinks_key] = {}
117
+ if symlinks_key not in config_to_write:
118
+ config_to_write[symlinks_key] = {}
119
+
115
120
  if mk not in config[symlinks_key]:
116
121
  config[symlinks_key][mk] = {}
122
+ if mk not in config_to_write[symlinks_key]:
123
+ config_to_write[symlinks_key][mk] = {}
124
+
117
125
  config[symlinks_key][mk] = apply_patch_to_config(
118
126
  config[symlinks_key][mk],
119
127
  _default_symlinks
120
128
  )
121
- if symlinks_key not in config_to_write:
122
- config_to_write[symlinks_key] = {}
123
129
  config_to_write[symlinks_key][mk] = config[symlinks_key][mk]
124
130
 
125
131
  ### Write the default key.
@@ -179,6 +185,7 @@ def read_config(
179
185
  import traceback
180
186
  traceback.print_exc()
181
187
  _config_key = {}
188
+ substitute = False
182
189
  _single_key_config = (
183
190
  search_and_substitute_config({key: _config_key}) if substitute
184
191
  else {key: _config_key}
@@ -208,15 +215,16 @@ def read_config(
208
215
 
209
216
 
210
217
  def search_and_substitute_config(
211
- config: Dict[str, Any],
212
- leading_key: str = "MRSM",
213
- delimiter: str = ":",
214
- begin_key: str = "{",
215
- end_key: str = "}",
216
- literal_key: str = '!',
217
- keep_symlinks: bool = True,
218
- ) -> Dict[str, Any]:
219
- """Search the config for Meerschaum substitution syntax and substite with value of keys.
218
+ config: Dict[str, Any],
219
+ leading_key: str = "MRSM",
220
+ delimiter: str = ":",
221
+ begin_key: str = "{",
222
+ end_key: str = "}",
223
+ literal_key: str = '!',
224
+ keep_symlinks: bool = True,
225
+ ) -> Dict[str, Any]:
226
+ """
227
+ Search the config for Meerschaum substitution syntax and substite with value of keys.
220
228
 
221
229
  Parameters
222
230
  ----------
@@ -242,7 +250,7 @@ def search_and_substitute_config(
242
250
  - ' MRSM{a:b:c} ' => ' "{\'d\': 1}"' : not isolated
243
251
  - ' MRSM{!a:b:c} ' => ' {"d": 1}' : literal
244
252
 
245
- keep_symlinks :
253
+ keep_symlinks: bool, default True
246
254
  If True, include the symlinks under the top-level key '_symlinks' (never written to a file).
247
255
  Defaults to True.
248
256
 
@@ -251,7 +259,13 @@ def search_and_substitute_config(
251
259
  ```
252
260
  MRSM{meerschaum:connectors:main:host} => cf['meerschaum']['connectors']['main']['host']
253
261
  ```
262
+
263
+ Returns
264
+ -------
265
+ The configuration dictionary with `MRSM{}` symlinks replaced with
266
+ the values from the current configuration.
254
267
  """
268
+ from meerschaum.config import get_config
255
269
 
256
270
  _links = []
257
271
  def _find_symlinks(d, _keys: Optional[List[str]] = None):
@@ -270,9 +284,6 @@ def search_and_substitute_config(
270
284
  import json
271
285
  needle = leading_key + begin_key
272
286
  haystack = json.dumps(config, separators=(',', ':'))
273
- mod_haystack = list(str(haystack))
274
- buff = str(needle)
275
- max_index = len(haystack) - len(buff)
276
287
 
277
288
  patterns = {}
278
289
  isolated_patterns = {}
@@ -329,7 +340,7 @@ def search_and_substitute_config(
329
340
  write_missing=False,
330
341
  sync_files=False,
331
342
  )
332
- except Exception as e:
343
+ except Exception:
333
344
  import traceback
334
345
  traceback.print_exc()
335
346
  valid = False
@@ -382,15 +393,55 @@ def search_and_substitute_config(
382
393
  s[_keys[-1]] = _pattern
383
394
 
384
395
  from meerschaum.config._patch import apply_patch_to_config
385
- from meerschaum.config.static import STATIC_CONFIG
386
396
  symlinks_key = STATIC_CONFIG['config']['symlinks_key']
387
- if symlinks_key not in parsed_config:
388
- parsed_config[symlinks_key] = {}
389
- parsed_config[symlinks_key] = apply_patch_to_config(parsed_config[symlinks_key], symlinks)
397
+ if symlinks:
398
+ if symlinks_key not in parsed_config:
399
+ parsed_config[symlinks_key] = symlinks
400
+ else:
401
+ parsed_config[symlinks_key] = apply_patch_to_config(
402
+ parsed_config[symlinks_key],
403
+ symlinks,
404
+ warn=False,
405
+ )
390
406
 
391
407
  return parsed_config
392
408
 
393
409
 
410
+ def revert_symlinks_config(config: Dict[str, Any]) -> Dict[str, Any]:
411
+ """
412
+ Given a configuration dictionary, re-apply the values from the
413
+ accompanying `_symlinks` dictionary.
414
+
415
+ Parameters
416
+ ----------
417
+ config: Dict[str, Any]
418
+ The configuration dictionary containing a `_symlinks` dictionary.
419
+
420
+ Returns
421
+ -------
422
+ A configuration dictionary with `_symlinks` re-applied.
423
+ """
424
+ import copy
425
+ from meerschaum._internal.static import STATIC_CONFIG
426
+
427
+ symlinks_key = STATIC_CONFIG['config']['symlinks_key']
428
+ if symlinks_key not in config:
429
+ return config
430
+
431
+ reverted_config = copy.deepcopy(config)
432
+ symlinks_config = reverted_config.pop(symlinks_key)
433
+
434
+ def deep_patch(target_dict, patch_dict):
435
+ for key, value in patch_dict.items():
436
+ if isinstance(value, dict) and key in target_dict and isinstance(target_dict[key], dict):
437
+ deep_patch(target_dict[key], value)
438
+ else:
439
+ target_dict[key] = value
440
+
441
+ deep_patch(reverted_config, symlinks_config)
442
+ return reverted_config
443
+
444
+
394
445
  def get_possible_keys() -> List[str]:
395
446
  """
396
447
  Return a list of possible top-level keys.
@@ -407,12 +458,13 @@ def get_possible_keys() -> List[str]:
407
458
 
408
459
 
409
460
  def get_keyfile_path(
410
- key: str,
411
- create_new: bool = False,
412
- directory: Union[pathlib.Path, str, None] = None,
413
- ) -> Union[pathlib.Path, None]:
461
+ key: str,
462
+ create_new: bool = False,
463
+ directory: Union[pathlib.Path, str, None] = None,
464
+ ) -> Union[pathlib.Path, None]:
414
465
  """Determine a key's file path."""
415
- import os, pathlib
466
+ import os
467
+ import pathlib
416
468
  if directory is None:
417
469
  from meerschaum.config._paths import CONFIG_DIR_PATH
418
470
  directory = CONFIG_DIR_PATH
@@ -422,16 +474,15 @@ def get_keyfile_path(
422
474
  os.path.join(
423
475
  directory,
424
476
  read_config(
425
- keys = [key],
426
- with_filenames = True,
427
- write_missing = False,
428
- substitute = False,
477
+ keys=[key],
478
+ with_filenames=True,
479
+ write_missing=False,
480
+ substitute=False,
429
481
  )[1][0]
430
482
  )
431
483
  )
432
- except IndexError as e:
484
+ except IndexError:
433
485
  if create_new:
434
- from meerschaum.config.static import STATIC_CONFIG
435
486
  default_filetype = STATIC_CONFIG['config']['default_filetype']
436
487
  return pathlib.Path(os.path.join(directory, key + '.' + default_filetype))
437
488
  return None
@@ -40,10 +40,11 @@ def sync_yaml_configs(
40
40
  If provided, iterate through a list of tuples,
41
41
  replacing the old string (index 0) with the new string (index 1).
42
42
  """
43
- import os, sys
43
+ import os
44
+ import sys
44
45
  try:
45
46
  from meerschaum.utils.yaml import yaml, _yaml
46
- except Exception as e:
47
+ except Exception:
47
48
  return
48
49
  from meerschaum.config._patch import apply_patch_to_config
49
50
  import meerschaum.config
@@ -110,7 +111,8 @@ def sync_files(keys: Optional[List[str]] = None):
110
111
  GRAFANA_DATASOURCE_PATH,
111
112
  GRAFANA_DASHBOARD_PATH,
112
113
  )
113
- from meerschaum.config.static import STATIC_CONFIG
114
+ from meerschaum._internal.static import STATIC_CONFIG
115
+ from meerschaum.config.stack import _write_initdb
114
116
 
115
117
  sync_yaml_configs(
116
118
  ['stack', STACK_COMPOSE_FILENAME],
@@ -131,6 +133,7 @@ def sync_files(keys: Optional[List[str]] = None):
131
133
  GRAFANA_DASHBOARD_PATH,
132
134
  substitute=True,
133
135
  )
136
+ _write_initdb()
134
137
 
135
138
  key_functions = {
136
139
  'stack': _stack,
@@ -2,4 +2,4 @@
2
2
  Specify the Meerschaum release version.
3
3
  """
4
4
 
5
- __version__ = "2.9.5"
5
+ __version__ = "3.0.0"