meerschaum 3.0.0rc4__py3-none-any.whl → 3.0.0rc7__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.
- meerschaum/_internal/arguments/_parser.py +14 -2
- meerschaum/_internal/cli/__init__.py +6 -0
- meerschaum/_internal/cli/daemons.py +103 -0
- meerschaum/_internal/cli/entry.py +220 -0
- meerschaum/_internal/cli/workers.py +434 -0
- meerschaum/_internal/docs/index.py +1 -2
- meerschaum/_internal/entry.py +44 -8
- meerschaum/_internal/shell/Shell.py +113 -19
- meerschaum/_internal/shell/__init__.py +4 -1
- meerschaum/_internal/static.py +3 -1
- meerschaum/_internal/term/TermPageHandler.py +1 -2
- meerschaum/_internal/term/__init__.py +40 -6
- meerschaum/_internal/term/tools.py +33 -8
- meerschaum/actions/__init__.py +6 -4
- meerschaum/actions/api.py +39 -11
- meerschaum/actions/attach.py +1 -0
- meerschaum/actions/delete.py +4 -2
- meerschaum/actions/edit.py +27 -8
- meerschaum/actions/login.py +8 -8
- meerschaum/actions/register.py +13 -7
- meerschaum/actions/reload.py +22 -5
- meerschaum/actions/restart.py +14 -0
- meerschaum/actions/show.py +69 -4
- meerschaum/actions/start.py +135 -14
- meerschaum/actions/stop.py +36 -3
- meerschaum/actions/sync.py +6 -1
- meerschaum/api/__init__.py +35 -13
- meerschaum/api/_events.py +2 -2
- meerschaum/api/_oauth2.py +47 -4
- meerschaum/api/dash/callbacks/dashboard.py +29 -0
- meerschaum/api/dash/callbacks/jobs.py +3 -2
- meerschaum/api/dash/callbacks/login.py +10 -1
- meerschaum/api/dash/callbacks/register.py +9 -2
- meerschaum/api/dash/pages/login.py +2 -2
- meerschaum/api/dash/pipes.py +72 -36
- meerschaum/api/dash/webterm.py +14 -6
- meerschaum/api/models/_pipes.py +7 -1
- meerschaum/api/resources/static/js/terminado.js +3 -0
- meerschaum/api/resources/static/js/xterm-addon-unicode11.js +2 -0
- meerschaum/api/resources/templates/termpage.html +1 -0
- meerschaum/api/routes/_jobs.py +23 -11
- meerschaum/api/routes/_login.py +73 -5
- meerschaum/api/routes/_pipes.py +6 -4
- meerschaum/api/routes/_webterm.py +3 -3
- meerschaum/config/__init__.py +60 -13
- meerschaum/config/_default.py +89 -61
- meerschaum/config/_edit.py +10 -8
- meerschaum/config/_formatting.py +2 -0
- meerschaum/config/_patch.py +4 -2
- meerschaum/config/_paths.py +127 -12
- meerschaum/config/_read_config.py +20 -10
- meerschaum/config/_version.py +1 -1
- meerschaum/config/environment.py +262 -0
- meerschaum/config/stack/__init__.py +7 -5
- meerschaum/connectors/_Connector.py +1 -2
- meerschaum/connectors/__init__.py +37 -2
- meerschaum/connectors/api/_APIConnector.py +1 -1
- meerschaum/connectors/api/_jobs.py +11 -0
- meerschaum/connectors/api/_pipes.py +7 -1
- meerschaum/connectors/instance/_plugins.py +9 -1
- meerschaum/connectors/instance/_tokens.py +20 -3
- meerschaum/connectors/instance/_users.py +8 -1
- meerschaum/connectors/parse.py +1 -1
- meerschaum/connectors/sql/_create_engine.py +3 -0
- meerschaum/connectors/sql/_pipes.py +93 -79
- meerschaum/connectors/sql/_users.py +8 -1
- meerschaum/connectors/valkey/_ValkeyConnector.py +3 -3
- meerschaum/connectors/valkey/_pipes.py +7 -5
- meerschaum/core/Pipe/__init__.py +45 -71
- meerschaum/core/Pipe/_attributes.py +66 -90
- meerschaum/core/Pipe/_cache.py +555 -0
- meerschaum/core/Pipe/_clear.py +0 -11
- meerschaum/core/Pipe/_data.py +0 -50
- meerschaum/core/Pipe/_deduplicate.py +0 -13
- meerschaum/core/Pipe/_delete.py +12 -21
- meerschaum/core/Pipe/_drop.py +11 -23
- meerschaum/core/Pipe/_dtypes.py +1 -1
- meerschaum/core/Pipe/_index.py +8 -14
- meerschaum/core/Pipe/_sync.py +12 -18
- meerschaum/core/Plugin/_Plugin.py +7 -1
- meerschaum/core/Token/_Token.py +1 -1
- meerschaum/core/User/_User.py +1 -2
- meerschaum/jobs/_Executor.py +88 -4
- meerschaum/jobs/_Job.py +135 -35
- meerschaum/jobs/systemd.py +7 -2
- meerschaum/plugins/__init__.py +277 -81
- meerschaum/utils/daemon/Daemon.py +195 -41
- meerschaum/utils/daemon/FileDescriptorInterceptor.py +0 -1
- meerschaum/utils/daemon/RotatingFile.py +63 -36
- meerschaum/utils/daemon/StdinFile.py +53 -13
- meerschaum/utils/daemon/__init__.py +18 -5
- meerschaum/utils/daemon/_names.py +6 -3
- meerschaum/utils/debug.py +34 -4
- meerschaum/utils/dtypes/__init__.py +5 -1
- meerschaum/utils/formatting/__init__.py +4 -1
- meerschaum/utils/formatting/_jobs.py +1 -1
- meerschaum/utils/formatting/_pipes.py +47 -46
- meerschaum/utils/formatting/_shell.py +16 -6
- meerschaum/utils/misc.py +18 -38
- meerschaum/utils/packages/__init__.py +15 -13
- meerschaum/utils/packages/_packages.py +1 -0
- meerschaum/utils/pipes.py +33 -5
- meerschaum/utils/process.py +1 -1
- meerschaum/utils/prompt.py +171 -144
- meerschaum/utils/sql.py +12 -2
- meerschaum/utils/threading.py +42 -0
- meerschaum/utils/venv/__init__.py +2 -0
- meerschaum/utils/warnings.py +19 -13
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/METADATA +3 -1
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/RECORD +116 -110
- meerschaum/config/_environment.py +0 -145
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/WHEEL +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/entry_points.txt +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/licenses/LICENSE +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/licenses/NOTICE +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/top_level.txt +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/zip-safe +0 -0
@@ -0,0 +1,262 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# vim:fenc=utf-8
|
4
|
+
|
5
|
+
"""
|
6
|
+
Patch the runtime configuration from environment variables.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import os
|
10
|
+
import re
|
11
|
+
import json
|
12
|
+
import contextlib
|
13
|
+
import copy
|
14
|
+
import pathlib
|
15
|
+
|
16
|
+
from meerschaum.utils.typing import List, Union, Dict, Any, Optional
|
17
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
18
|
+
|
19
|
+
|
20
|
+
def apply_environment_patches(env: Optional[Dict[str, Any]] = None) -> None:
|
21
|
+
"""
|
22
|
+
Apply patches defined in `MRSM_CONFIG` and `MRSM_PATCH`.
|
23
|
+
"""
|
24
|
+
config_var = STATIC_CONFIG['environment']['config']
|
25
|
+
patch_var = STATIC_CONFIG['environment']['patch']
|
26
|
+
apply_environment_config(config_var, env=env)
|
27
|
+
apply_environment_config(patch_var, env=env)
|
28
|
+
|
29
|
+
|
30
|
+
def apply_environment_config(env_var: str, env: Optional[Dict[str, Any]] = None) -> None:
|
31
|
+
"""
|
32
|
+
Parse a dictionary (simple or JSON) from an environment variable
|
33
|
+
and apply it to the current configuration.
|
34
|
+
"""
|
35
|
+
from meerschaum.config import get_config, set_config, _config
|
36
|
+
from meerschaum.config._patch import apply_patch_to_config
|
37
|
+
|
38
|
+
env = env if env is not None else os.environ
|
39
|
+
|
40
|
+
if env_var not in env:
|
41
|
+
return
|
42
|
+
|
43
|
+
from meerschaum.utils.misc import string_to_dict
|
44
|
+
try:
|
45
|
+
_patch = string_to_dict(str(os.environ[env_var]).lstrip())
|
46
|
+
except Exception:
|
47
|
+
_patch = None
|
48
|
+
|
49
|
+
error_msg = (
|
50
|
+
f"Environment variable {env_var} is set but cannot be parsed.\n"
|
51
|
+
f"Unset {env_var} or change to JSON or simplified dictionary format "
|
52
|
+
"(see --help, under params for formatting)\n"
|
53
|
+
f"{env_var} is set to:\n{os.environ[env_var]}\n"
|
54
|
+
f"Skipping patching os environment into config..."
|
55
|
+
)
|
56
|
+
|
57
|
+
if not isinstance(_patch, dict):
|
58
|
+
print(error_msg)
|
59
|
+
return
|
60
|
+
|
61
|
+
valids = []
|
62
|
+
|
63
|
+
def load_key(key: str) -> Union[Dict[str, Any], None]:
|
64
|
+
try:
|
65
|
+
c = get_config(key, warn=False)
|
66
|
+
except Exception:
|
67
|
+
c = None
|
68
|
+
return c
|
69
|
+
|
70
|
+
### This was multi-threaded, but I ran into all sorts of locking issues.
|
71
|
+
keys = list(_patch.keys())
|
72
|
+
for key in keys:
|
73
|
+
_ = load_key(key)
|
74
|
+
|
75
|
+
### Load and patch config files.
|
76
|
+
set_config(
|
77
|
+
apply_patch_to_config(
|
78
|
+
_config(),
|
79
|
+
_patch,
|
80
|
+
)
|
81
|
+
)
|
82
|
+
|
83
|
+
|
84
|
+
def apply_environment_uris(env: Optional[Dict[str, Any]] = None) -> None:
|
85
|
+
"""
|
86
|
+
Patch temporary connectors defined in environment variables which start with
|
87
|
+
`MRSM_SQL_` or `MRSM_API_`.
|
88
|
+
"""
|
89
|
+
for env_var in get_connector_env_vars(env=env):
|
90
|
+
apply_connector_uri(env_var, env=env)
|
91
|
+
|
92
|
+
|
93
|
+
def get_connector_env_regex() -> str:
|
94
|
+
"""
|
95
|
+
Return the regex pattern for valid environment variable names for instance connectors.
|
96
|
+
"""
|
97
|
+
return STATIC_CONFIG['environment']['uri_regex']
|
98
|
+
|
99
|
+
|
100
|
+
def get_connector_env_vars(env: Optional[Dict[str, Any]] = None) -> List[str]:
|
101
|
+
"""
|
102
|
+
Get the names of the environment variables which match the Meerschaum connector regex.
|
103
|
+
|
104
|
+
Examples
|
105
|
+
--------
|
106
|
+
>>> get_connector_environment_vars()
|
107
|
+
['MRSM_SQL_FOO']
|
108
|
+
"""
|
109
|
+
uri_regex = get_connector_env_regex()
|
110
|
+
env_vars = []
|
111
|
+
|
112
|
+
env = env if env is not None else os.environ
|
113
|
+
|
114
|
+
for env_var in env:
|
115
|
+
matched = re.match(uri_regex, env_var)
|
116
|
+
if matched is None:
|
117
|
+
continue
|
118
|
+
if env_var in STATIC_CONFIG['environment'].values():
|
119
|
+
continue
|
120
|
+
env_vars.append(env_var)
|
121
|
+
|
122
|
+
return env_vars
|
123
|
+
|
124
|
+
|
125
|
+
def apply_connector_uri(env_var: str, env: Optional[Dict[str, Any]] = None) -> None:
|
126
|
+
"""
|
127
|
+
Parse and validate a URI obtained from an environment variable.
|
128
|
+
"""
|
129
|
+
from meerschaum.config import get_config, set_config, _config
|
130
|
+
from meerschaum.config._patch import apply_patch_to_config
|
131
|
+
from meerschaum.config._read_config import search_and_substitute_config
|
132
|
+
from meerschaum.utils.warnings import warn
|
133
|
+
|
134
|
+
env = env if env is not None else os.environ
|
135
|
+
|
136
|
+
if env_var not in env:
|
137
|
+
return
|
138
|
+
|
139
|
+
uri_regex = get_connector_env_regex()
|
140
|
+
matched = re.match(uri_regex, env_var)
|
141
|
+
groups = matched.groups()
|
142
|
+
typ, label = groups[0].lower(), groups[1].lower()
|
143
|
+
if not typ or not label:
|
144
|
+
return
|
145
|
+
|
146
|
+
uri = env[env_var]
|
147
|
+
|
148
|
+
if uri.lstrip().startswith('{') and uri.rstrip().endswith('}'):
|
149
|
+
try:
|
150
|
+
conn_attrs = json.loads(uri)
|
151
|
+
except Exception:
|
152
|
+
warn(f"Unable to parse JSON for environment connector '{typ}:{label}'.")
|
153
|
+
conn_attrs = {'uri': uri}
|
154
|
+
else:
|
155
|
+
conn_attrs = {'uri': uri}
|
156
|
+
|
157
|
+
set_config(
|
158
|
+
apply_patch_to_config(
|
159
|
+
{'meerschaum': get_config('meerschaum')},
|
160
|
+
{'meerschaum': {'connectors': {typ: {label: conn_attrs}}}},
|
161
|
+
)
|
162
|
+
)
|
163
|
+
|
164
|
+
|
165
|
+
def get_env_vars(env: Optional[Dict[str, Any]] = None) -> List[str]:
|
166
|
+
"""
|
167
|
+
Return all environment variables which begin with `'MRSM_'`.
|
168
|
+
"""
|
169
|
+
prefix = STATIC_CONFIG['environment']['prefix']
|
170
|
+
env = env if env is not None else os.environ
|
171
|
+
return sorted([env_var for env_var in env if env_var.startswith(prefix)])
|
172
|
+
|
173
|
+
|
174
|
+
@contextlib.contextmanager
|
175
|
+
def replace_env(env: Union[Dict[str, Any], None]):
|
176
|
+
"""
|
177
|
+
Temporarily replace environment variables and current configuration.
|
178
|
+
|
179
|
+
Parameters
|
180
|
+
----------
|
181
|
+
env: Dict[str, Any]
|
182
|
+
The new environment dictionary to be patched on `os.environ`.
|
183
|
+
"""
|
184
|
+
if env is None:
|
185
|
+
try:
|
186
|
+
yield
|
187
|
+
finally:
|
188
|
+
return
|
189
|
+
|
190
|
+
from meerschaum.config import _config, set_config
|
191
|
+
from meerschaum.config.paths import (
|
192
|
+
set_root,
|
193
|
+
set_plugins_dir_paths,
|
194
|
+
set_venvs_dir_path,
|
195
|
+
set_config_dir_path,
|
196
|
+
ROOT_DIR_PATH,
|
197
|
+
PLUGINS_DIR_PATHS,
|
198
|
+
VIRTENV_RESOURCES_PATH,
|
199
|
+
CONFIG_DIR_PATH,
|
200
|
+
)
|
201
|
+
|
202
|
+
old_environ = dict(os.environ)
|
203
|
+
old_config = copy.deepcopy(_config())
|
204
|
+
old_root_dir_path = ROOT_DIR_PATH
|
205
|
+
old_plugins_dir_paths = PLUGINS_DIR_PATHS
|
206
|
+
old_venvs_dir_path = VIRTENV_RESOURCES_PATH
|
207
|
+
old_config_dir_path = CONFIG_DIR_PATH
|
208
|
+
|
209
|
+
os.environ.update(env)
|
210
|
+
|
211
|
+
root_dir_env_var = STATIC_CONFIG['environment']['root']
|
212
|
+
plugins_dir_env_var = STATIC_CONFIG['environment']['plugins']
|
213
|
+
config_dir_env_var = STATIC_CONFIG['environment']['config_dir']
|
214
|
+
venvs_dir_env_var = STATIC_CONFIG['environment']['venvs']
|
215
|
+
|
216
|
+
replaced_root = False
|
217
|
+
if root_dir_env_var in env:
|
218
|
+
root_dir_path = pathlib.Path(env[root_dir_env_var])
|
219
|
+
set_root(root_dir_path)
|
220
|
+
replaced_root = True
|
221
|
+
|
222
|
+
replaced_plugins = False
|
223
|
+
if plugins_dir_env_var in env:
|
224
|
+
plugins_dir_paths = env[plugins_dir_env_var]
|
225
|
+
set_plugins_dir_paths(plugins_dir_paths)
|
226
|
+
replaced_plugins = True
|
227
|
+
|
228
|
+
replaced_venvs = False
|
229
|
+
if venvs_dir_env_var in env:
|
230
|
+
venv_dir_path = pathlib.Path(env[venvs_dir_env_var])
|
231
|
+
set_venvs_dir_path(venv_dir_path)
|
232
|
+
replaced_venvs = True
|
233
|
+
|
234
|
+
replaced_config_dir = False
|
235
|
+
if config_dir_env_var in env:
|
236
|
+
config_dir_path = pathlib.Path(env[config_dir_env_var])
|
237
|
+
set_config_dir_path(config_dir_path)
|
238
|
+
replaced_config_dir = True
|
239
|
+
|
240
|
+
apply_environment_patches(env)
|
241
|
+
apply_environment_uris(env)
|
242
|
+
|
243
|
+
try:
|
244
|
+
yield
|
245
|
+
finally:
|
246
|
+
os.environ.clear()
|
247
|
+
os.environ.update(old_environ)
|
248
|
+
|
249
|
+
if replaced_root:
|
250
|
+
set_root(old_root_dir_path)
|
251
|
+
|
252
|
+
if replaced_plugins:
|
253
|
+
set_plugins_dir_paths(old_plugins_dir_paths)
|
254
|
+
|
255
|
+
if replaced_venvs:
|
256
|
+
set_venvs_dir_path(old_venvs_dir_path)
|
257
|
+
|
258
|
+
if replaced_config_dir:
|
259
|
+
set_config_dir_path(old_config_dir_path)
|
260
|
+
|
261
|
+
_config().clear()
|
262
|
+
set_config(old_config)
|
@@ -56,19 +56,22 @@ env_dict['MEERSCHAUM_API_CONFIG'] = json.dumps(
|
|
56
56
|
{
|
57
57
|
'meerschaum': 'MRSM{!meerschaum}',
|
58
58
|
'system': 'MRSM{!system}',
|
59
|
+
'api': 'MRSM{!api}',
|
59
60
|
},
|
60
61
|
indent=4,
|
61
62
|
).replace(
|
62
63
|
'"MRSM{!system}"', 'MRSM{!system}'
|
63
64
|
).replace(
|
64
|
-
'"MRSM{!meerschaum}"', 'MRSM{!meerschaum}'
|
65
|
+
'"MRSM{!meerschaum}"', 'MRSM{!meerschaum}'
|
66
|
+
).replace(
|
67
|
+
'"MRSM{!api}"', 'MRSM{!api}'
|
65
68
|
)
|
66
69
|
|
67
70
|
volumes = {
|
68
71
|
'api_root': '/meerschaum',
|
69
|
-
'meerschaum_db_data': '/
|
72
|
+
'meerschaum_db_data': '/home/postgres/pgdata',
|
70
73
|
'grafana_storage': '/var/lib/grafana',
|
71
|
-
'valkey_data': '/
|
74
|
+
'valkey_data': '/valkey/data',
|
72
75
|
}
|
73
76
|
networks = {
|
74
77
|
'frontend': None,
|
@@ -122,7 +125,6 @@ default_docker_compose_config = {
|
|
122
125
|
'POSTGRES_DB': '<DOLLAR>POSTGRES_DB',
|
123
126
|
'POSTGRES_PASSWORD': '<DOLLAR>POSTGRES_PASSWORD',
|
124
127
|
'ALLOW_IP_RANGE': env_dict['ALLOW_IP_RANGE'],
|
125
|
-
# 'POSTGRES_INITDB_ARGS': '-c max_connections=1000 -c shared_buffers=1024MB -c max_prepared_transactions=100'
|
126
128
|
},
|
127
129
|
'command': 'postgres -c max_connections=1000 -c shared_buffers=1024MB -c max_prepared_transactions=100',
|
128
130
|
'healthcheck': {
|
@@ -184,7 +186,7 @@ default_docker_compose_config = {
|
|
184
186
|
],
|
185
187
|
},
|
186
188
|
'valkey': {
|
187
|
-
'image': '
|
189
|
+
'image': 'valkey/valkey:latest',
|
188
190
|
'restart': 'always',
|
189
191
|
'environment': {
|
190
192
|
'VALKEY_PASSWORD': '<DOLLAR>VALKEY_PASSWORD',
|
@@ -152,8 +152,7 @@ class Connector(metaclass=abc.ABCMeta):
|
|
152
152
|
------
|
153
153
|
An error if any of the required attributes are missing.
|
154
154
|
"""
|
155
|
-
from meerschaum.utils.warnings import error
|
156
|
-
from meerschaum.utils.debug import dprint
|
155
|
+
from meerschaum.utils.warnings import error
|
157
156
|
from meerschaum.utils.misc import items_str
|
158
157
|
if required_attributes is None:
|
159
158
|
required_attributes = ['type', 'label']
|
@@ -14,7 +14,7 @@ For ease of use, you can also import from the root `meerschaum` module:
|
|
14
14
|
from __future__ import annotations
|
15
15
|
|
16
16
|
import meerschaum as mrsm
|
17
|
-
from meerschaum.utils.typing import Any, Union, List, Dict
|
17
|
+
from meerschaum.utils.typing import Any, Union, List, Dict, Optional
|
18
18
|
from meerschaum.utils.threading import RLock
|
19
19
|
from meerschaum.utils.warnings import warn
|
20
20
|
|
@@ -51,6 +51,7 @@ _locks: Dict[str, RLock] = {
|
|
51
51
|
'connectors' : RLock(),
|
52
52
|
'types' : RLock(),
|
53
53
|
'custom_types' : RLock(),
|
54
|
+
'plugins_types' : RLock(),
|
54
55
|
'_loaded_plugin_connectors': RLock(),
|
55
56
|
'instance_types' : RLock(),
|
56
57
|
}
|
@@ -58,6 +59,8 @@ _locks: Dict[str, RLock] = {
|
|
58
59
|
### Fill this with objects only when connectors are first referenced.
|
59
60
|
types: Dict[str, Any] = {}
|
60
61
|
custom_types: set = set()
|
62
|
+
plugins_types: Dict[str, List[str]] = {}
|
63
|
+
_known_custom_types: set = set()
|
61
64
|
_loaded_plugin_connectors: bool = False
|
62
65
|
|
63
66
|
|
@@ -72,7 +75,6 @@ def get_connector(
|
|
72
75
|
Return existing connector or create new connection and store for reuse.
|
73
76
|
|
74
77
|
You can create new connectors if enough parameters are provided for the given type and flavor.
|
75
|
-
|
76
78
|
|
77
79
|
Parameters
|
78
80
|
----------
|
@@ -297,16 +299,23 @@ def make_connector(cls, _is_executor: bool = False):
|
|
297
299
|
>>>
|
298
300
|
"""
|
299
301
|
import re
|
302
|
+
from meerschaum.plugins import _get_parent_plugin
|
300
303
|
suffix_regex = (
|
301
304
|
r'connector$'
|
302
305
|
if not _is_executor
|
303
306
|
else r'executor$'
|
304
307
|
)
|
308
|
+
plugin_name = _get_parent_plugin(2)
|
305
309
|
typ = re.sub(suffix_regex, '', cls.__name__.lower())
|
306
310
|
with _locks['types']:
|
307
311
|
types[typ] = cls
|
308
312
|
with _locks['custom_types']:
|
309
313
|
custom_types.add(typ)
|
314
|
+
if plugin_name:
|
315
|
+
with _locks['plugins_types']:
|
316
|
+
if plugin_name not in plugins_types:
|
317
|
+
plugins_types[plugin_name] = []
|
318
|
+
plugins_types[plugin_name].append(typ)
|
310
319
|
with _locks['connectors']:
|
311
320
|
if typ not in connectors:
|
312
321
|
connectors[typ] = {}
|
@@ -337,6 +346,30 @@ def load_plugin_connectors():
|
|
337
346
|
import_plugins(*to_import)
|
338
347
|
|
339
348
|
|
349
|
+
def unload_plugin_connectors(
|
350
|
+
plugin_names: Optional[List[str]] = None,
|
351
|
+
debug: bool = False,
|
352
|
+
) -> None:
|
353
|
+
"""
|
354
|
+
Unload custom connectors added by plugins.
|
355
|
+
"""
|
356
|
+
from meerschaum.plugins import get_plugins_names
|
357
|
+
global custom_types, _known_custom_types, types, plugins_types, connectors
|
358
|
+
|
359
|
+
plugin_names = plugin_names or get_plugins_names()
|
360
|
+
|
361
|
+
for plugin_name in plugin_names:
|
362
|
+
plugin_types = plugins_types.get(plugin_name, [])
|
363
|
+
for typ in plugin_types:
|
364
|
+
_ = types.pop(typ, None)
|
365
|
+
_ = connectors.pop(typ, None)
|
366
|
+
if typ in instance_types:
|
367
|
+
instance_types.remove(typ)
|
368
|
+
|
369
|
+
custom_types.clear()
|
370
|
+
custom_types.update(_known_custom_types)
|
371
|
+
|
372
|
+
|
340
373
|
def get_connector_plugin(
|
341
374
|
connector: Connector,
|
342
375
|
) -> Union[str, None, mrsm.Plugin]:
|
@@ -373,3 +406,5 @@ def _load_builtin_custom_connectors():
|
|
373
406
|
"""
|
374
407
|
import meerschaum.jobs.systemd
|
375
408
|
import meerschaum.connectors.valkey
|
409
|
+
_known_custom_types.add('valkey')
|
410
|
+
_known_custom_types.add('systemd')
|
@@ -380,3 +380,14 @@ def get_job_is_blocking_on_stdin(self, name: str, debug: bool = False) -> bool:
|
|
380
380
|
return False
|
381
381
|
|
382
382
|
return response.json()
|
383
|
+
|
384
|
+
|
385
|
+
def get_job_prompt_kwargs(self, name: str, debug: bool = False) -> Dict[str, Any]:
|
386
|
+
"""
|
387
|
+
Return the kwargs to the blocking `prompt()`, if available.
|
388
|
+
"""
|
389
|
+
response = self.get(JOBS_ENDPOINT + f'/{name}/prompt_kwargs', debug=debug)
|
390
|
+
if not response:
|
391
|
+
return {}
|
392
|
+
|
393
|
+
return response.json()
|
@@ -112,7 +112,13 @@ def fetch_pipes_keys(
|
|
112
112
|
tags: Optional[List[str]] = None,
|
113
113
|
params: Optional[Dict[str, Any]] = None,
|
114
114
|
debug: bool = False
|
115
|
-
) ->
|
115
|
+
) -> List[
|
116
|
+
Union[
|
117
|
+
Tuple[str, str, Union[str, None]],
|
118
|
+
Tuple[str, str, Union[str, None], List[str]],
|
119
|
+
Tuple[str, str, Union[str, None], Dict[str, Any]]
|
120
|
+
]
|
121
|
+
]:
|
116
122
|
"""
|
117
123
|
Fetch registered Pipes' keys from the API.
|
118
124
|
|
@@ -16,13 +16,20 @@ def get_plugins_pipe(self) -> 'mrsm.Pipe':
|
|
16
16
|
"""
|
17
17
|
Return the internal pipe for syncing plugins metadata.
|
18
18
|
"""
|
19
|
+
if '_plugins_pipe' in self.__dict__:
|
20
|
+
return self._plugins_pipe
|
21
|
+
|
22
|
+
cache_connector = self.__dict__.get('_cache_connector', None)
|
19
23
|
users_pipe = self.get_users_pipe()
|
20
24
|
user_id_dtype = users_pipe.dtypes.get('user_id', 'uuid')
|
21
|
-
|
25
|
+
|
26
|
+
self._plugins_pipe = mrsm.Pipe(
|
22
27
|
'mrsm', 'plugins',
|
23
28
|
instance=self,
|
24
29
|
target='mrsm_plugins',
|
25
30
|
temporary=True,
|
31
|
+
cache=True,
|
32
|
+
cache_connector_keys=cache_connector,
|
26
33
|
static=True,
|
27
34
|
null_indices=False,
|
28
35
|
columns={
|
@@ -36,6 +43,7 @@ def get_plugins_pipe(self) -> 'mrsm.Pipe':
|
|
36
43
|
'version': 'string',
|
37
44
|
},
|
38
45
|
)
|
46
|
+
return self._plugins_pipe
|
39
47
|
|
40
48
|
|
41
49
|
def register_plugin(self, plugin: Plugin, debug: bool = False) -> mrsm.SuccessTuple:
|
@@ -15,23 +15,33 @@ import meerschaum as mrsm
|
|
15
15
|
from meerschaum.core import Token, User
|
16
16
|
from meerschaum.core.User import hash_password
|
17
17
|
from meerschaum._internal.static import STATIC_CONFIG
|
18
|
+
from meerschaum.utils.warnings import dprint
|
18
19
|
|
19
20
|
|
20
21
|
def get_tokens_pipe(self) -> mrsm.Pipe:
|
21
22
|
"""
|
22
23
|
Return the internal pipe for tokens management.
|
23
24
|
"""
|
25
|
+
if '_tokens_pipe' in self.__dict__:
|
26
|
+
return self._tokens_pipe
|
27
|
+
|
24
28
|
users_pipe = self.get_users_pipe()
|
25
|
-
user_id_dtype =
|
29
|
+
user_id_dtype = (
|
30
|
+
users_pipe._attributes.get('parameters', {}).get('dtypes', {}).get('user_id', 'uuid')
|
31
|
+
)
|
32
|
+
|
33
|
+
cache_connector = self.__dict__.get('_cache_connector', None)
|
26
34
|
|
27
|
-
|
35
|
+
self._tokens_pipe = mrsm.Pipe(
|
28
36
|
'mrsm', 'tokens',
|
29
37
|
instance=self,
|
30
38
|
target='mrsm_tokens',
|
31
39
|
temporary=True,
|
40
|
+
cache=True,
|
41
|
+
cache_connector_keys=cache_connector,
|
32
42
|
static=True,
|
33
43
|
autotime=True,
|
34
|
-
null_indices=
|
44
|
+
null_indices=False,
|
35
45
|
columns={
|
36
46
|
'datetime': 'creation',
|
37
47
|
'primary': 'id',
|
@@ -51,6 +61,7 @@ def get_tokens_pipe(self) -> mrsm.Pipe:
|
|
51
61
|
'secret_hash': 'string',
|
52
62
|
},
|
53
63
|
)
|
64
|
+
return self._tokens_pipe
|
54
65
|
|
55
66
|
|
56
67
|
def register_token(
|
@@ -200,10 +211,16 @@ def get_tokens(
|
|
200
211
|
if ids:
|
201
212
|
params['id'] = ids
|
202
213
|
|
214
|
+
if debug:
|
215
|
+
dprint(f"Getting tokens with {user_id=}, {params=}")
|
216
|
+
|
203
217
|
tokens_df = tokens_pipe.get_data(params=params, debug=debug)
|
204
218
|
if tokens_df is None:
|
205
219
|
return []
|
206
220
|
|
221
|
+
if debug:
|
222
|
+
dprint(f"Retrieved tokens dataframe:\n{tokens_df}")
|
223
|
+
|
207
224
|
tokens_docs = tokens_df.to_dict(orient='records')
|
208
225
|
return [
|
209
226
|
Token(
|
@@ -18,11 +18,17 @@ def get_users_pipe(self) -> 'mrsm.Pipe':
|
|
18
18
|
"""
|
19
19
|
Return the pipe used for users registration.
|
20
20
|
"""
|
21
|
-
|
21
|
+
if '_users_pipe' in self.__dict__:
|
22
|
+
return self._users_pipe
|
23
|
+
|
24
|
+
cache_connector = self.__dict__.get('_cache_connector', None)
|
25
|
+
self._users_pipe = mrsm.Pipe(
|
22
26
|
'mrsm', 'users',
|
23
27
|
instance=self,
|
24
28
|
target='mrsm_users',
|
25
29
|
temporary=True,
|
30
|
+
cache=True,
|
31
|
+
cache_connector_keys=cache_connector,
|
26
32
|
static=True,
|
27
33
|
null_indices=False,
|
28
34
|
columns={
|
@@ -40,6 +46,7 @@ def get_users_pipe(self) -> 'mrsm.Pipe':
|
|
40
46
|
'unique': 'username',
|
41
47
|
},
|
42
48
|
)
|
49
|
+
return self._users_pipe
|
43
50
|
|
44
51
|
|
45
52
|
def register_user(
|
meerschaum/connectors/parse.py
CHANGED
@@ -111,7 +111,7 @@ def parse_repo_keys(keys: Optional[str] = None, **kw):
|
|
111
111
|
"""Parse the Meerschaum repository value into an APIConnector."""
|
112
112
|
from meerschaum.config import get_config
|
113
113
|
if keys is None:
|
114
|
-
keys = get_config('meerschaum', '
|
114
|
+
keys = get_config('meerschaum', 'repository', patch=True)
|
115
115
|
keys = str(keys)
|
116
116
|
if ':' not in keys:
|
117
117
|
keys = 'api:' + keys
|
@@ -78,6 +78,9 @@ def create_engine(
|
|
78
78
|
_host = self.__dict__.get('host', None)
|
79
79
|
_port = self.__dict__.get('port', None)
|
80
80
|
_database = self.__dict__.get('database', None)
|
81
|
+
if _database == '{SQLITE_DB_PATH}':
|
82
|
+
from meerschaum.config.paths import SQLITE_DB_PATH
|
83
|
+
_database = SQLITE_DB_PATH.as_posix()
|
81
84
|
_options = self.__dict__.get('options', {})
|
82
85
|
if isinstance(_options, str):
|
83
86
|
_options = dict(urllib.parse.parse_qsl(_options))
|