meerschaum 2.9.4__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.
- meerschaum/__init__.py +5 -2
- meerschaum/_internal/__init__.py +1 -0
- meerschaum/_internal/arguments/_parse_arguments.py +4 -4
- meerschaum/_internal/arguments/_parser.py +33 -4
- 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 +435 -0
- meerschaum/_internal/docs/index.py +48 -2
- meerschaum/_internal/entry.py +50 -14
- meerschaum/_internal/shell/Shell.py +121 -29
- meerschaum/_internal/shell/__init__.py +4 -1
- meerschaum/_internal/static.py +359 -0
- 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 +53 -13
- meerschaum/actions/attach.py +1 -0
- meerschaum/actions/bootstrap.py +8 -8
- meerschaum/actions/delete.py +4 -2
- meerschaum/actions/edit.py +171 -25
- meerschaum/actions/login.py +8 -8
- meerschaum/actions/register.py +143 -6
- meerschaum/actions/reload.py +22 -5
- meerschaum/actions/restart.py +14 -0
- meerschaum/actions/show.py +184 -31
- meerschaum/actions/start.py +166 -17
- meerschaum/actions/stop.py +38 -2
- meerschaum/actions/sync.py +7 -2
- meerschaum/actions/tag.py +9 -8
- meerschaum/actions/verify.py +5 -8
- meerschaum/api/__init__.py +45 -15
- meerschaum/api/_events.py +46 -4
- meerschaum/api/_oauth2.py +162 -9
- meerschaum/api/_tokens.py +102 -0
- meerschaum/api/dash/__init__.py +0 -3
- meerschaum/api/dash/callbacks/__init__.py +1 -0
- meerschaum/api/dash/callbacks/custom.py +4 -3
- meerschaum/api/dash/callbacks/dashboard.py +228 -117
- meerschaum/api/dash/callbacks/jobs.py +14 -7
- meerschaum/api/dash/callbacks/login.py +10 -1
- meerschaum/api/dash/callbacks/pipes.py +194 -14
- meerschaum/api/dash/callbacks/plugins.py +0 -1
- meerschaum/api/dash/callbacks/register.py +10 -3
- meerschaum/api/dash/callbacks/settings/password_reset.py +2 -2
- meerschaum/api/dash/callbacks/tokens.py +389 -0
- meerschaum/api/dash/components.py +36 -15
- meerschaum/api/dash/jobs.py +1 -1
- meerschaum/api/dash/keys.py +35 -93
- meerschaum/api/dash/pages/__init__.py +2 -1
- meerschaum/api/dash/pages/dashboard.py +1 -20
- meerschaum/api/dash/pages/{job.py → jobs.py} +10 -7
- meerschaum/api/dash/pages/login.py +2 -2
- meerschaum/api/dash/pages/pipes.py +16 -5
- meerschaum/api/dash/pages/settings/password_reset.py +1 -1
- meerschaum/api/dash/pages/tokens.py +53 -0
- meerschaum/api/dash/pipes.py +438 -88
- meerschaum/api/dash/sessions.py +12 -0
- meerschaum/api/dash/tokens.py +603 -0
- meerschaum/api/dash/websockets.py +1 -1
- meerschaum/api/dash/webterm.py +18 -6
- meerschaum/api/models/__init__.py +23 -3
- meerschaum/api/models/_actions.py +22 -0
- meerschaum/api/models/_pipes.py +91 -7
- meerschaum/api/models/_tokens.py +81 -0
- meerschaum/api/resources/static/css/dash.css +16 -0
- 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 +13 -0
- meerschaum/api/routes/__init__.py +1 -0
- meerschaum/api/routes/_actions.py +3 -4
- meerschaum/api/routes/_connectors.py +3 -7
- meerschaum/api/routes/_jobs.py +26 -35
- meerschaum/api/routes/_login.py +120 -15
- meerschaum/api/routes/_misc.py +5 -10
- meerschaum/api/routes/_pipes.py +178 -143
- meerschaum/api/routes/_plugins.py +38 -28
- meerschaum/api/routes/_tokens.py +236 -0
- meerschaum/api/routes/_users.py +47 -35
- meerschaum/api/routes/_version.py +3 -3
- meerschaum/api/routes/_webterm.py +3 -3
- meerschaum/config/__init__.py +100 -30
- meerschaum/config/_default.py +132 -64
- meerschaum/config/_edit.py +38 -32
- meerschaum/config/_formatting.py +2 -0
- meerschaum/config/_patch.py +10 -8
- meerschaum/config/_paths.py +133 -13
- meerschaum/config/_read_config.py +87 -36
- meerschaum/config/_sync.py +6 -3
- meerschaum/config/_version.py +1 -1
- meerschaum/config/environment.py +262 -0
- meerschaum/config/stack/__init__.py +37 -15
- meerschaum/config/static.py +18 -0
- meerschaum/connectors/_Connector.py +11 -6
- meerschaum/connectors/__init__.py +41 -22
- meerschaum/connectors/api/_APIConnector.py +34 -6
- meerschaum/connectors/api/_actions.py +2 -2
- meerschaum/connectors/api/_jobs.py +12 -1
- meerschaum/connectors/api/_login.py +33 -7
- meerschaum/connectors/api/_misc.py +2 -2
- meerschaum/connectors/api/_pipes.py +23 -32
- meerschaum/connectors/api/_plugins.py +2 -2
- meerschaum/connectors/api/_request.py +1 -1
- meerschaum/connectors/api/_tokens.py +146 -0
- meerschaum/connectors/api/_users.py +70 -58
- meerschaum/connectors/instance/_InstanceConnector.py +83 -0
- meerschaum/connectors/instance/__init__.py +10 -0
- meerschaum/connectors/instance/_pipes.py +442 -0
- meerschaum/connectors/instance/_plugins.py +159 -0
- meerschaum/connectors/instance/_tokens.py +317 -0
- meerschaum/connectors/instance/_users.py +188 -0
- meerschaum/connectors/parse.py +5 -2
- meerschaum/connectors/sql/_SQLConnector.py +22 -5
- meerschaum/connectors/sql/_cli.py +12 -11
- meerschaum/connectors/sql/_create_engine.py +12 -168
- meerschaum/connectors/sql/_fetch.py +2 -18
- meerschaum/connectors/sql/_pipes.py +295 -278
- meerschaum/connectors/sql/_plugins.py +29 -0
- meerschaum/connectors/sql/_sql.py +47 -22
- meerschaum/connectors/sql/_users.py +36 -2
- meerschaum/connectors/sql/tables/__init__.py +254 -122
- meerschaum/connectors/valkey/_ValkeyConnector.py +5 -7
- meerschaum/connectors/valkey/_pipes.py +60 -31
- meerschaum/connectors/valkey/_plugins.py +2 -26
- meerschaum/core/Pipe/__init__.py +115 -85
- meerschaum/core/Pipe/_attributes.py +425 -124
- meerschaum/core/Pipe/_bootstrap.py +54 -24
- meerschaum/core/Pipe/_cache.py +555 -0
- meerschaum/core/Pipe/_clear.py +0 -11
- meerschaum/core/Pipe/_data.py +96 -68
- 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 +49 -19
- meerschaum/core/Pipe/_edit.py +14 -4
- meerschaum/core/Pipe/_fetch.py +1 -1
- meerschaum/core/Pipe/_index.py +8 -14
- meerschaum/core/Pipe/_show.py +5 -5
- meerschaum/core/Pipe/_sync.py +123 -204
- meerschaum/core/Pipe/_verify.py +4 -4
- meerschaum/{plugins → core/Plugin}/_Plugin.py +16 -12
- meerschaum/core/Plugin/__init__.py +1 -1
- meerschaum/core/Token/_Token.py +220 -0
- meerschaum/core/Token/__init__.py +12 -0
- meerschaum/core/User/_User.py +35 -10
- meerschaum/core/User/__init__.py +9 -1
- meerschaum/core/__init__.py +1 -0
- meerschaum/jobs/_Executor.py +88 -4
- meerschaum/jobs/_Job.py +149 -38
- meerschaum/jobs/__init__.py +3 -2
- meerschaum/jobs/systemd.py +8 -3
- meerschaum/models/__init__.py +35 -0
- meerschaum/models/pipes.py +247 -0
- meerschaum/models/tokens.py +38 -0
- meerschaum/models/users.py +26 -0
- meerschaum/plugins/__init__.py +301 -88
- meerschaum/plugins/bootstrap.py +510 -4
- meerschaum/utils/_get_pipes.py +97 -30
- meerschaum/utils/daemon/Daemon.py +199 -43
- 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 +47 -6
- meerschaum/utils/daemon/_names.py +6 -3
- meerschaum/utils/dataframe.py +480 -82
- meerschaum/utils/debug.py +49 -19
- meerschaum/utils/dtypes/__init__.py +478 -37
- meerschaum/utils/dtypes/sql.py +369 -29
- meerschaum/utils/formatting/__init__.py +5 -2
- meerschaum/utils/formatting/_jobs.py +1 -1
- meerschaum/utils/formatting/_pipes.py +52 -50
- meerschaum/utils/formatting/_pprint.py +1 -0
- meerschaum/utils/formatting/_shell.py +44 -18
- meerschaum/utils/misc.py +268 -186
- meerschaum/utils/packages/__init__.py +25 -40
- meerschaum/utils/packages/_packages.py +42 -34
- meerschaum/utils/pipes.py +213 -0
- meerschaum/utils/process.py +2 -2
- meerschaum/utils/prompt.py +175 -144
- meerschaum/utils/schedule.py +2 -1
- meerschaum/utils/sql.py +135 -49
- meerschaum/utils/threading.py +42 -0
- meerschaum/utils/typing.py +1 -4
- meerschaum/utils/venv/_Venv.py +2 -2
- meerschaum/utils/venv/__init__.py +7 -7
- meerschaum/utils/warnings.py +19 -13
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/METADATA +94 -96
- meerschaum-3.0.0.dist-info/RECORD +289 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/WHEEL +1 -1
- meerschaum-3.0.0.dist-info/licenses/NOTICE +2 -0
- meerschaum/api/models/_interfaces.py +0 -15
- meerschaum/api/models/_locations.py +0 -15
- meerschaum/api/models/_metrics.py +0 -15
- meerschaum/config/_environment.py +0 -145
- meerschaum/config/static/__init__.py +0 -186
- meerschaum-2.9.4.dist-info/RECORD +0 -263
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/top_level.txt +0 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/zip-safe +0 -0
@@ -14,7 +14,7 @@ from functools import partial
|
|
14
14
|
|
15
15
|
import meerschaum as mrsm
|
16
16
|
from meerschaum.utils.typing import SuccessTuple, List, Callable, Optional
|
17
|
-
from meerschaum.
|
17
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
18
18
|
|
19
19
|
ACTIONS_ENDPOINT: str = STATIC_CONFIG['api']['endpoints']['actions']
|
20
20
|
TEMP_PREFIX: str = STATIC_CONFIG['api']['jobs']['temp_prefix']
|
@@ -88,7 +88,7 @@ def do_action_legacy(
|
|
88
88
|
"""
|
89
89
|
import sys, json
|
90
90
|
from meerschaum.utils.debug import dprint
|
91
|
-
from meerschaum.
|
91
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
92
92
|
from meerschaum.utils.misc import json_serialize_datetime
|
93
93
|
if action is None:
|
94
94
|
action = []
|
@@ -14,7 +14,7 @@ from datetime import datetime
|
|
14
14
|
import meerschaum as mrsm
|
15
15
|
from meerschaum.utils.typing import Dict, Any, SuccessTuple, List, Union, Callable, Optional
|
16
16
|
from meerschaum.jobs import Job
|
17
|
-
from meerschaum.
|
17
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
18
18
|
from meerschaum.utils.warnings import warn, dprint
|
19
19
|
|
20
20
|
JOBS_ENDPOINT: str = STATIC_CONFIG['api']['endpoints']['jobs']
|
@@ -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()
|
@@ -11,7 +11,7 @@ from __future__ import annotations
|
|
11
11
|
import json
|
12
12
|
import datetime
|
13
13
|
from meerschaum.utils.typing import SuccessTuple, Any, Union
|
14
|
-
from meerschaum.
|
14
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
15
15
|
from meerschaum.utils.warnings import warn as _warn
|
16
16
|
|
17
17
|
|
@@ -22,14 +22,40 @@ def login(
|
|
22
22
|
**kw: Any
|
23
23
|
) -> SuccessTuple:
|
24
24
|
"""Log in and set the session token."""
|
25
|
+
if self.login_scheme == 'api_key':
|
26
|
+
validate_response = self.post(
|
27
|
+
STATIC_CONFIG['api']['endpoints']['tokens'] + '/validate',
|
28
|
+
headers={'Authorization': f'Bearer {self.api_key}'},
|
29
|
+
use_token=False,
|
30
|
+
debug=debug,
|
31
|
+
)
|
32
|
+
if not validate_response:
|
33
|
+
return False, "API key is not valid."
|
34
|
+
return True, "API key is valid."
|
35
|
+
|
25
36
|
try:
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
37
|
+
if self.login_scheme == 'password':
|
38
|
+
login_data = {
|
39
|
+
'username': self.username,
|
40
|
+
'password': self.password,
|
41
|
+
}
|
42
|
+
elif self.login_scheme == 'client_credentials':
|
43
|
+
login_data = {
|
44
|
+
'client_id': self.client_id,
|
45
|
+
'client_secret': self.client_secret,
|
46
|
+
}
|
30
47
|
except AttributeError:
|
48
|
+
login_data = {}
|
49
|
+
|
50
|
+
if not login_data:
|
31
51
|
return False, f"Please login with the command `login {self}`."
|
32
52
|
|
53
|
+
login_scheme_msg = (
|
54
|
+
f" as user '{login_data['username']}'"
|
55
|
+
if self.login_scheme == 'username'
|
56
|
+
else ''
|
57
|
+
)
|
58
|
+
|
33
59
|
response = self.post(
|
34
60
|
STATIC_CONFIG['api']['endpoints']['login'],
|
35
61
|
data=login_data,
|
@@ -37,7 +63,7 @@ def login(
|
|
37
63
|
debug=debug,
|
38
64
|
)
|
39
65
|
if response:
|
40
|
-
msg = f"Successfully logged into '{self}'
|
66
|
+
msg = f"Successfully logged into '{self}'{login_scheme_msg}'."
|
41
67
|
self._token = json.loads(response.text)['access_token']
|
42
68
|
self._expires = datetime.datetime.strptime(
|
43
69
|
json.loads(response.text)['expires'],
|
@@ -45,7 +71,7 @@ def login(
|
|
45
71
|
)
|
46
72
|
else:
|
47
73
|
msg = (
|
48
|
-
f"Failed to log into '{self}'
|
74
|
+
f"Failed to log into '{self}'{login_scheme_msg}.\n" +
|
49
75
|
f" Please verify login details for connector '{self}'."
|
50
76
|
)
|
51
77
|
if warn and not self.__dict__.get('_emitted_warning', False):
|
@@ -13,7 +13,7 @@ def get_mrsm_version(self, **kw) -> Optional[str]:
|
|
13
13
|
"""
|
14
14
|
Return the Meerschaum version of the API instance.
|
15
15
|
"""
|
16
|
-
from meerschaum.
|
16
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
17
17
|
try:
|
18
18
|
j = self.get(
|
19
19
|
STATIC_CONFIG['api']['endpoints']['version'] + '/mrsm',
|
@@ -31,7 +31,7 @@ def get_chaining_status(self, **kw) -> Optional[bool]:
|
|
31
31
|
"""
|
32
32
|
Fetch the chaining status of the API instance.
|
33
33
|
"""
|
34
|
-
from meerschaum.
|
34
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
35
35
|
try:
|
36
36
|
response = self.get(
|
37
37
|
STATIC_CONFIG['api']['endpoints']['chaining'],
|
@@ -21,7 +21,7 @@ def pipe_r_url(
|
|
21
21
|
pipe: mrsm.Pipe
|
22
22
|
) -> str:
|
23
23
|
"""Return a relative URL path from a Pipe's keys."""
|
24
|
-
from meerschaum.
|
24
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
25
25
|
location_key = pipe.location_key
|
26
26
|
if location_key is None:
|
27
27
|
location_key = '[None]'
|
@@ -87,7 +87,7 @@ def edit_pipe(
|
|
87
87
|
response = self.patch(
|
88
88
|
r_url + '/edit',
|
89
89
|
params={'patch': patch, 'instance_keys': self.get_pipe_instance_keys(pipe)},
|
90
|
-
json=pipe.
|
90
|
+
json=pipe.get_parameters(apply_symlinks=False),
|
91
91
|
debug=debug,
|
92
92
|
)
|
93
93
|
if debug:
|
@@ -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
|
|
@@ -142,7 +148,7 @@ def fetch_pipes_keys(
|
|
142
148
|
-------
|
143
149
|
A list of tuples containing pipes' keys.
|
144
150
|
"""
|
145
|
-
from meerschaum.
|
151
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
146
152
|
if connector_keys is None:
|
147
153
|
connector_keys = []
|
148
154
|
if metric_keys is None:
|
@@ -167,6 +173,8 @@ def fetch_pipes_keys(
|
|
167
173
|
debug=debug
|
168
174
|
).json()
|
169
175
|
except Exception as e:
|
176
|
+
import traceback
|
177
|
+
traceback.print_exc()
|
170
178
|
error(str(e))
|
171
179
|
|
172
180
|
if 'detail' in j:
|
@@ -185,10 +193,11 @@ def sync_pipe(
|
|
185
193
|
"""Sync a DataFrame into a Pipe."""
|
186
194
|
from decimal import Decimal
|
187
195
|
from meerschaum.utils.debug import dprint
|
188
|
-
from meerschaum.utils.
|
196
|
+
from meerschaum.utils.dtypes import json_serialize_value
|
197
|
+
from meerschaum.utils.misc import items_str, interval_str
|
189
198
|
from meerschaum.config import get_config
|
190
199
|
from meerschaum.utils.packages import attempt_import
|
191
|
-
from meerschaum.utils.dataframe import
|
200
|
+
from meerschaum.utils.dataframe import get_special_cols, to_json
|
192
201
|
begin = time.perf_counter()
|
193
202
|
more_itertools = attempt_import('more_itertools')
|
194
203
|
if df is None:
|
@@ -197,8 +206,10 @@ def sync_pipe(
|
|
197
206
|
|
198
207
|
def get_json_str(c):
|
199
208
|
### allow syncing dict or JSON without needing to import pandas (for IOT devices)
|
200
|
-
if isinstance(c,
|
201
|
-
return
|
209
|
+
if isinstance(c, str):
|
210
|
+
return c
|
211
|
+
if isinstance(c, (dict, list, tuple)):
|
212
|
+
return json.dumps(c, default=json_serialize_value)
|
202
213
|
return to_json(c, orient='columns')
|
203
214
|
|
204
215
|
df = json.loads(df) if isinstance(df, str) else df
|
@@ -218,26 +229,6 @@ def sync_pipe(
|
|
218
229
|
else [partition.compute() for partition in df.partitions]
|
219
230
|
)
|
220
231
|
|
221
|
-
numeric_cols = get_numeric_cols(df)
|
222
|
-
if numeric_cols:
|
223
|
-
for col in numeric_cols:
|
224
|
-
df[col] = df[col].apply(lambda x: f'{x:f}' if isinstance(x, Decimal) else x)
|
225
|
-
pipe_dtypes = pipe.dtypes
|
226
|
-
new_numeric_cols = [
|
227
|
-
col
|
228
|
-
for col in numeric_cols
|
229
|
-
if pipe_dtypes.get(col, None) != 'numeric'
|
230
|
-
]
|
231
|
-
pipe.dtypes.update({
|
232
|
-
col: 'numeric'
|
233
|
-
for col in new_numeric_cols
|
234
|
-
})
|
235
|
-
edit_success, edit_msg = pipe.edit(debug=debug)
|
236
|
-
if not edit_success:
|
237
|
-
warn(
|
238
|
-
"Failed to update new numeric columns "
|
239
|
-
+ f"{items_str(new_numeric_cols)}:\n{edit_msg}"
|
240
|
-
)
|
241
232
|
elif isinstance(df, dict):
|
242
233
|
### `_chunks` is a dict of lists of dicts.
|
243
234
|
### e.g. {'a' : [ {'a':[1, 2]}, {'a':[3, 4]} ] }
|
@@ -313,7 +304,7 @@ def sync_pipe(
|
|
313
304
|
|
314
305
|
success_tuple = True, (
|
315
306
|
f"It took {interval_str(timedelta(seconds=(time.perf_counter() - begin)))} "
|
316
|
-
+ "to sync {rowcount:,} row"
|
307
|
+
+ f"to sync {rowcount:,} row"
|
317
308
|
+ ('s' if rowcount != 1 else '')
|
318
309
|
+ f" across {num_success_chunks:,} chunk" + ('s' if num_success_chunks != 1 else '') +
|
319
310
|
f" to {pipe}."
|
@@ -324,7 +315,7 @@ def sync_pipe(
|
|
324
315
|
def delete_pipe(
|
325
316
|
self,
|
326
317
|
pipe: Optional[mrsm.Pipe] = None,
|
327
|
-
debug: bool =
|
318
|
+
debug: bool = False,
|
328
319
|
) -> SuccessTuple:
|
329
320
|
"""Delete a Pipe and drop its table."""
|
330
321
|
if pipe is None:
|
@@ -576,7 +567,7 @@ def create_metadata(
|
|
576
567
|
A bool indicating success.
|
577
568
|
"""
|
578
569
|
from meerschaum.utils.debug import dprint
|
579
|
-
from meerschaum.
|
570
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
580
571
|
r_url = STATIC_CONFIG['api']['endpoints']['metadata']
|
581
572
|
response = self.post(r_url, debug=debug)
|
582
573
|
if debug:
|
@@ -663,7 +654,7 @@ def drop_pipe(
|
|
663
654
|
from meerschaum.utils.warnings import error
|
664
655
|
from meerschaum.utils.debug import dprint
|
665
656
|
if pipe is None:
|
666
|
-
error(
|
657
|
+
error("Pipe cannot be None.")
|
667
658
|
r_url = pipe_r_url(pipe)
|
668
659
|
response = self.delete(
|
669
660
|
r_url + '/drop',
|
@@ -16,7 +16,7 @@ def plugin_r_url(
|
|
16
16
|
plugin: Union[mrsm.core.Plugin, str],
|
17
17
|
) -> str:
|
18
18
|
"""Generate a relative URL path from a Plugin."""
|
19
|
-
from meerschaum.
|
19
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
20
20
|
return f"{STATIC_CONFIG['api']['endpoints']['plugins']}/{plugin}"
|
21
21
|
|
22
22
|
|
@@ -111,7 +111,7 @@ def get_plugins(
|
|
111
111
|
"""
|
112
112
|
import json
|
113
113
|
from meerschaum.utils.warnings import error
|
114
|
-
from meerschaum.
|
114
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
115
115
|
response = self.get(
|
116
116
|
STATIC_CONFIG['api']['endpoints']['plugins'],
|
117
117
|
params = {'user_id': user_id, 'search_term': search_term},
|
@@ -11,7 +11,7 @@ import urllib.parse
|
|
11
11
|
import pathlib
|
12
12
|
from meerschaum.utils.typing import Any, Optional, Dict, Union
|
13
13
|
from meerschaum.utils.debug import dprint
|
14
|
-
from meerschaum.
|
14
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
15
15
|
|
16
16
|
METHODS = {
|
17
17
|
'GET',
|
@@ -0,0 +1,146 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# vim:fenc=utf-8
|
3
|
+
|
4
|
+
"""
|
5
|
+
Implement the `APIConnector` token methods.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import json
|
9
|
+
import uuid
|
10
|
+
from datetime import datetime
|
11
|
+
from typing import Union, List, Optional
|
12
|
+
|
13
|
+
import meerschaum as mrsm
|
14
|
+
from meerschaum.core import Token
|
15
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
16
|
+
tokens_endpoint = STATIC_CONFIG['api']['endpoints']['tokens']
|
17
|
+
|
18
|
+
|
19
|
+
def register_token(self, token: Token, debug: bool = False) -> mrsm.SuccessTuple:
|
20
|
+
"""
|
21
|
+
Register the provided token to the API.
|
22
|
+
"""
|
23
|
+
from meerschaum.utils.dtypes import json_serialize_value
|
24
|
+
r_url = tokens_endpoint + '/register'
|
25
|
+
response = self.post(
|
26
|
+
r_url,
|
27
|
+
data=json.dumps({
|
28
|
+
'label': token.label,
|
29
|
+
'scopes': token.scopes,
|
30
|
+
'expiration': token.expiration,
|
31
|
+
}, default=json_serialize_value),
|
32
|
+
debug=debug,
|
33
|
+
)
|
34
|
+
if not response:
|
35
|
+
return False, f"Failed to register token:\n{response.text}"
|
36
|
+
|
37
|
+
data = response.json()
|
38
|
+
token.label = data['label']
|
39
|
+
token.secret = data['secret']
|
40
|
+
token.id = uuid.UUID(data['id'])
|
41
|
+
if data.get('expiration', None):
|
42
|
+
token.expiration = datetime.fromisoformat(data['expiration'])
|
43
|
+
|
44
|
+
return True, f"Registered token '{token.label}'."
|
45
|
+
|
46
|
+
|
47
|
+
def get_token_model(self, token_id: uuid.UUID, debug: bool = False) -> 'Union[TokenModel, None]':
|
48
|
+
"""
|
49
|
+
Return a token's model from the API instance.
|
50
|
+
"""
|
51
|
+
from meerschaum.models import TokenModel
|
52
|
+
r_url = tokens_endpoint + f'/{token_id}'
|
53
|
+
response = self.get(r_url, debug=debug)
|
54
|
+
if not response:
|
55
|
+
return None
|
56
|
+
data = response.json()
|
57
|
+
return TokenModel(**data)
|
58
|
+
|
59
|
+
|
60
|
+
def get_tokens(self, labels: Optional[List[str]] = None, debug: bool = False) -> List[Token]:
|
61
|
+
"""
|
62
|
+
Return the tokens registered to the current user.
|
63
|
+
"""
|
64
|
+
from meerschaum.utils.warnings import warn
|
65
|
+
r_url = tokens_endpoint
|
66
|
+
params = {}
|
67
|
+
if labels:
|
68
|
+
params['labels'] = ','.join(labels)
|
69
|
+
response = self.get(r_url, params={'labels': labels}, debug=debug)
|
70
|
+
if not response:
|
71
|
+
warn(f"Could not get tokens from '{self}':\n{response.text}")
|
72
|
+
return []
|
73
|
+
|
74
|
+
tokens = [
|
75
|
+
Token(instance=self, **payload)
|
76
|
+
for payload in response.json()
|
77
|
+
]
|
78
|
+
return tokens
|
79
|
+
|
80
|
+
|
81
|
+
def edit_token(self, token: Token, debug: bool = False) -> mrsm.SuccessTuple:
|
82
|
+
"""
|
83
|
+
Persist the token's in-memory state to the API.
|
84
|
+
"""
|
85
|
+
r_url = tokens_endpoint + f"/{token.id}/edit"
|
86
|
+
response = self.post(
|
87
|
+
r_url,
|
88
|
+
json={
|
89
|
+
'creation': token.creation.isoformat() if token.creation else None,
|
90
|
+
'expiration': token.expiration.isoformat() if token.expiration else None,
|
91
|
+
'label': token.label,
|
92
|
+
'is_valid': token.is_valid,
|
93
|
+
'scopes': token.scopes,
|
94
|
+
},
|
95
|
+
)
|
96
|
+
if not response:
|
97
|
+
return False, f"Failed to edit token:\n{response.text}"
|
98
|
+
|
99
|
+
success, msg = response.json()
|
100
|
+
return success, msg
|
101
|
+
|
102
|
+
|
103
|
+
def invalidate_token(self, token: Token, debug: bool = False) -> mrsm.SuccessTuple:
|
104
|
+
"""
|
105
|
+
Invalidate the token, disabling it for future requests.
|
106
|
+
"""
|
107
|
+
r_url = tokens_endpoint + f"/{token.id}/invalidate"
|
108
|
+
response = self.post(r_url)
|
109
|
+
if not response:
|
110
|
+
return False, f"Failed to invalidate token:\n{response.text}"
|
111
|
+
|
112
|
+
success, msg = response.json()
|
113
|
+
return success, msg
|
114
|
+
|
115
|
+
|
116
|
+
def get_token_scopes(self, token_id: Union[uuid.UUID, Token], debug: bool = False) -> List[str]:
|
117
|
+
"""
|
118
|
+
Return the scopes for a token.
|
119
|
+
"""
|
120
|
+
_token_id = (token_id.id if isinstance(token_id, Token) else token_id)
|
121
|
+
model = self.get_token_model(_token_id, debug=debug).scopes
|
122
|
+
return getattr(model, 'scopes', [])
|
123
|
+
|
124
|
+
|
125
|
+
def token_exists(self, token_id: Union[uuid.UUID, Token], debug: bool = False) -> bool:
|
126
|
+
"""
|
127
|
+
Return `True` if a token exists.
|
128
|
+
"""
|
129
|
+
_token_id = (token_id.id if isinstance(token_id, Token) else token_id)
|
130
|
+
model = self.get_token_model(_token_id, debug=debug)
|
131
|
+
if model is None:
|
132
|
+
return False
|
133
|
+
return model.creation is not None
|
134
|
+
|
135
|
+
|
136
|
+
def delete_token(self, token: Token, debug: bool = False) -> mrsm.SuccessTuple:
|
137
|
+
"""
|
138
|
+
Delete the token from the API.
|
139
|
+
"""
|
140
|
+
r_url = tokens_endpoint + f"/{token.id}"
|
141
|
+
response = self.delete(r_url, debug=debug)
|
142
|
+
if not response:
|
143
|
+
return False, f"Failed to delete token:\n{response.text}"
|
144
|
+
|
145
|
+
success, msg = response.json()
|
146
|
+
return success, msg
|
@@ -7,18 +7,23 @@ Manage users via the API Connector.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
-
|
10
|
+
|
11
|
+
import json
|
12
|
+
from uuid import UUID
|
13
|
+
|
14
|
+
import meerschaum as mrsm
|
15
|
+
from meerschaum.utils.typing import Optional, Any, List, SuccessTuple, Union
|
16
|
+
|
11
17
|
|
12
18
|
def get_users(
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
19
|
+
self,
|
20
|
+
debug: bool = False,
|
21
|
+
**kw: Any
|
22
|
+
) -> List[str]:
|
17
23
|
"""
|
18
24
|
Return a list of registered usernames.
|
19
25
|
"""
|
20
|
-
from meerschaum.
|
21
|
-
import json
|
26
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
22
27
|
response = self.get(
|
23
28
|
f"{STATIC_CONFIG['api']['endpoints']['users']}",
|
24
29
|
debug = debug,
|
@@ -31,15 +36,15 @@ def get_users(
|
|
31
36
|
except Exception as e:
|
32
37
|
return []
|
33
38
|
|
39
|
+
|
34
40
|
def edit_user(
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
41
|
+
self,
|
42
|
+
user: mrsm.core.User,
|
43
|
+
debug: bool = False,
|
44
|
+
**kw: Any
|
45
|
+
) -> SuccessTuple:
|
40
46
|
"""Edit an existing user."""
|
41
|
-
import
|
42
|
-
from meerschaum.config.static import STATIC_CONFIG
|
47
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
43
48
|
r_url = f"{STATIC_CONFIG['api']['endpoints']['users']}/edit"
|
44
49
|
data = {
|
45
50
|
'username': user.username,
|
@@ -54,7 +59,7 @@ def edit_user(
|
|
54
59
|
if isinstance(_json, dict) and 'detail' in _json:
|
55
60
|
return False, _json['detail']
|
56
61
|
success_tuple = tuple(_json)
|
57
|
-
except Exception
|
62
|
+
except Exception:
|
58
63
|
msg = response.text if response else f"Failed to edit user '{user}'."
|
59
64
|
return False, msg
|
60
65
|
|
@@ -62,14 +67,13 @@ def edit_user(
|
|
62
67
|
|
63
68
|
|
64
69
|
def register_user(
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
+
self,
|
71
|
+
user: mrsm.core.User,
|
72
|
+
debug: bool = False,
|
73
|
+
**kw: Any
|
74
|
+
) -> SuccessTuple:
|
70
75
|
"""Register a new user."""
|
71
|
-
import
|
72
|
-
from meerschaum.config.static import STATIC_CONFIG
|
76
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
73
77
|
r_url = f"{STATIC_CONFIG['api']['endpoints']['users']}/register"
|
74
78
|
data = {
|
75
79
|
'username': user.username,
|
@@ -94,31 +98,37 @@ def register_user(
|
|
94
98
|
|
95
99
|
|
96
100
|
def get_user_id(
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
101
|
+
self,
|
102
|
+
user: mrsm.core.User,
|
103
|
+
debug: bool = False,
|
104
|
+
**kw: Any
|
105
|
+
) -> Union[int, str, UUID, None]:
|
102
106
|
"""Get a user's ID."""
|
103
|
-
from meerschaum.
|
104
|
-
import
|
107
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
108
|
+
from meerschaum.utils.misc import is_int, is_uuid
|
105
109
|
r_url = f"{STATIC_CONFIG['api']['endpoints']['users']}/{user.username}/id"
|
106
110
|
response = self.get(r_url, debug=debug, **kw)
|
107
111
|
try:
|
108
|
-
|
112
|
+
id_text = str(json.loads(response.text))
|
113
|
+
if is_int(id_text):
|
114
|
+
user_id = int(id_text)
|
115
|
+
elif is_uuid(id_text):
|
116
|
+
user_id = UUID(id_text)
|
117
|
+
else:
|
118
|
+
user_id = id_text
|
109
119
|
except Exception as e:
|
110
120
|
user_id = None
|
111
121
|
return user_id
|
112
122
|
|
123
|
+
|
113
124
|
def delete_user(
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
125
|
+
self,
|
126
|
+
user: mrsm.core.User,
|
127
|
+
debug: bool = False,
|
128
|
+
**kw: Any
|
129
|
+
) -> SuccessTuple:
|
119
130
|
"""Delete a user."""
|
120
|
-
from meerschaum.
|
121
|
-
import json
|
131
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
122
132
|
r_url = f"{STATIC_CONFIG['api']['endpoints']['users']}/{user.username}"
|
123
133
|
response = self.delete(r_url, debug=debug)
|
124
134
|
try:
|
@@ -126,53 +136,55 @@ def delete_user(
|
|
126
136
|
if isinstance(_json, dict) and 'detail' in _json:
|
127
137
|
return False, _json['detail']
|
128
138
|
success_tuple = tuple(_json)
|
129
|
-
except Exception
|
139
|
+
except Exception:
|
130
140
|
success_tuple = False, f"Failed to delete user '{user.username}'."
|
131
141
|
return success_tuple
|
132
142
|
|
143
|
+
|
133
144
|
def get_user_attributes(
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
145
|
+
self,
|
146
|
+
user: mrsm.core.User,
|
147
|
+
debug: bool = False,
|
148
|
+
**kw
|
149
|
+
) -> int:
|
139
150
|
"""Get a user's attributes."""
|
140
|
-
from meerschaum.
|
141
|
-
import json
|
151
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
142
152
|
r_url = f"{STATIC_CONFIG['api']['endpoints']['users']}/{user.username}/attributes"
|
143
153
|
response = self.get(r_url, debug=debug, **kw)
|
144
154
|
try:
|
145
155
|
attributes = json.loads(response.text)
|
146
|
-
except Exception
|
156
|
+
except Exception:
|
147
157
|
attributes = None
|
148
158
|
return attributes
|
149
159
|
|
160
|
+
|
150
161
|
#############################
|
151
162
|
# Chaining functions below. #
|
152
163
|
#############################
|
153
164
|
|
154
165
|
def get_user_password_hash(
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
166
|
+
self,
|
167
|
+
user: mrsm.core.User,
|
168
|
+
debug: bool = False,
|
169
|
+
**kw: Any
|
170
|
+
) -> Optional[str]:
|
160
171
|
"""If configured, get a user's password hash."""
|
161
|
-
from meerschaum.
|
172
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
162
173
|
r_url = STATIC_CONFIG['api']['endpoints']['users'] + '/' + user.username + '/password_hash'
|
163
174
|
response = self.get(r_url, debug=debug, **kw)
|
164
175
|
if not response:
|
165
176
|
return None
|
166
177
|
return response.json()
|
167
178
|
|
179
|
+
|
168
180
|
def get_user_type(
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
181
|
+
self,
|
182
|
+
user: mrsm.core.User,
|
183
|
+
debug: bool = False,
|
184
|
+
**kw: Any
|
185
|
+
) -> Optional[str]:
|
174
186
|
"""If configured, get a user's type."""
|
175
|
-
from meerschaum.
|
187
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
176
188
|
r_url = STATIC_CONFIG['api']['endpoints']['users'] + '/' + user.username + '/type'
|
177
189
|
response = self.get(r_url, debug=debug, **kw)
|
178
190
|
if not response:
|