meerschaum 2.9.5__py3-none-any.whl → 3.0.0rc1__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 +17 -1
- meerschaum/_internal/entry.py +6 -6
- meerschaum/_internal/shell/Shell.py +1 -1
- meerschaum/_internal/static.py +372 -0
- meerschaum/actions/api.py +12 -2
- meerschaum/actions/bootstrap.py +7 -7
- meerschaum/actions/edit.py +142 -18
- meerschaum/actions/register.py +137 -6
- meerschaum/actions/show.py +117 -29
- meerschaum/actions/stop.py +4 -1
- meerschaum/actions/sync.py +1 -1
- meerschaum/actions/tag.py +9 -8
- meerschaum/api/__init__.py +9 -2
- meerschaum/api/_events.py +39 -2
- meerschaum/api/_oauth2.py +118 -8
- meerschaum/api/_tokens.py +102 -0
- meerschaum/api/dash/__init__.py +0 -1
- meerschaum/api/dash/callbacks/custom.py +2 -2
- meerschaum/api/dash/callbacks/dashboard.py +102 -18
- meerschaum/api/dash/callbacks/plugins.py +0 -1
- meerschaum/api/dash/callbacks/register.py +1 -1
- meerschaum/api/dash/callbacks/settings/__init__.py +1 -0
- meerschaum/api/dash/callbacks/settings/password_reset.py +2 -2
- meerschaum/api/dash/callbacks/settings/tokens.py +388 -0
- meerschaum/api/dash/components.py +30 -8
- meerschaum/api/dash/keys.py +19 -93
- meerschaum/api/dash/pages/dashboard.py +1 -20
- meerschaum/api/dash/pages/settings/__init__.py +1 -0
- meerschaum/api/dash/pages/settings/password_reset.py +1 -1
- meerschaum/api/dash/pages/settings/tokens.py +55 -0
- meerschaum/api/dash/pipes.py +94 -59
- meerschaum/api/dash/sessions.py +12 -0
- meerschaum/api/dash/tokens.py +606 -0
- meerschaum/api/dash/websockets.py +1 -1
- meerschaum/api/dash/webterm.py +4 -0
- meerschaum/api/models/__init__.py +23 -3
- meerschaum/api/models/_actions.py +22 -0
- meerschaum/api/models/_pipes.py +85 -7
- meerschaum/api/models/_tokens.py +81 -0
- meerschaum/api/resources/templates/termpage.html +12 -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 +14 -35
- meerschaum/api/routes/_login.py +49 -12
- meerschaum/api/routes/_misc.py +5 -10
- meerschaum/api/routes/_pipes.py +134 -111
- 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/config/__init__.py +43 -20
- meerschaum/config/_default.py +32 -5
- meerschaum/config/_edit.py +28 -24
- meerschaum/config/_environment.py +1 -1
- meerschaum/config/_patch.py +6 -6
- meerschaum/config/_paths.py +5 -1
- meerschaum/config/_read_config.py +65 -34
- meerschaum/config/_sync.py +6 -3
- meerschaum/config/_version.py +1 -1
- meerschaum/config/stack/__init__.py +24 -5
- meerschaum/config/static.py +18 -0
- meerschaum/connectors/_Connector.py +10 -4
- meerschaum/connectors/__init__.py +4 -20
- meerschaum/connectors/api/_APIConnector.py +34 -6
- meerschaum/connectors/api/_actions.py +2 -2
- meerschaum/connectors/api/_jobs.py +1 -1
- meerschaum/connectors/api/_login.py +33 -7
- meerschaum/connectors/api/_misc.py +2 -2
- meerschaum/connectors/api/_pipes.py +15 -14
- 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 +151 -0
- meerschaum/connectors/instance/_tokens.py +296 -0
- meerschaum/connectors/instance/_users.py +181 -0
- meerschaum/connectors/parse.py +4 -1
- meerschaum/connectors/sql/_SQLConnector.py +8 -5
- meerschaum/connectors/sql/_cli.py +12 -11
- meerschaum/connectors/sql/_create_engine.py +6 -154
- meerschaum/connectors/sql/_fetch.py +2 -18
- meerschaum/connectors/sql/_pipes.py +42 -31
- meerschaum/connectors/sql/_plugins.py +29 -0
- meerschaum/connectors/sql/_sql.py +8 -1
- meerschaum/connectors/sql/_users.py +29 -2
- meerschaum/connectors/sql/tables/__init__.py +1 -1
- meerschaum/connectors/valkey/_ValkeyConnector.py +2 -4
- meerschaum/connectors/valkey/_pipes.py +9 -10
- meerschaum/connectors/valkey/_plugins.py +2 -26
- meerschaum/core/Pipe/__init__.py +31 -14
- meerschaum/core/Pipe/_attributes.py +156 -58
- meerschaum/core/Pipe/_bootstrap.py +54 -24
- meerschaum/core/Pipe/_data.py +41 -1
- meerschaum/core/Pipe/_dtypes.py +29 -14
- meerschaum/core/Pipe/_edit.py +12 -4
- meerschaum/core/Pipe/_show.py +5 -5
- meerschaum/core/Pipe/_sync.py +48 -53
- meerschaum/core/Pipe/_verify.py +1 -1
- meerschaum/{plugins → core/Plugin}/_Plugin.py +9 -11
- meerschaum/core/Plugin/__init__.py +1 -1
- meerschaum/core/Token/_Token.py +221 -0
- meerschaum/core/Token/__init__.py +12 -0
- meerschaum/core/User/_User.py +34 -8
- meerschaum/core/User/__init__.py +9 -1
- meerschaum/core/__init__.py +1 -0
- meerschaum/jobs/_Job.py +3 -2
- meerschaum/jobs/__init__.py +3 -2
- meerschaum/jobs/systemd.py +1 -1
- 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 +22 -7
- meerschaum/plugins/bootstrap.py +2 -1
- meerschaum/utils/_get_pipes.py +68 -27
- meerschaum/utils/daemon/Daemon.py +2 -1
- meerschaum/utils/daemon/__init__.py +30 -2
- meerschaum/utils/dataframe.py +95 -14
- meerschaum/utils/dtypes/__init__.py +91 -18
- meerschaum/utils/dtypes/sql.py +44 -0
- meerschaum/utils/formatting/__init__.py +1 -1
- meerschaum/utils/formatting/_pipes.py +5 -4
- meerschaum/utils/formatting/_shell.py +11 -9
- meerschaum/utils/misc.py +237 -80
- meerschaum/utils/packages/__init__.py +3 -6
- meerschaum/utils/packages/_packages.py +34 -32
- meerschaum/utils/pipes.py +181 -0
- meerschaum/utils/process.py +1 -1
- meerschaum/utils/prompt.py +3 -1
- meerschaum/utils/schedule.py +1 -0
- meerschaum/utils/sql.py +114 -37
- meerschaum/utils/typing.py +1 -4
- meerschaum/utils/venv/_Venv.py +2 -2
- meerschaum/utils/venv/__init__.py +5 -7
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc1.dist-info}/METADATA +88 -80
- meerschaum-3.0.0rc1.dist-info/RECORD +282 -0
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc1.dist-info}/WHEEL +1 -1
- meerschaum/api/models/_interfaces.py +0 -15
- meerschaum/api/models/_locations.py +0 -15
- meerschaum/api/models/_metrics.py +0 -15
- meerschaum/config/static/__init__.py +0 -186
- meerschaum-2.9.5.dist-info/RECORD +0 -263
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc1.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc1.dist-info}/licenses/LICENSE +0 -0
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc1.dist-info}/top_level.txt +0 -0
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc1.dist-info}/zip-safe +0 -0
@@ -0,0 +1,247 @@
|
|
1
|
+
#! /usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# vim:fenc=utf-8
|
4
|
+
|
5
|
+
"""
|
6
|
+
Pydantic model for a pipe's keys.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from __future__ import annotations
|
10
|
+
|
11
|
+
from typing import Optional, List, Tuple, Dict, Any
|
12
|
+
|
13
|
+
import meerschaum as mrsm
|
14
|
+
|
15
|
+
pydantic = mrsm.attempt_import('pydantic', lazy=False)
|
16
|
+
from pydantic import (
|
17
|
+
BaseModel,
|
18
|
+
RootModel,
|
19
|
+
field_validator,
|
20
|
+
ValidationInfo,
|
21
|
+
ConfigDict,
|
22
|
+
)
|
23
|
+
|
24
|
+
|
25
|
+
class ConnectorKeysModel(RootModel[str]):
|
26
|
+
"""
|
27
|
+
Validate the connector keys:
|
28
|
+
- May not begin with an underscore (_).
|
29
|
+
- Must be at least one character long.
|
30
|
+
- May contain one or zero colons (:).
|
31
|
+
"""
|
32
|
+
model_config = ConfigDict(
|
33
|
+
frozen=True,
|
34
|
+
json_schema_extra={
|
35
|
+
'example': 'sql:main',
|
36
|
+
},
|
37
|
+
)
|
38
|
+
@field_validator('root')
|
39
|
+
@classmethod
|
40
|
+
def validate_connector_keys(cls, v: str, info: ValidationInfo) -> str:
|
41
|
+
"""Validate the connector keys."""
|
42
|
+
if not v:
|
43
|
+
raise ValueError("Connector keys must be at least one character long.")
|
44
|
+
if v.startswith('_'):
|
45
|
+
raise ValueError("Connector keys may not begin with an underscore.")
|
46
|
+
if v.count(':') > 1:
|
47
|
+
raise ValueError("Connector keys may contain at most one colon.")
|
48
|
+
return v
|
49
|
+
|
50
|
+
|
51
|
+
class MetricKeyModel(RootModel[str]):
|
52
|
+
"""
|
53
|
+
Validate the metric key:
|
54
|
+
|
55
|
+
- May not begin with an underscore (_).
|
56
|
+
- Must be at least one character long.
|
57
|
+
"""
|
58
|
+
model_config = ConfigDict(
|
59
|
+
frozen=True,
|
60
|
+
json_schema_extra={
|
61
|
+
'example': 'weather',
|
62
|
+
},
|
63
|
+
)
|
64
|
+
@field_validator('root')
|
65
|
+
@classmethod
|
66
|
+
def validate_metric_key(cls, v: str, info: ValidationInfo) -> str:
|
67
|
+
"""Validate the metric key."""
|
68
|
+
if not v:
|
69
|
+
raise ValueError("Metric key must be at least one character long.")
|
70
|
+
if v.startswith('_'):
|
71
|
+
raise ValueError("Metric key may not begin with an underscore.")
|
72
|
+
return v
|
73
|
+
|
74
|
+
|
75
|
+
class LocationKeyModel(RootModel[Optional[str]]):
|
76
|
+
"""
|
77
|
+
Validate the location key:
|
78
|
+
|
79
|
+
- May not begin with an underscore (_).
|
80
|
+
- May be null (`None`).
|
81
|
+
- If not null, must be at least one character long.
|
82
|
+
"""
|
83
|
+
model_config = ConfigDict(
|
84
|
+
frozen=True,
|
85
|
+
json_schema_extra={
|
86
|
+
'example': 'us.co.denver',
|
87
|
+
},
|
88
|
+
)
|
89
|
+
@field_validator('root')
|
90
|
+
@classmethod
|
91
|
+
def validate_location_key(cls, v: Optional[str], info: ValidationInfo) -> Optional[str]:
|
92
|
+
"""Validate the location key."""
|
93
|
+
if v is None:
|
94
|
+
return v
|
95
|
+
if not v:
|
96
|
+
raise ValueError("Location key must be at least one character long if not null.")
|
97
|
+
if v.startswith('_'):
|
98
|
+
raise ValueError("Location key may not begin with an underscore.")
|
99
|
+
return v
|
100
|
+
|
101
|
+
|
102
|
+
class InstanceKeysModel(RootModel[str]):
|
103
|
+
"""
|
104
|
+
Validate the instance keys. The instance keys are connector keys which must have one colon
|
105
|
+
(e.g. `'sql:main'`).
|
106
|
+
"""
|
107
|
+
model_config = ConfigDict(
|
108
|
+
frozen=True,
|
109
|
+
json_schema_extra={
|
110
|
+
'example': 'sql:main',
|
111
|
+
},
|
112
|
+
)
|
113
|
+
@field_validator('root')
|
114
|
+
@classmethod
|
115
|
+
def validate_instance_keys(cls, v: str, info: ValidationInfo) -> str:
|
116
|
+
"""Validate the instance keys."""
|
117
|
+
if not v:
|
118
|
+
raise ValueError("Instance keys must be at least one character long.")
|
119
|
+
if v.startswith('_'):
|
120
|
+
raise ValueError("Instance keys may not begin with an underscore.")
|
121
|
+
if v.count(':') != 1:
|
122
|
+
raise ValueError("Instance keys must contain exactly one colon.")
|
123
|
+
return v
|
124
|
+
|
125
|
+
|
126
|
+
class PipeModel(BaseModel):
|
127
|
+
"""
|
128
|
+
Define the four components to uniquely identify a pipe.
|
129
|
+
"""
|
130
|
+
connector_keys: ConnectorKeysModel
|
131
|
+
metric_key: MetricKeyModel
|
132
|
+
location_key: Optional[LocationKeyModel] = None
|
133
|
+
instance_keys: Optional[InstanceKeysModel] = None
|
134
|
+
model_config = ConfigDict(
|
135
|
+
json_schema_extra={
|
136
|
+
'example': {
|
137
|
+
'connector_keys': 'sql:main',
|
138
|
+
'metric_key': 'weather',
|
139
|
+
'location_key': 'atl',
|
140
|
+
'instance_keys': 'sql:main',
|
141
|
+
},
|
142
|
+
},
|
143
|
+
)
|
144
|
+
|
145
|
+
|
146
|
+
class PipeWithParametersModel(PipeModel):
|
147
|
+
"""
|
148
|
+
A Pipe's model including its parameters dictionary.
|
149
|
+
"""
|
150
|
+
parameters: Dict[str, Any]
|
151
|
+
model_config = ConfigDict(
|
152
|
+
json_schema_extra={
|
153
|
+
'example': {
|
154
|
+
'connector_keys': 'sql:main',
|
155
|
+
'metric_key': 'weather',
|
156
|
+
'location_key': 'atl',
|
157
|
+
'instance_keys': 'sql:main',
|
158
|
+
'parameters': {
|
159
|
+
'columns': {
|
160
|
+
'datetime': 'dt',
|
161
|
+
'id': 'id',
|
162
|
+
},
|
163
|
+
},
|
164
|
+
},
|
165
|
+
},
|
166
|
+
)
|
167
|
+
|
168
|
+
class PipesWithParametersDictModel(
|
169
|
+
RootModel[
|
170
|
+
Dict[
|
171
|
+
str,
|
172
|
+
Dict[
|
173
|
+
str,
|
174
|
+
Dict[
|
175
|
+
str,
|
176
|
+
PipeWithParametersModel
|
177
|
+
]
|
178
|
+
]
|
179
|
+
]
|
180
|
+
]
|
181
|
+
):
|
182
|
+
"""
|
183
|
+
A dictionary of pipes' parameters, nested by connector, metric, and location keys.
|
184
|
+
"""
|
185
|
+
@field_validator('root')
|
186
|
+
@classmethod
|
187
|
+
def validate_keys(cls, v: dict, info: ValidationInfo) -> dict:
|
188
|
+
"""
|
189
|
+
Validate the dictionary keys.
|
190
|
+
"""
|
191
|
+
for c_key, metrics in v.items():
|
192
|
+
ConnectorKeysModel(root=c_key)
|
193
|
+
for m_key, locations in metrics.items():
|
194
|
+
MetricKeyModel(root=m_key)
|
195
|
+
for l_key in locations:
|
196
|
+
LocationKeyModel(root=l_key if l_key not in ('None', 'null', '[None]') else None)
|
197
|
+
return v
|
198
|
+
|
199
|
+
model_config = ConfigDict(
|
200
|
+
json_schema_extra={
|
201
|
+
'example': {
|
202
|
+
"plugin:noaa": {
|
203
|
+
"weather": {
|
204
|
+
"None": {
|
205
|
+
"pipe_id": 1,
|
206
|
+
"connector_keys": "plugin:noaa",
|
207
|
+
"metric_key": "weather",
|
208
|
+
"location_key": "clemson",
|
209
|
+
"parameters": {
|
210
|
+
"columns": {
|
211
|
+
"datetime": "timestamp",
|
212
|
+
"id": "station"
|
213
|
+
},
|
214
|
+
"noaa": {
|
215
|
+
"stations": {
|
216
|
+
"KCEU": {
|
217
|
+
"name": "Clemson, Clemson-Oconee County Airport",
|
218
|
+
"geometry": {
|
219
|
+
"type": "Point",
|
220
|
+
"coordinates": [
|
221
|
+
-82.88139,
|
222
|
+
34.67222
|
223
|
+
]
|
224
|
+
}
|
225
|
+
}
|
226
|
+
}
|
227
|
+
},
|
228
|
+
"verify": {
|
229
|
+
"chunk_minutes": 20160
|
230
|
+
},
|
231
|
+
"target": "plugin_noaa_weather",
|
232
|
+
"tags": [],
|
233
|
+
"dtypes": {
|
234
|
+
"timestamp": "datetime",
|
235
|
+
"geometry": "json",
|
236
|
+
"cloudLayers": "json",
|
237
|
+
"presentWeather": "json"
|
238
|
+
},
|
239
|
+
"static": False,
|
240
|
+
"enforce": True
|
241
|
+
}
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
},
|
246
|
+
},
|
247
|
+
)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# vim:fenc=utf-8
|
3
|
+
|
4
|
+
"""
|
5
|
+
Define Pydantic models for tokens.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import uuid
|
9
|
+
from typing import Optional, List, Union
|
10
|
+
from datetime import datetime
|
11
|
+
|
12
|
+
import meerschaum as mrsm
|
13
|
+
|
14
|
+
pydantic = mrsm.attempt_import('pydantic', lazy=False)
|
15
|
+
from pydantic import (
|
16
|
+
BaseModel,
|
17
|
+
RootModel,
|
18
|
+
field_validator,
|
19
|
+
ValidationInfo,
|
20
|
+
ConfigDict,
|
21
|
+
Field,
|
22
|
+
)
|
23
|
+
from meerschaum.models.users import UserModel
|
24
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
25
|
+
|
26
|
+
|
27
|
+
class TokenModel(BaseModel):
|
28
|
+
"""Pydantic model for a Meerschaum token."""
|
29
|
+
model_config = ConfigDict(from_attributes=True)
|
30
|
+
|
31
|
+
id: Optional[uuid.UUID] = Field(default=None)
|
32
|
+
creation: Optional[datetime] = Field(default=None)
|
33
|
+
expiration: Optional[datetime] = Field(default=None)
|
34
|
+
label: Optional[str] = Field(default=None)
|
35
|
+
user_id: Optional[Union[int, uuid.UUID]] = Field(default=None)
|
36
|
+
secret_hash: Optional[str] = Field(default=None)
|
37
|
+
scopes: Optional[List[str]] = Field(default=list(STATIC_CONFIG['tokens']['scopes']))
|
38
|
+
is_valid: bool = Field(default=True)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# vim:fenc=utf-8
|
3
|
+
|
4
|
+
"""
|
5
|
+
Define Pydantic models for users.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from __future__ import annotations
|
9
|
+
from typing import Optional, Dict, Any, Union
|
10
|
+
import uuid
|
11
|
+
|
12
|
+
import meerschaum as mrsm
|
13
|
+
|
14
|
+
pydantic = mrsm.attempt_import('pydantic', lazy=False)
|
15
|
+
from pydantic import BaseModel, Field, ConfigDict
|
16
|
+
|
17
|
+
|
18
|
+
class UserModel(BaseModel):
|
19
|
+
"""Pydantic model for a Meerschaum User."""
|
20
|
+
model_config = ConfigDict(from_attributes=True)
|
21
|
+
|
22
|
+
user_id: Optional[Union[int, uuid.UUID]] = Field(default=None)
|
23
|
+
username: str
|
24
|
+
email: Optional[str] = Field(default=None)
|
25
|
+
type: Optional[str] = Field(default=None)
|
26
|
+
attributes: Optional[Dict[str, Any]] = Field(default=None)
|
meerschaum/plugins/__init__.py
CHANGED
@@ -7,11 +7,13 @@ Expose plugin management APIs from the `meerschaum.plugins` module.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
+
|
10
11
|
import functools
|
12
|
+
|
11
13
|
import meerschaum as mrsm
|
12
14
|
from meerschaum.utils.typing import Callable, Any, Union, Optional, Dict, List, Tuple
|
13
15
|
from meerschaum.utils.threading import Lock, RLock
|
14
|
-
from meerschaum.
|
16
|
+
from meerschaum.core.Plugin import Plugin
|
15
17
|
|
16
18
|
_api_plugins: Dict[str, List[Callable[['fastapi.App'], Any]]] = {}
|
17
19
|
_pre_sync_hooks: Dict[str, List[Callable[[Any], Any]]] = {}
|
@@ -28,15 +30,28 @@ _locks = {
|
|
28
30
|
'PLUGINS_INTERNAL_LOCK_PATH': RLock(),
|
29
31
|
}
|
30
32
|
__all__ = (
|
31
|
-
"Plugin",
|
32
|
-
"
|
33
|
-
"
|
34
|
-
"
|
33
|
+
"Plugin",
|
34
|
+
"make_action",
|
35
|
+
"api_plugin",
|
36
|
+
"dash_plugin",
|
37
|
+
"web_page",
|
38
|
+
"import_plugins",
|
39
|
+
"from_plugin_import",
|
40
|
+
"reload_plugins",
|
41
|
+
"get_plugins",
|
42
|
+
"get_data_plugins",
|
43
|
+
"add_plugin_argument",
|
44
|
+
"pre_sync_hook",
|
45
|
+
"post_sync_hook",
|
35
46
|
)
|
36
47
|
__pdoc__ = {
|
37
|
-
'venvs': False,
|
48
|
+
'venvs': False,
|
49
|
+
'data': False,
|
50
|
+
'stack': False,
|
51
|
+
'plugins': False,
|
38
52
|
}
|
39
53
|
|
54
|
+
|
40
55
|
def make_action(
|
41
56
|
function: Callable[[Any], Any],
|
42
57
|
shell: bool = False,
|
@@ -298,7 +313,7 @@ def sync_plugins_symlinks(debug: bool = False, warn: bool = True) -> None:
|
|
298
313
|
import importlib.util
|
299
314
|
from meerschaum.utils.misc import flatten_list, make_symlink, is_symlink
|
300
315
|
from meerschaum.utils.warnings import error, warn as _warn
|
301
|
-
from meerschaum.
|
316
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
302
317
|
from meerschaum.utils.venv import Venv, activate_venv, deactivate_venv, is_venv_active
|
303
318
|
from meerschaum.config._paths import (
|
304
319
|
PLUGINS_RESOURCES_PATH,
|
meerschaum/plugins/bootstrap.py
CHANGED
@@ -129,9 +129,10 @@ FEATURE_LINES: Dict[str, str] = {
|
|
129
129
|
" import dash.html as html\n"
|
130
130
|
" import dash.dcc as dcc\n"
|
131
131
|
" from dash import Input, Output, State, no_update\n"
|
132
|
+
" from dash.exceptions import PreventUpdate\n"
|
132
133
|
" import dash_bootstrap_components as dbc\n\n"
|
133
134
|
" # Create a new page at the path `/dash/{plugin_name}`.\n"
|
134
|
-
" @web_page('{plugin_name}', login_required=False)\n"
|
135
|
+
" @web_page('{plugin_name}', page_group='{plugin_name}', login_required=False)\n"
|
135
136
|
" def page_layout():\n"
|
136
137
|
" \"\"\"Return the layout objects for this page.\"\"\"\n"
|
137
138
|
" return dbc.Container([\n"
|
meerschaum/utils/_get_pipes.py
CHANGED
@@ -10,11 +10,21 @@ from __future__ import annotations
|
|
10
10
|
|
11
11
|
import meerschaum as mrsm
|
12
12
|
from meerschaum.utils.typing import (
|
13
|
-
Sequence,
|
13
|
+
Sequence,
|
14
|
+
Optional,
|
15
|
+
Union,
|
16
|
+
Mapping,
|
17
|
+
Any,
|
18
|
+
PipesDict,
|
19
|
+
List,
|
20
|
+
Dict,
|
21
|
+
Tuple,
|
22
|
+
InstanceConnector,
|
14
23
|
)
|
15
24
|
|
16
25
|
__pdoc__ = {'get_pipes': True, 'fetch_pipes_keys': True}
|
17
26
|
|
27
|
+
|
18
28
|
def get_pipes(
|
19
29
|
connector_keys: Union[str, List[str], None] = None,
|
20
30
|
metric_keys: Union[str, List[str], None] = None,
|
@@ -24,10 +34,12 @@ def get_pipes(
|
|
24
34
|
mrsm_instance: Union[str, InstanceConnector, None] = None,
|
25
35
|
instance: Union[str, InstanceConnector, None] = None,
|
26
36
|
as_list: bool = False,
|
37
|
+
as_tags_dict: bool = False,
|
27
38
|
method: str = 'registered',
|
39
|
+
workers: Optional[int] = None,
|
28
40
|
debug: bool = False,
|
29
41
|
**kw: Any
|
30
|
-
) -> Union[PipesDict, List[mrsm.Pipe]]:
|
42
|
+
) -> Union[PipesDict, List[mrsm.Pipe], Dict[str, mrsm.Pipe]]:
|
31
43
|
"""
|
32
44
|
Return a dictionary or list of `meerschaum.Pipe` objects.
|
33
45
|
|
@@ -62,6 +74,10 @@ def get_pipes(
|
|
62
74
|
`False` : `{connector_keys: {metric_key: {location_key: Pipe}}}`
|
63
75
|
`True` : `[Pipe]`
|
64
76
|
|
77
|
+
as_tags_dict: bool, default False
|
78
|
+
If `True`, return a dictionary mapping tags to pipes.
|
79
|
+
Pipes with multiple tags will be repeated.
|
80
|
+
|
65
81
|
method: str, default 'registered'
|
66
82
|
Available options: `['registered', 'explicit', 'all']`
|
67
83
|
If `'registered'` (default), create pipes based on registered keys in the connector's pipes table
|
@@ -71,6 +87,11 @@ def get_pipes(
|
|
71
87
|
If `'all'`, create pipes from predefined metrics and locations. Required `connector_keys`.
|
72
88
|
**NOTE:** Method `'all'` is not implemented!
|
73
89
|
|
90
|
+
workers: Optional[int], default None
|
91
|
+
If provided (and `as_tags_dict` is `True`), set the number of workers for the pool
|
92
|
+
to fetch tags.
|
93
|
+
Only takes effect if the instance connector supports multi-threading
|
94
|
+
|
74
95
|
**kw: Any:
|
75
96
|
Keyword arguments to pass to the `meerschaum.Pipe` constructor.
|
76
97
|
|
@@ -80,6 +101,7 @@ def get_pipes(
|
|
80
101
|
A dictionary of dictionaries and `meerschaum.Pipe` objects
|
81
102
|
in the connector, metric, location hierarchy.
|
82
103
|
If `as_list` is `True`, return a list of `meerschaum.Pipe` objects.
|
104
|
+
If `as_tags_dict` is `True`, return a dictionary mapping tags to pipes.
|
83
105
|
|
84
106
|
Examples
|
85
107
|
--------
|
@@ -100,14 +122,17 @@ def get_pipes(
|
|
100
122
|
>>> pipes['sql:main']['weather'][None]
|
101
123
|
>>> ### Return a list instead:
|
102
124
|
>>> get_pipes(as_list=True)
|
103
|
-
[
|
104
|
-
>>>
|
125
|
+
[Pipe('sql:main', 'weather')]
|
126
|
+
>>> get_pipes(as_tags_dict=True)
|
127
|
+
{'gvl': Pipe('sql:main', 'weather')}
|
105
128
|
```
|
106
129
|
"""
|
107
130
|
|
108
131
|
from meerschaum.config import get_config
|
109
132
|
from meerschaum.utils.warnings import error
|
110
133
|
from meerschaum.utils.misc import filter_keywords
|
134
|
+
from meerschaum.utils.pool import get_pool
|
135
|
+
from collections import defaultdict
|
111
136
|
|
112
137
|
if connector_keys is None:
|
113
138
|
connector_keys = []
|
@@ -159,6 +184,7 @@ def get_pipes(
|
|
159
184
|
location_keys = location_keys,
|
160
185
|
tags = tags,
|
161
186
|
params = params,
|
187
|
+
workers = workers,
|
162
188
|
debug = debug
|
163
189
|
)
|
164
190
|
if result is None:
|
@@ -182,17 +208,32 @@ def get_pipes(
|
|
182
208
|
**filter_keywords(Pipe, **kw)
|
183
209
|
)
|
184
210
|
|
185
|
-
if not as_list:
|
211
|
+
if not as_list and not as_tags_dict:
|
186
212
|
return pipes
|
213
|
+
|
187
214
|
from meerschaum.utils.misc import flatten_pipes_dict
|
188
|
-
|
215
|
+
pipes_list = flatten_pipes_dict(pipes)
|
216
|
+
if as_list:
|
217
|
+
return pipes_list
|
218
|
+
|
219
|
+
pool = get_pool(workers=(workers if connector.IS_THREAD_SAFE else 1))
|
220
|
+
def gather_pipe_tags(pipe: mrsm.Pipe) -> Tuple[mrsm.Pipe, List[str]]:
|
221
|
+
return pipe, (pipe.tags or [])
|
222
|
+
|
223
|
+
tags_pipes = defaultdict(lambda: [])
|
224
|
+
pipes_tags = dict(pool.map(gather_pipe_tags, pipes_list))
|
225
|
+
for pipe, tags in pipes_tags.items():
|
226
|
+
for tag in (tags or []):
|
227
|
+
tags_pipes[tag].append(pipe)
|
228
|
+
|
229
|
+
return dict(tags_pipes)
|
189
230
|
|
190
231
|
|
191
232
|
def fetch_pipes_keys(
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
233
|
+
method: str,
|
234
|
+
connector: 'mrsm.connectors.InstanceConnector',
|
235
|
+
**kw: Any
|
236
|
+
) -> List[Tuple[str, str, str]]:
|
196
237
|
"""
|
197
238
|
Fetch keys for pipes according to a method.
|
198
239
|
|
@@ -201,7 +242,7 @@ def fetch_pipes_keys(
|
|
201
242
|
method: str
|
202
243
|
The method by which to fetch the keys. See `get_pipes()` above.
|
203
244
|
|
204
|
-
connector: meerschaum.connectors.
|
245
|
+
connector: meerschaum.connectors.InstanceConnector
|
205
246
|
The connector to use to fetch the keys.
|
206
247
|
Must be of type `meerschaum.connectors.sql.SQLConnector.SQLConnector`
|
207
248
|
or `meerschaum.connectors.api.APIConnector.APIConnector`.
|
@@ -234,14 +275,14 @@ def fetch_pipes_keys(
|
|
234
275
|
from meerschaum.utils.warnings import error
|
235
276
|
|
236
277
|
def _registered(
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
278
|
+
connector_keys: Optional[List[str]] = None,
|
279
|
+
metric_keys: Optional[List[str]] = None,
|
280
|
+
location_keys: Optional[List[str]] = None,
|
281
|
+
tags: Optional[List[str]] = None,
|
282
|
+
params: Optional[Dict[str, Any]] = None,
|
283
|
+
debug: bool = False,
|
284
|
+
**kw
|
285
|
+
) -> List[Tuple[str, str, str]]:
|
245
286
|
"""
|
246
287
|
Get keys from the pipes table or the API directly.
|
247
288
|
Builds query or URL based on provided keys and parameters.
|
@@ -269,14 +310,14 @@ def fetch_pipes_keys(
|
|
269
310
|
)
|
270
311
|
|
271
312
|
def _explicit(
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
313
|
+
connector_keys: Optional[List[str]] = None,
|
314
|
+
metric_keys: Optional[List[str]] = None,
|
315
|
+
location_keys: Optional[List[str]] = None,
|
316
|
+
params: Optional[Dict[str, Any]] = None,
|
317
|
+
tags: Optional[List[str]] = None,
|
318
|
+
debug: bool = False,
|
319
|
+
**kw
|
320
|
+
) -> List[Tuple[str, str, str]]:
|
280
321
|
"""
|
281
322
|
Explicitly build Pipes based on provided keys.
|
282
323
|
Raises an error if `connector_keys` or `metric_keys` is empty,
|
@@ -24,7 +24,7 @@ from meerschaum.utils.typing import (
|
|
24
24
|
is_success_tuple, Tuple,
|
25
25
|
)
|
26
26
|
from meerschaum.config import get_config
|
27
|
-
from meerschaum.
|
27
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
28
28
|
from meerschaum.config._paths import (
|
29
29
|
DAEMON_RESOURCES_PATH, LOGS_RESOURCES_PATH, DAEMON_ERROR_LOG_PATH,
|
30
30
|
)
|
@@ -338,6 +338,7 @@ class Daemon:
|
|
338
338
|
result = False, str(e)
|
339
339
|
finally:
|
340
340
|
_results[self.daemon_id] = result
|
341
|
+
self.properties['result'] = result
|
341
342
|
|
342
343
|
if keep_daemon_output:
|
343
344
|
self._capture_process_timestamp('ended')
|
@@ -7,7 +7,15 @@ Manage Daemons via the `Daemon` class.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
-
|
10
|
+
|
11
|
+
import os
|
12
|
+
import pathlib
|
13
|
+
import shutil
|
14
|
+
import json
|
15
|
+
import datetime
|
16
|
+
import threading
|
17
|
+
import shlex
|
18
|
+
|
11
19
|
from meerschaum.utils.typing import SuccessTuple, List, Optional, Callable, Any, Dict
|
12
20
|
from meerschaum.config._paths import DAEMON_RESOURCES_PATH
|
13
21
|
from meerschaum.utils.daemon.StdinFile import StdinFile
|
@@ -17,6 +25,26 @@ from meerschaum.utils.daemon.FileDescriptorInterceptor import FileDescriptorInte
|
|
17
25
|
from meerschaum.utils.daemon._names import get_new_daemon_name
|
18
26
|
|
19
27
|
|
28
|
+
__all__ = (
|
29
|
+
'daemon_action',
|
30
|
+
'daemon_entry',
|
31
|
+
'get_daemons',
|
32
|
+
'get_daemon_ids',
|
33
|
+
'get_running_daemons',
|
34
|
+
'get_stopped_daemons',
|
35
|
+
'get_paused_daemons',
|
36
|
+
'get_filtered_daemons',
|
37
|
+
'get_new_daemon_name',
|
38
|
+
'run_daemon',
|
39
|
+
'running_in_daemon',
|
40
|
+
'Daemon',
|
41
|
+
'StdinFile',
|
42
|
+
'RotatingFile',
|
43
|
+
'FileDescriptorInterceptor',
|
44
|
+
'DAEMON_RESOURCES_PATH',
|
45
|
+
)
|
46
|
+
|
47
|
+
|
20
48
|
def daemon_entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
|
21
49
|
"""Parse sysargs and execute a Meerschaum action as a daemon.
|
22
50
|
|
@@ -280,6 +308,6 @@ def running_in_daemon() -> bool:
|
|
280
308
|
"""
|
281
309
|
Return whether the current thread is running in a Daemon context.
|
282
310
|
"""
|
283
|
-
from meerschaum.
|
311
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
284
312
|
daemon_env_var = STATIC_CONFIG['environment']['daemon_id']
|
285
313
|
return daemon_env_var in os.environ
|