meerschaum 2.3.6__py3-none-any.whl → 2.4.0.dev0__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/actions/bootstrap.py +36 -10
- meerschaum/actions/start.py +13 -14
- meerschaum/api/dash/__init__.py +7 -6
- meerschaum/api/dash/callbacks/__init__.py +1 -0
- meerschaum/api/dash/callbacks/dashboard.py +7 -5
- meerschaum/api/dash/callbacks/pipes.py +42 -0
- meerschaum/api/dash/pages/__init__.py +1 -0
- meerschaum/api/dash/pages/pipes.py +16 -0
- meerschaum/api/dash/pipes.py +79 -47
- meerschaum/api/dash/users.py +19 -6
- meerschaum/api/routes/_login.py +4 -4
- meerschaum/api/routes/_pipes.py +3 -3
- meerschaum/config/_default.py +9 -1
- meerschaum/config/_version.py +1 -1
- meerschaum/config/stack/__init__.py +59 -16
- meerschaum/connectors/Connector.py +19 -13
- meerschaum/connectors/__init__.py +9 -5
- meerschaum/connectors/poll.py +30 -24
- meerschaum/connectors/sql/_pipes.py +126 -154
- meerschaum/connectors/sql/_plugins.py +45 -43
- meerschaum/connectors/sql/_users.py +46 -38
- meerschaum/connectors/valkey/ValkeyConnector.py +535 -0
- meerschaum/connectors/valkey/__init__.py +8 -0
- meerschaum/connectors/valkey/_fetch.py +75 -0
- meerschaum/connectors/valkey/_pipes.py +839 -0
- meerschaum/connectors/valkey/_plugins.py +265 -0
- meerschaum/connectors/valkey/_users.py +305 -0
- meerschaum/core/Pipe/__init__.py +2 -0
- meerschaum/core/Pipe/_attributes.py +1 -2
- meerschaum/core/Pipe/_drop.py +4 -4
- meerschaum/core/Pipe/_dtypes.py +14 -14
- meerschaum/core/Pipe/_edit.py +15 -14
- meerschaum/core/Pipe/_sync.py +134 -51
- meerschaum/core/User/_User.py +14 -12
- meerschaum/plugins/_Plugin.py +17 -13
- meerschaum/utils/_get_pipes.py +14 -20
- meerschaum/utils/dataframe.py +288 -101
- meerschaum/utils/dtypes/__init__.py +31 -6
- meerschaum/utils/dtypes/sql.py +4 -4
- meerschaum/utils/misc.py +3 -3
- meerschaum/utils/packages/_packages.py +1 -0
- {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev0.dist-info}/METADATA +3 -1
- {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev0.dist-info}/RECORD +49 -41
- {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev0.dist-info}/WHEEL +1 -1
- {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev0.dist-info}/LICENSE +0 -0
- {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev0.dist-info}/NOTICE +0 -0
- {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev0.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev0.dist-info}/top_level.txt +0 -0
- {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev0.dist-info}/zip-safe +0 -0
@@ -0,0 +1,265 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# vim:fenc=utf-8
|
3
|
+
|
4
|
+
"""
|
5
|
+
Define methods for registering plugins.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from __future__ import annotations
|
9
|
+
|
10
|
+
import json
|
11
|
+
|
12
|
+
import meerschaum as mrsm
|
13
|
+
from meerschaum.utils.typing import Optional, Any, List, SuccessTuple, Dict, Union
|
14
|
+
|
15
|
+
PLUGINS_TABLE: str = "mrsm_plugins"
|
16
|
+
PLUGIN_PREFIX: str = "mrsm_plugin"
|
17
|
+
|
18
|
+
|
19
|
+
def get_plugins_pipe(self) -> mrsm.Pipe:
|
20
|
+
"""
|
21
|
+
Return the pipe to store the plugins.
|
22
|
+
"""
|
23
|
+
return mrsm.Pipe(
|
24
|
+
'mrsm', 'plugins',
|
25
|
+
columns=['plugin_name'],
|
26
|
+
temporary=True,
|
27
|
+
target=PLUGINS_TABLE,
|
28
|
+
instance=self,
|
29
|
+
)
|
30
|
+
|
31
|
+
|
32
|
+
@classmethod
|
33
|
+
def get_plugin_key(cls, plugin_name: str, sub_key: str) -> str:
|
34
|
+
"""
|
35
|
+
Return the key for a plugin's attribute.
|
36
|
+
"""
|
37
|
+
return cls.get_entity_key(PLUGIN_PREFIX, plugin_name, sub_key)
|
38
|
+
|
39
|
+
|
40
|
+
@classmethod
|
41
|
+
def get_plugin_keys_vals(
|
42
|
+
cls,
|
43
|
+
plugin: 'mrsm.core.Plugin',
|
44
|
+
mutable_only: bool = False,
|
45
|
+
) -> Dict[str, str]:
|
46
|
+
"""
|
47
|
+
Return a dictionary containing keys and values to set for the plugin.
|
48
|
+
|
49
|
+
Parameters
|
50
|
+
----------
|
51
|
+
plugin: mrsm.core.Plugin
|
52
|
+
The plugin for which to generate the keys.
|
53
|
+
|
54
|
+
mutable_only: bool, default False
|
55
|
+
If `True`, only return keys which may be edited.
|
56
|
+
|
57
|
+
Returns
|
58
|
+
-------
|
59
|
+
A dictionary mapping a plugins's keys to values.
|
60
|
+
"""
|
61
|
+
plugin_attributes_str = json.dumps(plugin.attributes, separators=(',', ':'))
|
62
|
+
mutable_keys_vals = {
|
63
|
+
cls.get_plugin_key(plugin.name, 'attributes'): plugin_attributes_str,
|
64
|
+
cls.get_plugin_key(plugin.name, 'version'): plugin.version,
|
65
|
+
}
|
66
|
+
if mutable_only:
|
67
|
+
return mutable_keys_vals
|
68
|
+
|
69
|
+
immutable_keys_vals = {
|
70
|
+
cls.get_plugin_key(plugin.name, 'user_id'): plugin.user_id,
|
71
|
+
}
|
72
|
+
|
73
|
+
return {**immutable_keys_vals, **mutable_keys_vals}
|
74
|
+
|
75
|
+
|
76
|
+
def register_plugin(
|
77
|
+
self,
|
78
|
+
plugin: 'mrsm.core.Plugin',
|
79
|
+
force: bool = False,
|
80
|
+
debug: bool = False,
|
81
|
+
**kw: Any
|
82
|
+
) -> SuccessTuple:
|
83
|
+
"""Register a new plugin to the `mrsm_plugins` "table"."""
|
84
|
+
from meerschaum.utils.misc import generate_password
|
85
|
+
|
86
|
+
plugins_pipe = self.get_plugins_pipe()
|
87
|
+
keys_vals = self.get_plugin_keys_vals(plugin)
|
88
|
+
|
89
|
+
try:
|
90
|
+
sync_success, sync_msg = plugins_pipe.sync(
|
91
|
+
[
|
92
|
+
{
|
93
|
+
'plugin_name': plugin.name,
|
94
|
+
'user_id': plugin.user_id,
|
95
|
+
},
|
96
|
+
],
|
97
|
+
check_existing=False,
|
98
|
+
debug=debug,
|
99
|
+
)
|
100
|
+
if not sync_success:
|
101
|
+
return sync_success, sync_msg
|
102
|
+
|
103
|
+
for key, val in keys_vals.items():
|
104
|
+
if val is not None:
|
105
|
+
self.set(key, val)
|
106
|
+
|
107
|
+
success, msg = True, "Success"
|
108
|
+
except Exception as e:
|
109
|
+
success = False
|
110
|
+
msg = f"Failed to register plugin '{plugin.name}':\n{e}"
|
111
|
+
|
112
|
+
if not success:
|
113
|
+
for key in keys_vals:
|
114
|
+
try:
|
115
|
+
self.client.delete(key)
|
116
|
+
except Exception:
|
117
|
+
pass
|
118
|
+
|
119
|
+
return success, msg
|
120
|
+
|
121
|
+
|
122
|
+
def get_plugin_id(
|
123
|
+
self,
|
124
|
+
plugin: 'mrsm.core.Plugin',
|
125
|
+
debug: bool = False
|
126
|
+
) -> Union[str, None]:
|
127
|
+
"""
|
128
|
+
Return a plugin's ID.
|
129
|
+
"""
|
130
|
+
return plugin.name
|
131
|
+
|
132
|
+
|
133
|
+
def get_plugin_version(
|
134
|
+
self,
|
135
|
+
plugin: 'mrsm.core.Plugin',
|
136
|
+
debug: bool = False,
|
137
|
+
) -> Union[str, None]:
|
138
|
+
"""
|
139
|
+
Return a plugin's version.
|
140
|
+
"""
|
141
|
+
version_key = self.get_plugin_key(plugin.name, 'version')
|
142
|
+
|
143
|
+
try:
|
144
|
+
return self.get(version_key)
|
145
|
+
except Exception:
|
146
|
+
return None
|
147
|
+
|
148
|
+
|
149
|
+
def get_plugin_user_id(
|
150
|
+
self,
|
151
|
+
plugin: 'mrsm.core.Plugin',
|
152
|
+
debug: bool = False
|
153
|
+
) -> Union[str, None]:
|
154
|
+
"""
|
155
|
+
Return a plugin's user ID.
|
156
|
+
"""
|
157
|
+
user_id_key = self.get_plugin_key(plugin.name, 'user_id')
|
158
|
+
|
159
|
+
try:
|
160
|
+
return self.get(user_id_key)
|
161
|
+
except Exception:
|
162
|
+
return None
|
163
|
+
|
164
|
+
|
165
|
+
def get_plugin_username(
|
166
|
+
self,
|
167
|
+
plugin: 'mrsm.core.Plugin',
|
168
|
+
debug: bool = False
|
169
|
+
) -> Union[str]:
|
170
|
+
"""
|
171
|
+
Return the username of a plugin's owner.
|
172
|
+
"""
|
173
|
+
user_id = self.get_plugin_user_id(plugin, debug=debug)
|
174
|
+
if user_id is None:
|
175
|
+
return None
|
176
|
+
|
177
|
+
username_key = self.get_user_key(user_id, 'username')
|
178
|
+
try:
|
179
|
+
return self.get(username_key)
|
180
|
+
except Exception:
|
181
|
+
return None
|
182
|
+
|
183
|
+
|
184
|
+
def get_plugin_attributes(
|
185
|
+
self,
|
186
|
+
plugin: 'mrsm.core.Plugin',
|
187
|
+
debug: bool = False
|
188
|
+
) -> Dict[str, Any]:
|
189
|
+
"""
|
190
|
+
Return the attributes of a plugin.
|
191
|
+
"""
|
192
|
+
attributes_key = self.get_plugin_key(plugin.name, 'attributes')
|
193
|
+
try:
|
194
|
+
attributes_str = self.get(attributes_key)
|
195
|
+
if not attributes_str:
|
196
|
+
return {}
|
197
|
+
return json.loads(attributes_str)
|
198
|
+
except Exception:
|
199
|
+
return {}
|
200
|
+
|
201
|
+
|
202
|
+
def get_plugins(
|
203
|
+
self,
|
204
|
+
user_id: Optional[int] = None,
|
205
|
+
search_term: Optional[str] = None,
|
206
|
+
debug: bool = False,
|
207
|
+
**kw: Any
|
208
|
+
) -> List[str]:
|
209
|
+
"""
|
210
|
+
Return a list of plugin names.
|
211
|
+
"""
|
212
|
+
plugins_pipe = self.get_plugins_pipe()
|
213
|
+
params = {}
|
214
|
+
if user_id:
|
215
|
+
params['user_id'] = user_id
|
216
|
+
|
217
|
+
df = plugins_pipe.get_data(['plugin_name'], params=params, debug=debug)
|
218
|
+
docs = df.to_dict(orient='records')
|
219
|
+
|
220
|
+
return [
|
221
|
+
doc['plugin_name']
|
222
|
+
for doc in docs
|
223
|
+
if (plugin_name := doc['plugin_name']).startswith(search_term or '')
|
224
|
+
]
|
225
|
+
|
226
|
+
|
227
|
+
def delete_plugin(
|
228
|
+
self,
|
229
|
+
plugin: 'mrsm.core.Plugin',
|
230
|
+
debug: bool = False,
|
231
|
+
**kw: Any
|
232
|
+
) -> SuccessTuple:
|
233
|
+
"""
|
234
|
+
Delete a plugin from the plugins table.
|
235
|
+
"""
|
236
|
+
plugins_pipe = self.get_plugins_pipe()
|
237
|
+
clear_success, clear_msg = plugins_pipe.clear(params={'plugin_name': plugin.name}, debug=debug)
|
238
|
+
if not clear_success:
|
239
|
+
return clear_success, clear_msg
|
240
|
+
|
241
|
+
keys_vals = self.get_plugin_keys_vals(plugin)
|
242
|
+
try:
|
243
|
+
old_keys_vals = {
|
244
|
+
key: self.get(key)
|
245
|
+
for key in keys_vals
|
246
|
+
}
|
247
|
+
except Exception as e:
|
248
|
+
return False, f"Failed to delete plugin '{plugin.name}':\n{e}"
|
249
|
+
|
250
|
+
try:
|
251
|
+
for key in keys_vals:
|
252
|
+
self.client.delete(key)
|
253
|
+
success, msg = True, "Success"
|
254
|
+
except Exception as e:
|
255
|
+
success = False
|
256
|
+
msg = f"Failed to delete plugin '{plugin.name}':\n{e}"
|
257
|
+
|
258
|
+
if not success:
|
259
|
+
try:
|
260
|
+
for key, old_val in old_keys_vals.items():
|
261
|
+
self.set(key, old_val)
|
262
|
+
except Exception:
|
263
|
+
pass
|
264
|
+
|
265
|
+
return success, msg
|
@@ -0,0 +1,305 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# vim:fenc=utf-8
|
3
|
+
|
4
|
+
"""
|
5
|
+
Define methods for managing users.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from __future__ import annotations
|
9
|
+
|
10
|
+
import json
|
11
|
+
|
12
|
+
import meerschaum as mrsm
|
13
|
+
from meerschaum.utils.typing import Any, Union, SuccessTuple, Dict, List
|
14
|
+
|
15
|
+
USERS_TABLE: str = 'mrsm_users'
|
16
|
+
USER_PREFIX: str = 'mrsm_user'
|
17
|
+
|
18
|
+
|
19
|
+
def get_users_pipe(self):
|
20
|
+
"""
|
21
|
+
Return the pipe which stores the registered users.
|
22
|
+
"""
|
23
|
+
return mrsm.Pipe(
|
24
|
+
'mrsm', 'users',
|
25
|
+
columns=['user_id'],
|
26
|
+
temporary=True,
|
27
|
+
target=USERS_TABLE,
|
28
|
+
instance=self,
|
29
|
+
)
|
30
|
+
|
31
|
+
|
32
|
+
@classmethod
|
33
|
+
def get_user_key(cls, user_id_or_username: str, sub_key: str, by_username: bool = False) -> str:
|
34
|
+
"""
|
35
|
+
Return the key to store metadata about a user.
|
36
|
+
|
37
|
+
Parameters
|
38
|
+
----------
|
39
|
+
user_id_or_username: str
|
40
|
+
The user ID or username of the given user.
|
41
|
+
If `by_username` is `True`, then provide the username.
|
42
|
+
|
43
|
+
sub_key: str
|
44
|
+
The key suffix, e.g. `'attributes'`.
|
45
|
+
|
46
|
+
by_username: bool, default False
|
47
|
+
If `True`, then treat `user_id_or_username` as a username.
|
48
|
+
|
49
|
+
Returns
|
50
|
+
-------
|
51
|
+
A key to store information about a user.
|
52
|
+
|
53
|
+
Examples
|
54
|
+
--------
|
55
|
+
>>> get_user_key('deadbeef', 'attributes')
|
56
|
+
'mrsm_user:user_id:deadbeef:attributes'
|
57
|
+
>>> get_user_key('foo', 'user_id', by_username=True)
|
58
|
+
'mrsm_user:username:foo:user_id'
|
59
|
+
"""
|
60
|
+
key_type = 'user_id' if not by_username else 'username'
|
61
|
+
return cls.get_entity_key(USER_PREFIX, key_type, user_id_or_username, sub_key)
|
62
|
+
|
63
|
+
|
64
|
+
@classmethod
|
65
|
+
def get_user_keys_vals(
|
66
|
+
cls,
|
67
|
+
user: 'mrsm.core.User',
|
68
|
+
mutable_only: bool = False,
|
69
|
+
) -> Dict[str, str]:
|
70
|
+
"""
|
71
|
+
Return a dictionary containing keys and values to set for the user.
|
72
|
+
|
73
|
+
Parameters
|
74
|
+
----------
|
75
|
+
user: mrsm.core.User
|
76
|
+
The user for which to generate the keys.
|
77
|
+
|
78
|
+
mutable_only: bool, default False
|
79
|
+
If `True`, only return keys which may be edited.
|
80
|
+
|
81
|
+
Returns
|
82
|
+
-------
|
83
|
+
A dictionary mapping a user's keys to values.
|
84
|
+
"""
|
85
|
+
user_attributes_str = json.dumps(user.attributes, separators=(',', ':'))
|
86
|
+
mutable_keys_vals = {
|
87
|
+
cls.get_user_key(user.user_id, 'attributes'): user_attributes_str,
|
88
|
+
cls.get_user_key(user.user_id, 'email'): user.email,
|
89
|
+
cls.get_user_key(user.user_id, 'type'): user.type,
|
90
|
+
cls.get_user_key(user.user_id, 'password_hash'): user.password_hash,
|
91
|
+
}
|
92
|
+
if mutable_only:
|
93
|
+
return mutable_keys_vals
|
94
|
+
|
95
|
+
immutable_keys_vals = {
|
96
|
+
cls.get_user_key(user.user_id, 'username'): user.username,
|
97
|
+
cls.get_user_key(user.username, 'user_id', by_username=True): user.user_id,
|
98
|
+
}
|
99
|
+
|
100
|
+
return {**immutable_keys_vals, **mutable_keys_vals}
|
101
|
+
|
102
|
+
|
103
|
+
def register_user(
|
104
|
+
self,
|
105
|
+
user: 'mrsm.core.User',
|
106
|
+
debug: bool = False,
|
107
|
+
**kwargs: Any
|
108
|
+
) -> SuccessTuple:
|
109
|
+
"""
|
110
|
+
Register a new user.
|
111
|
+
"""
|
112
|
+
from meerschaum.utils.misc import generate_password
|
113
|
+
|
114
|
+
user.user_id = generate_password(12)
|
115
|
+
users_pipe = self.get_users_pipe()
|
116
|
+
keys_vals = self.get_user_keys_vals(user)
|
117
|
+
|
118
|
+
try:
|
119
|
+
sync_success, sync_msg = users_pipe.sync(
|
120
|
+
[
|
121
|
+
{
|
122
|
+
'user_id': user.user_id,
|
123
|
+
'username': user.username,
|
124
|
+
},
|
125
|
+
],
|
126
|
+
check_existing=False,
|
127
|
+
debug=debug,
|
128
|
+
)
|
129
|
+
if not sync_success:
|
130
|
+
return sync_success, sync_msg
|
131
|
+
|
132
|
+
for key, val in keys_vals.items():
|
133
|
+
if val is not None:
|
134
|
+
self.set(key, val)
|
135
|
+
|
136
|
+
success, msg = True, "Success"
|
137
|
+
except Exception as e:
|
138
|
+
success = False
|
139
|
+
import traceback
|
140
|
+
traceback.print_exc()
|
141
|
+
msg = f"Failed to register '{user.username}':\n{e}"
|
142
|
+
|
143
|
+
if not success:
|
144
|
+
for key in keys_vals:
|
145
|
+
try:
|
146
|
+
self.client.delete(key)
|
147
|
+
except Exception:
|
148
|
+
pass
|
149
|
+
|
150
|
+
return success, msg
|
151
|
+
|
152
|
+
|
153
|
+
def get_user_id(self, user: 'mrsm.core.User', debug: bool = False) -> Union[str, None]:
|
154
|
+
"""
|
155
|
+
Return the ID for a user, or `None`.
|
156
|
+
"""
|
157
|
+
username_user_id_key = self.get_user_key(user.username, 'user_id', by_username=True)
|
158
|
+
try:
|
159
|
+
user_id = self.get(username_user_id_key)
|
160
|
+
except Exception:
|
161
|
+
user_id = None
|
162
|
+
return user_id
|
163
|
+
|
164
|
+
|
165
|
+
def edit_user(
|
166
|
+
self,
|
167
|
+
user: 'mrsm.core.User',
|
168
|
+
debug: bool = False,
|
169
|
+
**kw: Any
|
170
|
+
) -> SuccessTuple:
|
171
|
+
"""
|
172
|
+
Edit the attributes for an existing user.
|
173
|
+
"""
|
174
|
+
keys_vals = self.get_user_keys_vals(user, mutable_only=True)
|
175
|
+
try:
|
176
|
+
old_keys_vals = {
|
177
|
+
key: self.get(key)
|
178
|
+
for key in keys_vals
|
179
|
+
}
|
180
|
+
except Exception as e:
|
181
|
+
return False, f"Failed to edit user:\n{e}"
|
182
|
+
|
183
|
+
try:
|
184
|
+
for key, val in keys_vals.items():
|
185
|
+
self.set(key, val)
|
186
|
+
success, msg = True, "Success"
|
187
|
+
except Exception as e:
|
188
|
+
success = False
|
189
|
+
msg = f"Failed to edit user:\n{e}"
|
190
|
+
|
191
|
+
if not success:
|
192
|
+
try:
|
193
|
+
for key, old_val in old_keys_vals.items():
|
194
|
+
self.set(key, old_val)
|
195
|
+
except Exception:
|
196
|
+
pass
|
197
|
+
|
198
|
+
return success, msg
|
199
|
+
|
200
|
+
|
201
|
+
def get_user_attributes(
|
202
|
+
self,
|
203
|
+
user: 'mrsm.core.User',
|
204
|
+
debug: bool = False
|
205
|
+
) -> Union[Dict[str, Any], None]:
|
206
|
+
"""
|
207
|
+
Return the user's attributes.
|
208
|
+
"""
|
209
|
+
user_id = user.user_id if user.user_id is not None else self.get_user_id(user, debug=debug)
|
210
|
+
user_id_attributes_key = self.get_user_key(user_id, 'attributes')
|
211
|
+
try:
|
212
|
+
return json.loads(self.get(user_id_attributes_key))
|
213
|
+
except Exception:
|
214
|
+
return None
|
215
|
+
|
216
|
+
|
217
|
+
def delete_user(
|
218
|
+
self,
|
219
|
+
user: 'mrsm.core.User',
|
220
|
+
debug: bool = False
|
221
|
+
) -> SuccessTuple:
|
222
|
+
"""
|
223
|
+
Delete a user's keys.
|
224
|
+
"""
|
225
|
+
user_id = user.user_id if user.user_id is not None else self.get_user_id(user, debug=debug)
|
226
|
+
users_pipe = self.get_users_pipe()
|
227
|
+
keys_vals = self.get_user_keys_vals(user)
|
228
|
+
try:
|
229
|
+
old_keys_vals = {
|
230
|
+
key: self.get(key)
|
231
|
+
for key in keys_vals
|
232
|
+
}
|
233
|
+
except Exception as e:
|
234
|
+
return False, f"Failed to delete user:\n{e}"
|
235
|
+
|
236
|
+
clear_success, clear_msg = users_pipe.clear(params={'user_id': user_id})
|
237
|
+
if not clear_success:
|
238
|
+
return clear_success, clear_msg
|
239
|
+
|
240
|
+
try:
|
241
|
+
for key in keys_vals:
|
242
|
+
self.client.delete(key)
|
243
|
+
success, msg = True, "Success"
|
244
|
+
except Exception as e:
|
245
|
+
success = False
|
246
|
+
msg = f"Failed to delete user:\n{e}"
|
247
|
+
|
248
|
+
if not success:
|
249
|
+
try:
|
250
|
+
for key, old_val in old_keys_vals.items():
|
251
|
+
self.set(key, old_val)
|
252
|
+
except Exception:
|
253
|
+
pass
|
254
|
+
|
255
|
+
return success, msg
|
256
|
+
|
257
|
+
|
258
|
+
def get_users(
|
259
|
+
self,
|
260
|
+
debug: bool = False,
|
261
|
+
**kw: Any
|
262
|
+
) -> List[str]:
|
263
|
+
"""
|
264
|
+
Get the registered usernames.
|
265
|
+
"""
|
266
|
+
users_pipe = self.get_users_pipe()
|
267
|
+
df = users_pipe.get_data()
|
268
|
+
if df is None:
|
269
|
+
return []
|
270
|
+
|
271
|
+
return list(df['username'])
|
272
|
+
|
273
|
+
|
274
|
+
def get_user_password_hash(
|
275
|
+
self,
|
276
|
+
user: 'mrsm.core.User',
|
277
|
+
debug: bool = False,
|
278
|
+
**kw: Any
|
279
|
+
) -> Union[str, None]:
|
280
|
+
"""
|
281
|
+
Return the password has for a user.
|
282
|
+
"""
|
283
|
+
user_id = user.user_id if user.user_id is not None else self.get_user_id(user, debug=debug)
|
284
|
+
user_id_password_hash_key = self.get_user_key(user_id, 'password_hash')
|
285
|
+
try:
|
286
|
+
return self.get(user_id_password_hash_key)
|
287
|
+
except Exception:
|
288
|
+
return None
|
289
|
+
|
290
|
+
|
291
|
+
def get_user_type(
|
292
|
+
self,
|
293
|
+
user: 'mrsm.core.User',
|
294
|
+
debug: bool = False,
|
295
|
+
**kw: Any
|
296
|
+
) -> Union[str, None]:
|
297
|
+
"""
|
298
|
+
Return the user's type.
|
299
|
+
"""
|
300
|
+
user_id = user.user_id if user.user_id is not None else self.get_user_id(user, debug=debug)
|
301
|
+
user_id_type_key = self.get_user_key(user_id, 'type')
|
302
|
+
try:
|
303
|
+
return self.get(user_id_type_key)
|
304
|
+
except Exception:
|
305
|
+
return None
|
meerschaum/core/Pipe/__init__.py
CHANGED
@@ -122,8 +122,7 @@ def dtypes(self) -> Union[Dict[str, Any], None]:
|
|
122
122
|
configured_dtypes = self.parameters.get('dtypes', {})
|
123
123
|
remote_dtypes = self.infer_dtypes(persist=False)
|
124
124
|
patched_dtypes = apply_patch_to_config(remote_dtypes, configured_dtypes)
|
125
|
-
|
126
|
-
return self.parameters['dtypes']
|
125
|
+
return patched_dtypes
|
127
126
|
|
128
127
|
|
129
128
|
@dtypes.setter
|
meerschaum/core/Pipe/_drop.py
CHANGED
@@ -10,10 +10,10 @@ from __future__ import annotations
|
|
10
10
|
from meerschaum.utils.typing import SuccessTuple, Any
|
11
11
|
|
12
12
|
def drop(
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
self,
|
14
|
+
debug: bool = False,
|
15
|
+
**kw: Any
|
16
|
+
) -> SuccessTuple:
|
17
17
|
"""
|
18
18
|
Call the Pipe's instance connector's `drop_pipe()` method.
|
19
19
|
|
meerschaum/core/Pipe/_dtypes.py
CHANGED
@@ -16,12 +16,12 @@ if TYPE_CHECKING:
|
|
16
16
|
pd = mrsm.attempt_import('pandas')
|
17
17
|
|
18
18
|
def enforce_dtypes(
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
self,
|
20
|
+
df: 'pd.DataFrame',
|
21
|
+
chunksize: Optional[int] = -1,
|
22
|
+
safe_copy: bool = True,
|
23
|
+
debug: bool = False,
|
24
|
+
) -> 'pd.DataFrame':
|
25
25
|
"""
|
26
26
|
Cast the input dataframe to the pipe's registered data types.
|
27
27
|
If the pipe does not exist and dtypes are not set, return the dataframe.
|
@@ -35,7 +35,7 @@ def enforce_dtypes(
|
|
35
35
|
if df is None:
|
36
36
|
if debug:
|
37
37
|
dprint(
|
38
|
-
|
38
|
+
"Received None instead of a DataFrame.\n"
|
39
39
|
+ " Skipping dtype enforcement..."
|
40
40
|
)
|
41
41
|
return df
|
@@ -46,24 +46,24 @@ def enforce_dtypes(
|
|
46
46
|
if isinstance(df, str):
|
47
47
|
df = parse_df_datetimes(
|
48
48
|
pd.read_json(StringIO(df)),
|
49
|
-
ignore_cols
|
49
|
+
ignore_cols=[
|
50
50
|
col
|
51
51
|
for col, dtype in pipe_dtypes.items()
|
52
52
|
if 'datetime' not in str(dtype)
|
53
53
|
],
|
54
|
-
chunksize
|
55
|
-
debug
|
54
|
+
chunksize=chunksize,
|
55
|
+
debug=debug,
|
56
56
|
)
|
57
57
|
else:
|
58
58
|
df = parse_df_datetimes(
|
59
59
|
df,
|
60
|
-
ignore_cols
|
60
|
+
ignore_cols=[
|
61
61
|
col
|
62
62
|
for col, dtype in pipe_dtypes.items()
|
63
63
|
if 'datetime' not in str(dtype)
|
64
64
|
],
|
65
|
-
chunksize
|
66
|
-
debug
|
65
|
+
chunksize=chunksize,
|
66
|
+
debug=debug,
|
67
67
|
)
|
68
68
|
except Exception as e:
|
69
69
|
warn(f"Unable to cast incoming data as a DataFrame...:\n{e}\n\n{traceback.format_exc()}")
|
@@ -80,7 +80,7 @@ def enforce_dtypes(
|
|
80
80
|
return _enforce_dtypes(df, pipe_dtypes, safe_copy=safe_copy, debug=debug)
|
81
81
|
|
82
82
|
|
83
|
-
def infer_dtypes(self, persist: bool=False, debug: bool=False) -> Dict[str, Any]:
|
83
|
+
def infer_dtypes(self, persist: bool = False, debug: bool = False) -> Dict[str, Any]:
|
84
84
|
"""
|
85
85
|
If `dtypes` is not set in `meerschaum.Pipe.parameters`,
|
86
86
|
infer the data types from the underlying table if it exists.
|