meerschaum 2.6.12__py3-none-any.whl → 2.6.13__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/api.py +3 -2
- meerschaum/api/dash/__init__.py +1 -0
- meerschaum/api/dash/callbacks/dashboard.py +3 -3
- meerschaum/api/dash/pipes.py +61 -43
- meerschaum/api/routes/_actions.py +12 -15
- meerschaum/api/routes/_jobs.py +6 -5
- meerschaum/api/routes/_login.py +9 -9
- meerschaum/config/_version.py +1 -1
- meerschaum/core/User/_User.py +7 -0
- meerschaum/core/User/__init__.py +10 -11
- meerschaum/utils/daemon/Daemon.py +8 -2
- meerschaum/utils/packages/_packages.py +1 -0
- meerschaum/utils/threading.py +14 -3
- {meerschaum-2.6.12.dist-info → meerschaum-2.6.13.dist-info}/METADATA +5 -2
- {meerschaum-2.6.12.dist-info → meerschaum-2.6.13.dist-info}/RECORD +21 -21
- {meerschaum-2.6.12.dist-info → meerschaum-2.6.13.dist-info}/LICENSE +0 -0
- {meerschaum-2.6.12.dist-info → meerschaum-2.6.13.dist-info}/NOTICE +0 -0
- {meerschaum-2.6.12.dist-info → meerschaum-2.6.13.dist-info}/WHEEL +0 -0
- {meerschaum-2.6.12.dist-info → meerschaum-2.6.13.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.6.12.dist-info → meerschaum-2.6.13.dist-info}/top_level.txt +0 -0
- {meerschaum-2.6.12.dist-info → meerschaum-2.6.13.dist-info}/zip-safe +0 -0
meerschaum/actions/api.py
CHANGED
@@ -9,6 +9,7 @@ from __future__ import annotations
|
|
9
9
|
import os
|
10
10
|
from meerschaum.utils.typing import SuccessTuple, Optional, List, Any
|
11
11
|
|
12
|
+
|
12
13
|
def api(
|
13
14
|
action: Optional[List[str]] = None,
|
14
15
|
sysargs: Optional[List[str]] = None,
|
@@ -36,7 +37,6 @@ def api(
|
|
36
37
|
|
37
38
|
"""
|
38
39
|
from meerschaum.utils.warnings import warn, info
|
39
|
-
from meerschaum.utils.formatting import print_tuple
|
40
40
|
from meerschaum._internal.arguments._parse_arguments import parse_dict_to_sysargs
|
41
41
|
|
42
42
|
if action is None:
|
@@ -88,6 +88,7 @@ def api(
|
|
88
88
|
success, message = api_conn.do_action(sysargs)
|
89
89
|
return success, message
|
90
90
|
|
91
|
+
|
91
92
|
def _api_start(
|
92
93
|
action: Optional[List[str]] = None,
|
93
94
|
host: Optional[str] = None,
|
@@ -191,7 +192,7 @@ def _api_start(
|
|
191
192
|
|
192
193
|
if keyfile or certfile:
|
193
194
|
if not keyfile or not certfile:
|
194
|
-
return False,
|
195
|
+
return False, "HTTPS requires both `--keyfile` and `--certfile`."
|
195
196
|
|
196
197
|
pool = get_pool(workers=workers)
|
197
198
|
if pool is None:
|
meerschaum/api/dash/__init__.py
CHANGED
@@ -33,6 +33,7 @@ import warnings
|
|
33
33
|
### Suppress the depreciation warnings from importing enrich.
|
34
34
|
with warnings.catch_warnings():
|
35
35
|
warnings.simplefilter("ignore")
|
36
|
+
_ = attempt_import('dataclass_wizard', lazy=False)
|
36
37
|
enrich = attempt_import('dash_extensions.enrich', lazy=False)
|
37
38
|
html, dcc = import_html(), import_dcc()
|
38
39
|
from meerschaum.api.dash.components import location
|
@@ -978,9 +978,9 @@ def sign_out_button_click(
|
|
978
978
|
Input({'type': 'parameters-as-json-button', 'index': MATCH}, 'n_clicks'),
|
979
979
|
)
|
980
980
|
def parameters_as_yaml_or_json_click(
|
981
|
-
|
982
|
-
|
983
|
-
|
981
|
+
yaml_n_clicks: Optional[int],
|
982
|
+
json_n_clicks: Optional[int],
|
983
|
+
):
|
984
984
|
"""
|
985
985
|
When the `YAML` button is clicked under the parameters editor, switch the content to YAML.
|
986
986
|
"""
|
meerschaum/api/dash/pipes.py
CHANGED
@@ -18,6 +18,7 @@ from meerschaum.utils.misc import string_to_dict
|
|
18
18
|
from meerschaum.utils.packages import attempt_import, import_dcc, import_html, import_pandas
|
19
19
|
from meerschaum.utils.sql import get_pd_type
|
20
20
|
from meerschaum.utils.yaml import yaml
|
21
|
+
from meerschaum.utils.warnings import warn
|
21
22
|
from meerschaum.utils.dataframe import to_json
|
22
23
|
from meerschaum.connectors.sql._fetch import get_pipe_query
|
23
24
|
from meerschaum.api import CHECK_UPDATE
|
@@ -49,7 +50,7 @@ def pipe_from_ctx(ctx, trigger_property: str = 'n_clicks') -> Union[mrsm.Pipe, N
|
|
49
50
|
### Because Dash JSON-ifies the ID dictionary and we are including a JSON-ified dictionary,
|
50
51
|
### we have to do some crazy parsing to get the pipe's meta-dict back out of it
|
51
52
|
meta = json.loads(json.loads(ctx[0]['prop_id'].split('.' + trigger_property)[0])['index'])
|
52
|
-
except Exception
|
53
|
+
except Exception:
|
53
54
|
meta = None
|
54
55
|
if meta is None:
|
55
56
|
return None
|
@@ -115,6 +116,7 @@ def build_pipe_card(
|
|
115
116
|
pipe: mrsm.Pipe,
|
116
117
|
authenticated: bool = False,
|
117
118
|
include_manage: bool = True,
|
119
|
+
_build_parents_num: int = 10,
|
118
120
|
_build_children_num: int = 10,
|
119
121
|
) -> 'dbc.Card':
|
120
122
|
"""
|
@@ -220,6 +222,7 @@ def build_pipe_card(
|
|
220
222
|
accordion_items_from_pipe(
|
221
223
|
pipe,
|
222
224
|
authenticated=authenticated,
|
225
|
+
_build_parents_num=_build_parents_num,
|
223
226
|
_build_children_num=_build_children_num,
|
224
227
|
),
|
225
228
|
flush=True,
|
@@ -235,7 +238,7 @@ def build_pipe_card(
|
|
235
238
|
if pipe.instance_keys != default_instance:
|
236
239
|
query_params['instance'] = pipe.instance_keys
|
237
240
|
pipe_url = (
|
238
|
-
|
241
|
+
"/dash/pipes/"
|
239
242
|
+ f"{pipe.connector_keys}/"
|
240
243
|
+ f"{pipe.metric_key}/"
|
241
244
|
+ (f"{pipe.location_key}" if pipe.location_key is not None else '')
|
@@ -322,6 +325,7 @@ def accordion_items_from_pipe(
|
|
322
325
|
pipe: mrsm.Pipe,
|
323
326
|
active_items: Optional[List[str]] = None,
|
324
327
|
authenticated: bool = False,
|
328
|
+
_build_parents_num: int = 10,
|
325
329
|
_build_children_num: int = 10,
|
326
330
|
) -> 'List[dbc.AccordionItem]':
|
327
331
|
"""
|
@@ -494,7 +498,7 @@ def accordion_items_from_pipe(
|
|
494
498
|
else None
|
495
499
|
)
|
496
500
|
rowcount = pipe.get_rowcount(debug=debug)
|
497
|
-
except Exception
|
501
|
+
except Exception:
|
498
502
|
oldest_time = None
|
499
503
|
newest_time = None
|
500
504
|
interval = None
|
@@ -532,44 +536,44 @@ def accordion_items_from_pipe(
|
|
532
536
|
]
|
533
537
|
columns_body = [html.Tbody(columns_rows)]
|
534
538
|
columns_table = dbc.Table(columns_header + columns_body, bordered=False, hover=True)
|
535
|
-
except Exception
|
539
|
+
except Exception:
|
536
540
|
columns_table = html.P("Could not retrieve columns ― please try again.")
|
537
541
|
items_bodies['columns'] = columns_table
|
538
542
|
|
539
543
|
if 'parameters' in active_items:
|
540
544
|
parameters_editor = dash_ace.DashAceEditor(
|
541
|
-
value
|
542
|
-
mode
|
543
|
-
tabSize
|
544
|
-
theme
|
545
|
-
id
|
546
|
-
width
|
547
|
-
height
|
548
|
-
readOnly
|
549
|
-
showGutter
|
550
|
-
showPrintMargin
|
551
|
-
highlightActiveLine
|
552
|
-
wrapEnabled
|
553
|
-
style
|
545
|
+
value=yaml.dump(pipe.parameters),
|
546
|
+
mode='norm',
|
547
|
+
tabSize=4,
|
548
|
+
theme='twilight',
|
549
|
+
id={'type': 'parameters-editor', 'index': json.dumps(pipe.meta)},
|
550
|
+
width='100%',
|
551
|
+
height='500px',
|
552
|
+
readOnly=False,
|
553
|
+
showGutter=True,
|
554
|
+
showPrintMargin=True,
|
555
|
+
highlightActiveLine=True,
|
556
|
+
wrapEnabled=True,
|
557
|
+
style={'min-height': '120px'},
|
554
558
|
)
|
555
559
|
update_parameters_button = dbc.Button(
|
556
560
|
"Update",
|
557
|
-
id
|
561
|
+
id={'type': 'update-parameters-button', 'index': json.dumps(pipe.meta)},
|
558
562
|
)
|
559
563
|
|
560
564
|
as_yaml_button = dbc.Button(
|
561
565
|
"YAML",
|
562
|
-
id
|
563
|
-
color
|
564
|
-
size
|
565
|
-
style
|
566
|
+
id={'type': 'parameters-as-yaml-button', 'index': json.dumps(pipe.meta)},
|
567
|
+
color='link',
|
568
|
+
size='sm',
|
569
|
+
style={'text-decoration': 'none'},
|
566
570
|
)
|
567
571
|
as_json_button = dbc.Button(
|
568
572
|
"JSON",
|
569
|
-
id
|
570
|
-
color
|
571
|
-
size
|
572
|
-
style
|
573
|
+
id={'type': 'parameters-as-json-button', 'index': json.dumps(pipe.meta)},
|
574
|
+
color='link',
|
575
|
+
size='sm',
|
576
|
+
style={'text-decoration': 'none', 'margin-left': '10px'},
|
573
577
|
)
|
574
578
|
parameters_div_children = [
|
575
579
|
parameters_editor,
|
@@ -593,6 +597,20 @@ def accordion_items_from_pipe(
|
|
593
597
|
)
|
594
598
|
]),
|
595
599
|
]
|
600
|
+
|
601
|
+
if _build_parents_num > 0 and pipe.parents:
|
602
|
+
parents_cards = [
|
603
|
+
build_pipe_card(
|
604
|
+
parent_pipe,
|
605
|
+
authenticated = authenticated,
|
606
|
+
_build_parents_num = (_build_parents_num - 1),
|
607
|
+
)
|
608
|
+
for parent_pipe in pipe.parents
|
609
|
+
]
|
610
|
+
parents_grid = build_cards_grid(parents_cards, num_columns=1)
|
611
|
+
parents_div_items = [html.Br(), html.H3('Parent Pipes'), html.Br(), parents_grid]
|
612
|
+
parameters_div_children.extend([html.Br()] + parents_div_items)
|
613
|
+
|
596
614
|
if _build_children_num > 0 and pipe.children:
|
597
615
|
children_cards = [
|
598
616
|
build_pipe_card(
|
@@ -603,31 +621,31 @@ def accordion_items_from_pipe(
|
|
603
621
|
for child_pipe in pipe.children
|
604
622
|
]
|
605
623
|
children_grid = build_cards_grid(children_cards, num_columns=1)
|
606
|
-
|
607
|
-
parameters_div_children.extend([html.Br()] +
|
624
|
+
children_div_items = [html.Br(), html.H3('Children Pipes'), html.Br(), children_grid]
|
625
|
+
parameters_div_children.extend([html.Br()] + children_div_items)
|
608
626
|
|
609
627
|
items_bodies['parameters'] = html.Div(parameters_div_children)
|
610
628
|
|
611
629
|
if 'sql' in active_items:
|
612
630
|
query = dedent((get_pipe_query(pipe, warn=False) or "")).lstrip().rstrip()
|
613
631
|
sql_editor = dash_ace.DashAceEditor(
|
614
|
-
value
|
615
|
-
mode
|
616
|
-
tabSize
|
617
|
-
theme
|
618
|
-
id
|
619
|
-
width
|
620
|
-
height
|
621
|
-
readOnly
|
622
|
-
showGutter
|
623
|
-
showPrintMargin
|
624
|
-
highlightActiveLine
|
625
|
-
wrapEnabled
|
626
|
-
style
|
632
|
+
value=query,
|
633
|
+
mode='sql',
|
634
|
+
tabSize=4,
|
635
|
+
theme='twilight',
|
636
|
+
id={'type': 'sql-editor', 'index': json.dumps(pipe.meta)},
|
637
|
+
width='100%',
|
638
|
+
height='500px',
|
639
|
+
readOnly=False,
|
640
|
+
showGutter=True,
|
641
|
+
showPrintMargin=False,
|
642
|
+
highlightActiveLine=True,
|
643
|
+
wrapEnabled=True,
|
644
|
+
style={'min-height': '120px'},
|
627
645
|
)
|
628
646
|
update_sql_button = dbc.Button(
|
629
647
|
"Update",
|
630
|
-
id
|
648
|
+
id={'type': 'update-sql-button', 'index': json.dumps(pipe.meta)},
|
631
649
|
)
|
632
650
|
items_bodies['sql'] = html.Div([
|
633
651
|
sql_editor,
|
@@ -648,7 +666,7 @@ def accordion_items_from_pipe(
|
|
648
666
|
try:
|
649
667
|
df = pipe.get_backtrack_data(backtrack_minutes=10, limit=10, debug=debug).astype(str)
|
650
668
|
table = dbc.Table.from_dataframe(df, bordered=False, hover=True)
|
651
|
-
except Exception
|
669
|
+
except Exception:
|
652
670
|
table = html.P("Could not retrieve recent data.")
|
653
671
|
items_bodies['recent-data'] = table
|
654
672
|
|
@@ -10,10 +10,17 @@ from __future__ import annotations
|
|
10
10
|
|
11
11
|
from meerschaum.utils.typing import SuccessTuple, List, Dict, Any
|
12
12
|
from meerschaum.api import (
|
13
|
-
fastapi,
|
13
|
+
fastapi,
|
14
|
+
app,
|
15
|
+
endpoints,
|
16
|
+
get_api_connector,
|
17
|
+
debug,
|
18
|
+
manager,
|
19
|
+
private,
|
20
|
+
no_auth,
|
14
21
|
)
|
15
22
|
from meerschaum.actions import actions
|
16
|
-
from meerschaum.
|
23
|
+
from meerschaum.core.User import is_user_allowed_to_execute
|
17
24
|
|
18
25
|
actions_endpoint = endpoints['actions']
|
19
26
|
|
@@ -53,19 +60,9 @@ def do_action_legacy(
|
|
53
60
|
-------
|
54
61
|
A `SuccessTuple`.
|
55
62
|
"""
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
)
|
60
|
-
if not allow_non_admin:
|
61
|
-
return False, (
|
62
|
-
"The administrator for this server has not allowed users to perform actions.\n\n"
|
63
|
-
+ "Please contact the system administrator, or if you are running this server, "
|
64
|
-
+ "open the configuration file with `edit config system` "
|
65
|
-
+ "and search for 'permissions'. "
|
66
|
-
+ "\nUnder the keys 'api:permissions:actions', "
|
67
|
-
+ "you can allow non-admin users to perform actions."
|
68
|
-
)
|
63
|
+
allowed_success, allowed_msg = is_user_allowed_to_execute(curr_user, debug=debug)
|
64
|
+
if not allowed_success:
|
65
|
+
return allowed_success, allowed_msg
|
69
66
|
|
70
67
|
if action not in actions:
|
71
68
|
return False, f"Invalid action '{action}'."
|
meerschaum/api/routes/_jobs.py
CHANGED
@@ -30,6 +30,7 @@ from meerschaum.api import (
|
|
30
30
|
endpoints,
|
31
31
|
manager,
|
32
32
|
no_auth,
|
33
|
+
debug,
|
33
34
|
)
|
34
35
|
from meerschaum.config.static import STATIC_CONFIG
|
35
36
|
from meerschaum.core.User import is_user_allowed_to_execute
|
@@ -143,7 +144,7 @@ def create_job(
|
|
143
144
|
"""
|
144
145
|
Create and start a new job.
|
145
146
|
"""
|
146
|
-
allowed_success, allowed_msg = is_user_allowed_to_execute(curr_user)
|
147
|
+
allowed_success, allowed_msg = is_user_allowed_to_execute(curr_user, debug=debug)
|
147
148
|
if not allowed_success:
|
148
149
|
return allowed_success, allowed_msg
|
149
150
|
|
@@ -178,7 +179,7 @@ def delete_job(
|
|
178
179
|
"""
|
179
180
|
Delete a job.
|
180
181
|
"""
|
181
|
-
allowed_success, allowed_msg = is_user_allowed_to_execute(curr_user)
|
182
|
+
allowed_success, allowed_msg = is_user_allowed_to_execute(curr_user, debug=debug)
|
182
183
|
if not allowed_success:
|
183
184
|
return allowed_success, allowed_msg
|
184
185
|
job = _get_job(name)
|
@@ -230,7 +231,7 @@ def start_job(
|
|
230
231
|
"""
|
231
232
|
Start a job if stopped.
|
232
233
|
"""
|
233
|
-
allowed_success, allowed_msg = is_user_allowed_to_execute(curr_user)
|
234
|
+
allowed_success, allowed_msg = is_user_allowed_to_execute(curr_user, debug=debug)
|
234
235
|
if not allowed_success:
|
235
236
|
return allowed_success, allowed_msg
|
236
237
|
|
@@ -253,7 +254,7 @@ def stop_job(
|
|
253
254
|
"""
|
254
255
|
Stop a job if running.
|
255
256
|
"""
|
256
|
-
allowed_success, allowed_msg = is_user_allowed_to_execute(curr_user)
|
257
|
+
allowed_success, allowed_msg = is_user_allowed_to_execute(curr_user, debug=debug)
|
257
258
|
if not allowed_success:
|
258
259
|
return allowed_success, allowed_msg
|
259
260
|
|
@@ -276,7 +277,7 @@ def pause_job(
|
|
276
277
|
"""
|
277
278
|
Pause a job if running.
|
278
279
|
"""
|
279
|
-
allowed_success, allowed_msg = is_user_allowed_to_execute(curr_user)
|
280
|
+
allowed_success, allowed_msg = is_user_allowed_to_execute(curr_user, debug=debug)
|
280
281
|
if not allowed_success:
|
281
282
|
return allowed_success, allowed_msg
|
282
283
|
|
meerschaum/api/routes/_login.py
CHANGED
@@ -7,24 +7,24 @@ Manage access and refresh tokens.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from datetime import datetime, timedelta, timezone
|
10
|
+
|
10
11
|
import fastapi
|
11
12
|
from fastapi import Request, status
|
12
13
|
from fastapi_login.exceptions import InvalidCredentialsException
|
13
14
|
from fastapi.exceptions import RequestValidationError
|
14
|
-
from starlette.responses import
|
15
|
+
from starlette.responses import JSONResponse
|
16
|
+
|
15
17
|
from meerschaum.api import endpoints, get_api_connector, app, debug, manager, no_auth
|
16
18
|
from meerschaum.core import User
|
17
19
|
from meerschaum.config.static import STATIC_CONFIG
|
18
|
-
from meerschaum.utils.typing import Dict, Any
|
20
|
+
from meerschaum.utils.typing import Dict, Any
|
19
21
|
from meerschaum.core.User._User import verify_password
|
20
22
|
from meerschaum.utils.warnings import warn
|
21
23
|
from meerschaum.api._oauth2 import CustomOAuth2PasswordRequestForm
|
22
24
|
|
23
25
|
|
24
26
|
@manager.user_loader()
|
25
|
-
def load_user(
|
26
|
-
username: str
|
27
|
-
) -> User:
|
27
|
+
def load_user(username: str) -> User:
|
28
28
|
"""
|
29
29
|
Create the `meerschaum.core.User` object from the username.
|
30
30
|
"""
|
@@ -56,8 +56,8 @@ def login(
|
|
56
56
|
expires_delta = timedelta(minutes=expires_minutes)
|
57
57
|
expires_dt = datetime.now(timezone.utc).replace(tzinfo=None) + expires_delta
|
58
58
|
access_token = manager.create_access_token(
|
59
|
-
data
|
60
|
-
expires
|
59
|
+
data={'sub': username},
|
60
|
+
expires=expires_delta
|
61
61
|
)
|
62
62
|
return {
|
63
63
|
'access_token': access_token,
|
@@ -73,6 +73,6 @@ async def validation_exception_handler(request: Request, exc: RequestValidationE
|
|
73
73
|
"""
|
74
74
|
warn(f"Validation error: {exc.errors()}", stack=False)
|
75
75
|
return JSONResponse(
|
76
|
-
status_code
|
77
|
-
content
|
76
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
77
|
+
content={"detail": exc.errors()},
|
78
78
|
)
|
meerschaum/config/_version.py
CHANGED
meerschaum/core/User/_User.py
CHANGED
@@ -11,6 +11,8 @@ import os
|
|
11
11
|
import hashlib
|
12
12
|
import hmac
|
13
13
|
from binascii import b2a_base64, a2b_base64, Error as _BinAsciiError
|
14
|
+
|
15
|
+
import meerschaum as mrsm
|
14
16
|
from meerschaum.utils.typing import Optional, Dict, Any, Union
|
15
17
|
from meerschaum.config.static import STATIC_CONFIG
|
16
18
|
from meerschaum.utils.warnings import warn
|
@@ -18,6 +20,7 @@ from meerschaum.utils.warnings import warn
|
|
18
20
|
|
19
21
|
__all__ = ('hash_password', 'verify_password', 'User')
|
20
22
|
|
23
|
+
|
21
24
|
def hash_password(
|
22
25
|
password: str,
|
23
26
|
salt: Optional[bytes] = None,
|
@@ -113,9 +116,11 @@ _BASE64_STRIP = b"=\n"
|
|
113
116
|
_BASE64_PAD1 = b"="
|
114
117
|
_BASE64_PAD2 = b"=="
|
115
118
|
|
119
|
+
|
116
120
|
def ab64_encode(data):
|
117
121
|
return b64s_encode(data).replace(b"+", b".")
|
118
122
|
|
123
|
+
|
119
124
|
def ab64_decode(data):
|
120
125
|
"""
|
121
126
|
decode from shortened base64 format which omits padding & whitespace.
|
@@ -133,6 +138,7 @@ def ab64_decode(data):
|
|
133
138
|
def b64s_encode(data):
|
134
139
|
return b2a_base64(data).rstrip(_BASE64_STRIP)
|
135
140
|
|
141
|
+
|
136
142
|
def b64s_decode(data):
|
137
143
|
"""
|
138
144
|
decode from shortened base64 format which omits padding & whitespace.
|
@@ -222,5 +228,6 @@ class User:
|
|
222
228
|
_password_hash = self.__dict__.get('_password_hash', None)
|
223
229
|
if _password_hash is not None:
|
224
230
|
return _password_hash
|
231
|
+
|
225
232
|
self._password_hash = hash_password(self.password)
|
226
233
|
return self._password_hash
|
meerschaum/core/User/__init__.py
CHANGED
@@ -12,28 +12,27 @@ import meerschaum as mrsm
|
|
12
12
|
from meerschaum.core.User._User import User, hash_password, verify_password
|
13
13
|
|
14
14
|
|
15
|
-
def is_user_allowed_to_execute(
|
15
|
+
def is_user_allowed_to_execute(
|
16
|
+
user: Optional[User],
|
17
|
+
debug: bool = False,
|
18
|
+
) -> mrsm.SuccessTuple:
|
16
19
|
"""
|
17
20
|
Return a `SuccessTuple` indicating whether a given user is allowed to execute actions.
|
18
21
|
"""
|
22
|
+
print(f"{debug=}")
|
23
|
+
print(f"{user=}")
|
19
24
|
if user is None:
|
20
25
|
return True, "Success"
|
21
26
|
|
22
|
-
|
27
|
+
user_type = user.instance_connector.get_user_type(user, debug=debug)
|
28
|
+
|
29
|
+
if user_type == 'admin':
|
23
30
|
return True, "Success"
|
24
31
|
|
25
32
|
from meerschaum.config import get_config
|
26
33
|
|
27
34
|
allow_non_admin = get_config('system', 'api', 'permissions', 'actions', 'non_admin')
|
28
35
|
if not allow_non_admin:
|
29
|
-
return False,
|
30
|
-
"The administrator for this server has not allowed users to perform actions.\n\n"
|
31
|
-
+ "Please contact the system administrator, or if you are running this server, "
|
32
|
-
+ "open the configuration file with `edit config system` "
|
33
|
-
+ "and search for 'permissions'. "
|
34
|
-
+ "\nUnder the keys 'api:permissions:actions', "
|
35
|
-
+ "you can allow non-admin users to perform actions."
|
36
|
-
)
|
36
|
+
return False, "The administrator for this server has not allowed users to perform actions."
|
37
37
|
|
38
38
|
return True, "Success"
|
39
|
-
|
@@ -315,7 +315,13 @@ class Daemon:
|
|
315
315
|
with open(self.pid_path, 'w+', encoding='utf-8') as f:
|
316
316
|
f.write(str(os.getpid()))
|
317
317
|
|
318
|
-
|
318
|
+
### NOTE: The timer fails to start for remote actions to localhost.
|
319
|
+
try:
|
320
|
+
if not self._log_refresh_timer.is_running():
|
321
|
+
self._log_refresh_timer.start()
|
322
|
+
except Exception:
|
323
|
+
pass
|
324
|
+
|
319
325
|
self.properties['result'] = None
|
320
326
|
self._capture_process_timestamp('began')
|
321
327
|
result = self.target(*self.target_args, **self.target_kw)
|
@@ -345,7 +351,7 @@ class Daemon:
|
|
345
351
|
except BrokenPipeError:
|
346
352
|
pass
|
347
353
|
|
348
|
-
except Exception
|
354
|
+
except Exception:
|
349
355
|
daemon_error = traceback.format_exc()
|
350
356
|
with open(DAEMON_ERROR_LOG_PATH, 'a+', encoding='utf-8') as f:
|
351
357
|
f.write(daemon_error)
|
@@ -152,6 +152,7 @@ packages['dash'] = {
|
|
152
152
|
'dash_bootstrap_components' : 'dash-bootstrap-components>=1.2.1',
|
153
153
|
'dash_ace' : 'dash-ace>=0.2.1',
|
154
154
|
'dash_extensions' : 'dash-extensions>=1.0.4',
|
155
|
+
'dataclass_wizard' : 'dataclass-wizard>=0.28.0',
|
155
156
|
'dash_daq' : 'dash-daq>=0.5.0',
|
156
157
|
'terminado' : 'terminado>=0.12.1',
|
157
158
|
'tornado' : 'tornado>=6.1.0',
|
meerschaum/utils/threading.py
CHANGED
@@ -10,7 +10,6 @@ from __future__ import annotations
|
|
10
10
|
from meerschaum.utils.typing import Optional
|
11
11
|
|
12
12
|
import threading
|
13
|
-
import traceback
|
14
13
|
Lock = threading.Lock
|
15
14
|
RLock = threading.RLock
|
16
15
|
Event = threading.Event
|
@@ -67,8 +66,8 @@ class Worker(threading.Thread):
|
|
67
66
|
def run(self):
|
68
67
|
while True:
|
69
68
|
try:
|
70
|
-
|
71
|
-
except queue.Empty:
|
69
|
+
_ = self.queue.get(timeout=self.timeout)
|
70
|
+
except self.queue.Empty:
|
72
71
|
return None
|
73
72
|
|
74
73
|
self.queue.task_done()
|
@@ -79,9 +78,21 @@ class RepeatTimer(Timer):
|
|
79
78
|
Fire the timer's target function in a loop, every `interval` seconds.
|
80
79
|
"""
|
81
80
|
|
81
|
+
def __init__(self, *args, **kwargs):
|
82
|
+
super().__init__(*args, **kwargs)
|
83
|
+
self._is_running = False
|
84
|
+
|
85
|
+
def is_running(self) -> bool:
|
86
|
+
"""
|
87
|
+
Return whether this timer has been started and is running.
|
88
|
+
"""
|
89
|
+
return self._is_running
|
90
|
+
|
82
91
|
def run(self) -> None:
|
83
92
|
"""
|
84
93
|
Fire the target function in a loop.
|
85
94
|
"""
|
95
|
+
self._is_running = True
|
86
96
|
while not self.finished.wait(self.interval):
|
87
97
|
self.function(*self.args, **self.kwargs)
|
98
|
+
self._is_running = False
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: meerschaum
|
3
|
-
Version: 2.6.
|
3
|
+
Version: 2.6.13
|
4
4
|
Summary: Sync Time-Series Pipes with Meerschaum
|
5
5
|
Home-page: https://meerschaum.io
|
6
6
|
Author: Bennett Meares
|
@@ -20,11 +20,11 @@ Classifier: Operating System :: POSIX :: Linux
|
|
20
20
|
Classifier: Operating System :: Microsoft :: Windows
|
21
21
|
Classifier: Operating System :: MacOS
|
22
22
|
Classifier: Programming Language :: SQL
|
23
|
-
Classifier: Programming Language :: Python :: 3.8
|
24
23
|
Classifier: Programming Language :: Python :: 3.9
|
25
24
|
Classifier: Programming Language :: Python :: 3.10
|
26
25
|
Classifier: Programming Language :: Python :: 3.11
|
27
26
|
Classifier: Programming Language :: Python :: 3.12
|
27
|
+
Classifier: Programming Language :: Python :: 3.13
|
28
28
|
Classifier: Topic :: Database
|
29
29
|
Classifier: Natural Language :: English
|
30
30
|
Requires-Python: >=3.8
|
@@ -95,6 +95,7 @@ Requires-Dist: dash >=2.6.2 ; extra == 'api'
|
|
95
95
|
Requires-Dist: dash-bootstrap-components >=1.2.1 ; extra == 'api'
|
96
96
|
Requires-Dist: dash-ace >=0.2.1 ; extra == 'api'
|
97
97
|
Requires-Dist: dash-extensions >=1.0.4 ; extra == 'api'
|
98
|
+
Requires-Dist: dataclass-wizard >=0.28.0 ; extra == 'api'
|
98
99
|
Requires-Dist: dash-daq >=0.5.0 ; extra == 'api'
|
99
100
|
Requires-Dist: terminado >=0.12.1 ; extra == 'api'
|
100
101
|
Requires-Dist: tornado >=6.1.0 ; extra == 'api'
|
@@ -140,6 +141,7 @@ Requires-Dist: dash >=2.6.2 ; extra == 'dash'
|
|
140
141
|
Requires-Dist: dash-bootstrap-components >=1.2.1 ; extra == 'dash'
|
141
142
|
Requires-Dist: dash-ace >=0.2.1 ; extra == 'dash'
|
142
143
|
Requires-Dist: dash-extensions >=1.0.4 ; extra == 'dash'
|
144
|
+
Requires-Dist: dataclass-wizard >=0.28.0 ; extra == 'dash'
|
143
145
|
Requires-Dist: dash-daq >=0.5.0 ; extra == 'dash'
|
144
146
|
Requires-Dist: terminado >=0.12.1 ; extra == 'dash'
|
145
147
|
Requires-Dist: tornado >=6.1.0 ; extra == 'dash'
|
@@ -250,6 +252,7 @@ Requires-Dist: dash >=2.6.2 ; extra == 'full'
|
|
250
252
|
Requires-Dist: dash-bootstrap-components >=1.2.1 ; extra == 'full'
|
251
253
|
Requires-Dist: dash-ace >=0.2.1 ; extra == 'full'
|
252
254
|
Requires-Dist: dash-extensions >=1.0.4 ; extra == 'full'
|
255
|
+
Requires-Dist: dataclass-wizard >=0.28.0 ; extra == 'full'
|
253
256
|
Requires-Dist: dash-daq >=0.5.0 ; extra == 'full'
|
254
257
|
Requires-Dist: terminado >=0.12.1 ; extra == 'full'
|
255
258
|
Requires-Dist: tornado >=6.1.0 ; extra == 'full'
|
@@ -22,7 +22,7 @@ meerschaum/_internal/term/TermPageHandler.py,sha256=57peuFD4geabiP7aomVNH_bRfNFP
|
|
22
22
|
meerschaum/_internal/term/__init__.py,sha256=AT-dUw6cPISDDvHUplrSMsmPR5mo2JgVTtIzmOGcW7E,1733
|
23
23
|
meerschaum/_internal/term/tools.py,sha256=dXVAimKD-Yv2fg2WOTr0YGBY7XDKjQqw-RizcS65YVI,727
|
24
24
|
meerschaum/actions/__init__.py,sha256=MHPs8aRBhbZQXnqd_6tVtisTrNCgPAPgnNcXYbn0zP8,11640
|
25
|
-
meerschaum/actions/api.py,sha256=
|
25
|
+
meerschaum/actions/api.py,sha256=41r3fBh3vAPyNaOrvbh2oh6WUJTR2I-zaOEZN60A66E,12538
|
26
26
|
meerschaum/actions/attach.py,sha256=UV19d9W_2WYcrf7BRz7k3mriDoX1V4rA4AKvbLdor0o,3106
|
27
27
|
meerschaum/actions/bootstrap.py,sha256=9y4HU1uqjbkAg_706pOOJUMzl196pU7ghfGDCWg0vPE,18234
|
28
28
|
meerschaum/actions/clear.py,sha256=tMacHFv8btWpkNnXHtKDOMiCDNhGb5S6CJhCDIrrNDk,4914
|
@@ -56,13 +56,13 @@ meerschaum/api/_chain.py,sha256=h8-WXUGXX6AqzdALfsBC5uv0FkAcLdHJXCGzqzuq89k,875
|
|
56
56
|
meerschaum/api/_events.py,sha256=f-98AXHU10IL9zRGX1FrZFANxxiMz5ryeJnfFWaU8R8,2232
|
57
57
|
meerschaum/api/_oauth2.py,sha256=dJTIVlPpX3sAVW-PcN6pXRNy2RR5QAalu2RHp3l14YU,1683
|
58
58
|
meerschaum/api/_websockets.py,sha256=EMT9wB3yELu_WyCMqn9ZpgMDh23spUUchouRLCCLVuw,1509
|
59
|
-
meerschaum/api/dash/__init__.py,sha256=
|
59
|
+
meerschaum/api/dash/__init__.py,sha256=29vMm_m5gSDYG0lahh-8yVfhqg9kUFnUrYyw_9jC2Y0,2078
|
60
60
|
meerschaum/api/dash/components.py,sha256=t2goHW7oioao5Ew6Dro9U4LZDnHF-YWb4flLPx46GP8,6293
|
61
61
|
meerschaum/api/dash/connectors.py,sha256=nJxBOFldtCMJLYjUSVYZwX5BO-LNjTNHgoEaXe-0XMo,843
|
62
62
|
meerschaum/api/dash/graphs.py,sha256=wJUDWzcLN8-C3xko6rj0F2v7Rt8YDkSXoVkkXJjYGIk,2046
|
63
63
|
meerschaum/api/dash/jobs.py,sha256=mj9STE6AaQY4fwkjD1JcYRG0iW3VEcP04bO1SlKgiXw,7681
|
64
64
|
meerschaum/api/dash/keys.py,sha256=hzEVeN60SAfVTVSO5lajGaykxRIKGhj9Ph00HRJnNoE,12598
|
65
|
-
meerschaum/api/dash/pipes.py,sha256=
|
65
|
+
meerschaum/api/dash/pipes.py,sha256=39Ler1YIxaDmbZu9zKuJclA-j9psbrPRwZfBnh4KuxA,26264
|
66
66
|
meerschaum/api/dash/plugins.py,sha256=KdfG04f6SsUpBg-nm7MUJegFGuElOj-GAkxDX98hi60,3768
|
67
67
|
meerschaum/api/dash/sessions.py,sha256=-y5p4MYKh1eFzppkBfMsd6T7-rJs1nYS2-4fbVRAeRA,5029
|
68
68
|
meerschaum/api/dash/sync.py,sha256=9lt7IRdG-fe9gf_ZO_viPiGlerX7ic6r_VFocv3I51A,504
|
@@ -77,7 +77,7 @@ meerschaum/api/dash/assets/logo_48x48.png,sha256=hTR5BHUHEN4yP2xiqAcDciuigoII9T3
|
|
77
77
|
meerschaum/api/dash/assets/logo_500x500.png,sha256=9EUtf6wQcEZTXHKfQ2kjNXod6Rn_4DTB_BkTgxggq00,67702
|
78
78
|
meerschaum/api/dash/callbacks/__init__.py,sha256=5nLDkziaWWWt5ivmuMNG3kVBMOfqB6KQNIAS8f16bmA,493
|
79
79
|
meerschaum/api/dash/callbacks/custom.py,sha256=N9pVolAF8sIuJD3V6xBSgS7k8THJo_f8d1qAoh1Kg60,1161
|
80
|
-
meerschaum/api/dash/callbacks/dashboard.py,sha256=
|
80
|
+
meerschaum/api/dash/callbacks/dashboard.py,sha256=CWIHQAIBm5zORQXevpaeoA-AvHi0XJLkyj2tNMdI3EY,32745
|
81
81
|
meerschaum/api/dash/callbacks/jobs.py,sha256=JYTrDcUEte_MIT3EegLDmQDsmU_Mxqw8L60dvF71ho4,8418
|
82
82
|
meerschaum/api/dash/callbacks/login.py,sha256=mEvMgV-f85H6DvqNdTvJPoiwHqTnhWY2nf_zLB26ipE,2876
|
83
83
|
meerschaum/api/dash/callbacks/pipes.py,sha256=byphQn-wJOe8ft-fGU9wac0n5xsMjVHJzNvYYb9NsKU,1693
|
@@ -118,11 +118,11 @@ meerschaum/api/resources/templates/old_index.html,sha256=BDeOlcXhSsBH3-NaRtuX4Z1
|
|
118
118
|
meerschaum/api/resources/templates/secret.html,sha256=0QWkm4ZoN81Aw1pd2-62rGCvx3nXPHfFUoegj3Iy8Ls,141
|
119
119
|
meerschaum/api/resources/templates/termpage.html,sha256=qspXRuOkzqOn2mXw9mmUldzsvOHq_LyaywQ29CUevp0,4527
|
120
120
|
meerschaum/api/routes/__init__.py,sha256=jbkeFNl51Tg8aT5gWe560ZLZLojFJsLMe5IENRjRkb0,606
|
121
|
-
meerschaum/api/routes/_actions.py,sha256
|
121
|
+
meerschaum/api/routes/_actions.py,sha256=VUasS1dpr4d3TXHcR1CXlRZPAqvGKKuHv_f9PsOkQ5c,1732
|
122
122
|
meerschaum/api/routes/_connectors.py,sha256=NNbcn5xWhKqw2PqueSEaqRaZ95hFGDKazG5lE7gsssc,1849
|
123
123
|
meerschaum/api/routes/_index.py,sha256=QI6CBo6pI2Zi0a6fJHDjZfiLa9f4okb0BGe3A_JD0kM,578
|
124
|
-
meerschaum/api/routes/_jobs.py,sha256=
|
125
|
-
meerschaum/api/routes/_login.py,sha256=
|
124
|
+
meerschaum/api/routes/_jobs.py,sha256=sEt-UtVd5pN-hJgikTvj1oTKJQ2hhNe8XhjkclwOXOE,12568
|
125
|
+
meerschaum/api/routes/_login.py,sha256=tygEp50EVOMgvTG6CEASlShflbtEK8viJ9O07o0lnnE,2434
|
126
126
|
meerschaum/api/routes/_misc.py,sha256=05--9ZVFeaCgZrHER2kA3SYdK4TyfkEXOCjLvPbum-w,2469
|
127
127
|
meerschaum/api/routes/_pipes.py,sha256=li52WQUwZN8JEPyIuWN7s4wASWNV2BTVAUpQ_E1CKLg,21579
|
128
128
|
meerschaum/api/routes/_plugins.py,sha256=vR6-uTJraY1YEJMuRvds1-xFLB2mexxnp2dJwN_0rVo,6216
|
@@ -143,7 +143,7 @@ meerschaum/config/_preprocess.py,sha256=-AEA8m_--KivZwTQ1sWN6LTn5sio_fUr2XZ51BO6
|
|
143
143
|
meerschaum/config/_read_config.py,sha256=RLC3HHi_1ndj7ITVDKLD9_uULY3caGRwSz3ATYE-ixA,15014
|
144
144
|
meerschaum/config/_shell.py,sha256=46_m49Txc5q1rGfCgO49ca48BODx45DQJi8D0zz1R18,4245
|
145
145
|
meerschaum/config/_sync.py,sha256=jHcWRkxd82_BgX8Xo8agsWvf7BSbv3qHLWmYl6ehp_0,4242
|
146
|
-
meerschaum/config/_version.py,sha256=
|
146
|
+
meerschaum/config/_version.py,sha256=Ye56ah-9dP1YgHaQXApA4ezZi9HYTnZKyxqKSOsLtPk,72
|
147
147
|
meerschaum/config/paths.py,sha256=JjibeGN3YAdSNceRwsd42aNmeUrIgM6ndzC8qZAmNI0,621
|
148
148
|
meerschaum/config/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
149
149
|
meerschaum/config/stack/__init__.py,sha256=2UukC0Lmk-aVL1o1qXzumqmuIrw3vu9fD7iCuz4XD4I,10544
|
@@ -208,8 +208,8 @@ meerschaum/core/Pipe/_show.py,sha256=nG50y8eBT9TVuKkRgAKtNDNIxysJvMNxfu__lkL1F9k
|
|
208
208
|
meerschaum/core/Pipe/_sync.py,sha256=E2egt63tqhVpB0ZteMO36HTF4EYEMtdevKOtN1aLd9o,34753
|
209
209
|
meerschaum/core/Pipe/_verify.py,sha256=c3HvsZd4QPydqozaV6cDDRtwYiNz4V91b0IcnKvcimA,14158
|
210
210
|
meerschaum/core/Plugin/__init__.py,sha256=UXg64EvJPgI1PCxkY_KM02-ZmBm4FZpLPIQR_uSJJDc,137
|
211
|
-
meerschaum/core/User/_User.py,sha256=
|
212
|
-
meerschaum/core/User/__init__.py,sha256=
|
211
|
+
meerschaum/core/User/_User.py,sha256=qbI0GIkr3G0PI4d9S49uatbJQ2kH_-z5-GoVJ0fuEtA,6624
|
212
|
+
meerschaum/core/User/__init__.py,sha256=9qNy-Gobui4x6GiaE8U7-WOggsdniOM3_wegLN3SVKs,988
|
213
213
|
meerschaum/jobs/_Executor.py,sha256=qM62BhFTM4tyJ7p90KOM0y3qyeRY9k3ZV_aTDJMHnO8,1682
|
214
214
|
meerschaum/jobs/_Job.py,sha256=hkjHqG5YPej5rC4nwdU7Ay_mjep9Fy4HO5B-eqdBdfo,31984
|
215
215
|
meerschaum/jobs/__init__.py,sha256=q0f_2zWw91sAyafP50IgMM06abe-BIYSR_SCWmI4W3E,12177
|
@@ -229,11 +229,11 @@ meerschaum/utils/process.py,sha256=9O8PPPJjY9Q5W2f39I3B3lFU6TlSiRiI3bgrzdOOyOw,7
|
|
229
229
|
meerschaum/utils/prompt.py,sha256=6J--mZJ_NcEdSX6KMjtY4fXXezyILLHP24VdxFFqOIc,18985
|
230
230
|
meerschaum/utils/schedule.py,sha256=9BQGEzDbInLAU1aFO-FvL3wKu9XCTUpS0V_aQID6xzc,11228
|
231
231
|
meerschaum/utils/sql.py,sha256=TAsHcUXg2RN3UfwMh3V8U5MtBrTn1VCIvikUAwsw3q4,72164
|
232
|
-
meerschaum/utils/threading.py,sha256=
|
232
|
+
meerschaum/utils/threading.py,sha256=awjbVL_QR6G-o_9Qk85utac9cSdqkiC8tQSdERCdrG8,2814
|
233
233
|
meerschaum/utils/typing.py,sha256=U3MC347sh1umpa3Xr1k71eADyDmk4LB6TnVCpq8dVzI,2830
|
234
234
|
meerschaum/utils/warnings.py,sha256=n-phr3BftNNgyPnvnXC_VMSjtCvjiCZ-ewmVfcROhkc,6611
|
235
235
|
meerschaum/utils/yaml.py,sha256=PoC1du0pn2hLwTHwL-zuOf_EBWZSbCGOz-P-AZ4BWN0,3901
|
236
|
-
meerschaum/utils/daemon/Daemon.py,sha256=
|
236
|
+
meerschaum/utils/daemon/Daemon.py,sha256=Wj4IkcKb4NEgwPTSwf8_sKlKpbavlX5z4NPPcWnAS1k,42395
|
237
237
|
meerschaum/utils/daemon/FileDescriptorInterceptor.py,sha256=MJKMO0Syf3d8yWUs6xXcQzg8Ptsuvh2aCRRoglOjusA,5257
|
238
238
|
meerschaum/utils/daemon/RotatingFile.py,sha256=ePm_svjwyFDWh6V1k-bp1RHXCSWlyxDtlFu4SU4XvPU,24369
|
239
239
|
meerschaum/utils/daemon/StdinFile.py,sha256=J6tyUReM8NEp3bBQAxMfe8mjJG5mWi6CzHN4x86VQBI,3237
|
@@ -247,15 +247,15 @@ meerschaum/utils/formatting/_pipes.py,sha256=840O5rg2aHhQoraCDOh2ZtBo43_W2W6R60y
|
|
247
247
|
meerschaum/utils/formatting/_pprint.py,sha256=tgrT3FyGyu5CWJYysqK3kX1xdZYorlbOk9fcU_vt9Qg,3096
|
248
248
|
meerschaum/utils/formatting/_shell.py,sha256=XH7VFLteNv7NGtWhJl7FdIGt80sKeTiDoJokGSDAwBM,3761
|
249
249
|
meerschaum/utils/packages/__init__.py,sha256=Op93VJkAX3OL4H-js_p3dAaa_PT82jvjCna27aHOsUk,64199
|
250
|
-
meerschaum/utils/packages/_packages.py,sha256=
|
250
|
+
meerschaum/utils/packages/_packages.py,sha256=XTdIiPDDxcPqC0qEFveeEN4gmEjfwwWILQGhELP4IVQ,8868
|
251
251
|
meerschaum/utils/packages/lazy_loader.py,sha256=VHnph3VozH29R4JnSSBfwtA5WKZYZQFT_GeQSShCnuc,2540
|
252
252
|
meerschaum/utils/venv/_Venv.py,sha256=sBnlmxHdAh2bx8btfVoD79-H9-cYsv5lP02IIXkyECs,3553
|
253
253
|
meerschaum/utils/venv/__init__.py,sha256=f3oi67lXYPLKJrnRW9lae7M3A8SFiC7DzaMoBdCVUFs,24609
|
254
|
-
meerschaum-2.6.
|
255
|
-
meerschaum-2.6.
|
256
|
-
meerschaum-2.6.
|
257
|
-
meerschaum-2.6.
|
258
|
-
meerschaum-2.6.
|
259
|
-
meerschaum-2.6.
|
260
|
-
meerschaum-2.6.
|
261
|
-
meerschaum-2.6.
|
254
|
+
meerschaum-2.6.13.dist-info/LICENSE,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
|
255
|
+
meerschaum-2.6.13.dist-info/METADATA,sha256=KtiOaApFspAVgL6VCe3DPJL2W8rI8B_T2ywEwHn0RWM,24935
|
256
|
+
meerschaum-2.6.13.dist-info/NOTICE,sha256=OTA9Fcthjf5BRvWDDIcBC_xfLpeDV-RPZh3M-HQBRtQ,114
|
257
|
+
meerschaum-2.6.13.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
|
258
|
+
meerschaum-2.6.13.dist-info/entry_points.txt,sha256=5YBVzibw-0rNA_1VjB16z5GABsOGf-CDhW4yqH8C7Gc,88
|
259
|
+
meerschaum-2.6.13.dist-info/top_level.txt,sha256=bNoSiDj0El6buocix-FRoAtJOeq1qOF5rRm2u9i7Q6A,11
|
260
|
+
meerschaum-2.6.13.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
261
|
+
meerschaum-2.6.13.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|