meerschaum 2.9.5__py3-none-any.whl → 3.0.0rc2__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 +19 -2
- meerschaum/_internal/docs/index.py +49 -2
- meerschaum/_internal/entry.py +6 -6
- meerschaum/_internal/shell/Shell.py +1 -1
- meerschaum/_internal/static.py +356 -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/actions/verify.py +5 -8
- meerschaum/api/__init__.py +11 -3
- meerschaum/api/_events.py +39 -2
- meerschaum/api/_oauth2.py +118 -8
- meerschaum/api/_tokens.py +102 -0
- meerschaum/api/dash/__init__.py +0 -3
- meerschaum/api/dash/callbacks/custom.py +2 -2
- meerschaum/api/dash/callbacks/dashboard.py +103 -19
- 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 +173 -140
- 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 +43 -6
- 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 +31 -11
- 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 +16 -31
- 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 +9 -168
- meerschaum/connectors/sql/_fetch.py +2 -18
- meerschaum/connectors/sql/_pipes.py +156 -190
- meerschaum/connectors/sql/_plugins.py +29 -0
- meerschaum/connectors/sql/_sql.py +46 -21
- 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 +53 -26
- meerschaum/connectors/valkey/_plugins.py +2 -26
- meerschaum/core/Pipe/__init__.py +59 -19
- meerschaum/core/Pipe/_attributes.py +412 -90
- meerschaum/core/Pipe/_bootstrap.py +54 -24
- meerschaum/core/Pipe/_data.py +96 -18
- meerschaum/core/Pipe/_dtypes.py +48 -18
- meerschaum/core/Pipe/_edit.py +14 -4
- meerschaum/core/Pipe/_fetch.py +1 -1
- meerschaum/core/Pipe/_show.py +5 -5
- meerschaum/core/Pipe/_sync.py +118 -193
- meerschaum/core/Pipe/_verify.py +4 -4
- meerschaum/{plugins → core/Plugin}/_Plugin.py +9 -11
- 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 +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 +473 -81
- meerschaum/utils/debug.py +15 -15
- meerschaum/utils/dtypes/__init__.py +473 -34
- meerschaum/utils/dtypes/sql.py +368 -28
- 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 +246 -148
- meerschaum/utils/packages/__init__.py +10 -27
- meerschaum/utils/packages/_packages.py +41 -34
- meerschaum/utils/pipes.py +181 -0
- meerschaum/utils/process.py +1 -1
- meerschaum/utils/prompt.py +3 -1
- meerschaum/utils/schedule.py +2 -1
- meerschaum/utils/sql.py +121 -44
- 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.0rc2.dist-info}/METADATA +92 -96
- meerschaum-3.0.0rc2.dist-info/RECORD +283 -0
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc2.dist-info}/WHEEL +1 -1
- meerschaum-3.0.0rc2.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/static/__init__.py +0 -186
- meerschaum-2.9.5.dist-info/RECORD +0 -263
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc2.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc2.dist-info}/licenses/LICENSE +0 -0
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc2.dist-info}/top_level.txt +0 -0
- {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc2.dist-info}/zip-safe +0 -0
@@ -75,7 +75,9 @@ def get_module_path(
|
|
75
75
|
|
76
76
|
venv_target_candidate_paths = [vtp]
|
77
77
|
if venv is None:
|
78
|
-
site_user_packages_dirs = [
|
78
|
+
site_user_packages_dirs = [
|
79
|
+
pathlib.Path(site.getusersitepackages())
|
80
|
+
] if not inside_venv() else []
|
79
81
|
site_packages_dirs = [pathlib.Path(path) for path in site.getsitepackages()]
|
80
82
|
|
81
83
|
paths_to_add = [
|
@@ -755,7 +757,7 @@ def get_pip(
|
|
755
757
|
import subprocess
|
756
758
|
from meerschaum.utils.misc import wget
|
757
759
|
from meerschaum.config._paths import CACHE_RESOURCES_PATH
|
758
|
-
from meerschaum.
|
760
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
759
761
|
url = STATIC_CONFIG['system']['urls']['get-pip.py']
|
760
762
|
dest = CACHE_RESOURCES_PATH / 'get-pip.py'
|
761
763
|
try:
|
@@ -837,7 +839,7 @@ def pip_install(
|
|
837
839
|
|
838
840
|
"""
|
839
841
|
from meerschaum.config._paths import VIRTENV_RESOURCES_PATH
|
840
|
-
from meerschaum.
|
842
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
841
843
|
from meerschaum.utils.warnings import warn
|
842
844
|
if args is None:
|
843
845
|
args = ['--upgrade'] if not _uninstall else []
|
@@ -1500,15 +1502,12 @@ def import_pandas(
|
|
1500
1502
|
def import_rich(
|
1501
1503
|
lazy: bool = True,
|
1502
1504
|
debug: bool = False,
|
1503
|
-
**kw
|
1505
|
+
**kw: Any
|
1504
1506
|
) -> 'ModuleType':
|
1505
1507
|
"""
|
1506
1508
|
Quality of life function for importing `rich`.
|
1507
1509
|
"""
|
1508
1510
|
from meerschaum.utils.formatting import ANSI, UNICODE
|
1509
|
-
if not ANSI and not UNICODE:
|
1510
|
-
return None
|
1511
|
-
|
1512
1511
|
## need typing_extensions for `from rich import box`
|
1513
1512
|
typing_extensions = attempt_import(
|
1514
1513
|
'typing_extensions', lazy=False, debug=debug
|
@@ -1773,6 +1772,10 @@ def is_installed(
|
|
1773
1772
|
allow_outside_venv: bool, default True
|
1774
1773
|
If `True`, search outside of the specified virtual environment
|
1775
1774
|
if the package cannot be found.
|
1775
|
+
|
1776
|
+
Returns
|
1777
|
+
-------
|
1778
|
+
A bool indicating whether a package may be imported.
|
1776
1779
|
"""
|
1777
1780
|
if debug:
|
1778
1781
|
from meerschaum.utils.debug import dprint
|
@@ -1864,26 +1867,6 @@ def ensure_readline() -> 'ModuleType':
|
|
1864
1867
|
sys.modules['readline'] = readline
|
1865
1868
|
return readline
|
1866
1869
|
|
1867
|
-
_pkg_resources_get_distribution = None
|
1868
|
-
_custom_distributions = {}
|
1869
|
-
def _monkey_patch_get_distribution(_dist: str, _version: str) -> None:
|
1870
|
-
"""
|
1871
|
-
Monkey patch `pkg_resources.get_distribution` to allow for importing `flask_compress`.
|
1872
|
-
"""
|
1873
|
-
import pkg_resources
|
1874
|
-
from collections import namedtuple
|
1875
|
-
global _pkg_resources_get_distribution
|
1876
|
-
with _locks['_pkg_resources_get_distribution']:
|
1877
|
-
_pkg_resources_get_distribution = pkg_resources.get_distribution
|
1878
|
-
_custom_distributions[_dist] = _version
|
1879
|
-
_Dist = namedtuple('_Dist', ['version'])
|
1880
|
-
def _get_distribution(dist):
|
1881
|
-
"""Hack for flask-compress."""
|
1882
|
-
if dist in _custom_distributions:
|
1883
|
-
return _Dist(_custom_distributions[dist])
|
1884
|
-
return _pkg_resources_get_distribution(dist)
|
1885
|
-
pkg_resources.get_distribution = _get_distribution
|
1886
|
-
|
1887
1870
|
|
1888
1871
|
def _get_pip_os_env(color: bool = True):
|
1889
1872
|
"""
|
@@ -13,8 +13,7 @@ packages dictionary is structured in the following schema:
|
|
13
13
|
}
|
14
14
|
"""
|
15
15
|
|
16
|
-
from
|
17
|
-
from meerschaum.utils.typing import Dict
|
16
|
+
from typing import Dict
|
18
17
|
|
19
18
|
_MRSM_PACKAGE_ARCHIVES_PREFIX: str = "https://meerschaum.io/files/archives/wheels/"
|
20
19
|
|
@@ -54,23 +53,25 @@ packages: Dict[str, Dict[str, str]] = {
|
|
54
53
|
'virtualenv' : 'virtualenv>=20.1.0',
|
55
54
|
'attrs' : 'attrs>=24.2.0',
|
56
55
|
'uv' : 'uv>=0.2.11',
|
56
|
+
'pydantic' : 'pydantic>=2.11.7',
|
57
|
+
'annotated-types' : 'annotated-types>=0.7.0',
|
57
58
|
},
|
58
59
|
'_internal' : {
|
59
60
|
'apscheduler' : (
|
60
61
|
f"{_MRSM_PACKAGE_ARCHIVES_PREFIX}"
|
61
|
-
"
|
62
|
+
"apscheduler-4.0.0a6.post8+mrsm-py3-none-any.whl>=4.0.0a6"
|
62
63
|
),
|
63
|
-
'dataclass_wizard' : 'dataclass-wizard>=0.
|
64
|
+
'dataclass_wizard' : 'dataclass-wizard>=0.35.0',
|
64
65
|
},
|
65
66
|
'jobs': {
|
66
|
-
'dill' : 'dill>=0.
|
67
|
-
'daemon' : 'python-daemon>=
|
68
|
-
'watchfiles' : 'watchfiles>=
|
69
|
-
'psutil' : 'psutil>=
|
67
|
+
'dill' : 'dill>=0.4.0',
|
68
|
+
'daemon' : 'python-daemon>=3.1.2',
|
69
|
+
'watchfiles' : 'watchfiles>=1.1.0',
|
70
|
+
'psutil' : 'psutil>=7.0.0',
|
70
71
|
},
|
71
72
|
'drivers': {
|
72
73
|
'cryptography' : 'cryptography>=38.0.1',
|
73
|
-
'psycopg' : 'psycopg[binary]>=3.2.
|
74
|
+
'psycopg' : 'psycopg[binary]>=3.2.9',
|
74
75
|
'pymysql' : 'PyMySQL>=0.9.0',
|
75
76
|
'aiomysql' : 'aiomysql>=0.0.21',
|
76
77
|
'sqlalchemy_cockroachdb' : 'sqlalchemy-cockroachdb>=2.0.0',
|
@@ -122,7 +123,7 @@ packages: Dict[str, Dict[str, str]] = {
|
|
122
123
|
'mkdocs_section_index' : 'mkdocs-section-index>=0.3.3',
|
123
124
|
'mkdocs_linkcheck' : 'mkdocs-linkcheck>=1.0.6',
|
124
125
|
'mkdocs_redirects' : 'mkdocs-redirects>=1.0.4',
|
125
|
-
'jinja2' : 'jinja2
|
126
|
+
'jinja2' : 'jinja2>=3.1.6',
|
126
127
|
},
|
127
128
|
'gui': {
|
128
129
|
'webview' : 'pywebview>=3.6.3',
|
@@ -137,43 +138,43 @@ packages: Dict[str, Dict[str, str]] = {
|
|
137
138
|
},
|
138
139
|
}
|
139
140
|
packages['sql'] = {
|
140
|
-
'numpy' : 'numpy>=
|
141
|
-
'pandas' : 'pandas[parquet]>=2.
|
142
|
-
'pyarrow' : 'pyarrow>=
|
141
|
+
'numpy' : 'numpy>=2.3.1',
|
142
|
+
'pandas' : 'pandas[parquet]>=2.3.1',
|
143
|
+
'pyarrow' : 'pyarrow>=20.0.0',
|
143
144
|
'dask' : 'dask[complete]>=2024.12.1',
|
144
145
|
'partd' : 'partd>=1.4.2',
|
145
146
|
'pytz' : 'pytz',
|
146
|
-
'joblib' : 'joblib>=
|
147
|
-
'sqlalchemy' : 'SQLAlchemy>=2.0.
|
147
|
+
'joblib' : 'joblib>=1.5.1',
|
148
|
+
'sqlalchemy' : 'SQLAlchemy>=2.0.41',
|
148
149
|
'geoalchemy' : 'GeoAlchemy2>=0.17.1',
|
149
|
-
'databases' : 'databases>=0.
|
150
|
-
'aiosqlite' : 'aiosqlite>=0.
|
151
|
-
'asyncpg' : 'asyncpg>=0.
|
150
|
+
'databases' : 'databases>=0.9.0',
|
151
|
+
'aiosqlite' : 'aiosqlite>=0.21.0',
|
152
|
+
'asyncpg' : 'asyncpg>=0.30.0',
|
152
153
|
}
|
153
154
|
packages['sql'].update(packages['drivers'])
|
154
155
|
packages['sql'].update(packages['core'])
|
155
156
|
packages['sql'].update(packages['gis'])
|
156
157
|
packages['dash'] = {
|
157
|
-
'flask_compress' : 'Flask-Compress>=1.
|
158
|
-
'dash' : 'dash>=
|
158
|
+
'flask_compress' : 'Flask-Compress>=1.17.0',
|
159
|
+
'dash' : 'dash>=3.1.1',
|
159
160
|
'dash_bootstrap_components' : 'dash-bootstrap-components>=1.7.1',
|
160
161
|
'dash_ace' : 'dash-ace>=0.2.1',
|
161
|
-
'dash_extensions' : 'dash-extensions>=
|
162
|
-
'dash_daq' : 'dash-daq>=0.
|
163
|
-
'terminado' : 'terminado>=0.
|
164
|
-
'tornado' : 'tornado>=6.1
|
162
|
+
'dash_extensions' : 'dash-extensions>=2.0.4',
|
163
|
+
'dash_daq' : 'dash-daq>=0.6.0',
|
164
|
+
'terminado' : 'terminado>=0.18.1',
|
165
|
+
'tornado' : 'tornado>=6.5.1',
|
165
166
|
}
|
166
167
|
packages['api'] = {
|
167
|
-
'uvicorn' : 'uvicorn[standard]>=0.
|
168
|
-
'gunicorn' : 'gunicorn>=
|
169
|
-
'dotenv' : 'python-dotenv>=
|
170
|
-
'websockets' : 'websockets>=
|
171
|
-
'fastapi' : 'fastapi>=0.
|
172
|
-
'fastapi_login' : 'fastapi-login>=1.
|
173
|
-
'multipart' : 'python-multipart>=0.0.
|
174
|
-
'httpx' : 'httpx>=0.
|
175
|
-
'httpcore' : 'httpcore>=1.0.
|
176
|
-
'valkey' : 'valkey>=6.
|
168
|
+
'uvicorn' : 'uvicorn[standard]>=0.35.0',
|
169
|
+
'gunicorn' : 'gunicorn>=23.0.0',
|
170
|
+
'dotenv' : 'python-dotenv>=1.1.1',
|
171
|
+
'websockets' : 'websockets>=15.0.1',
|
172
|
+
'fastapi' : 'fastapi>=0.116.0',
|
173
|
+
'fastapi_login' : 'fastapi-login>=1.10.3',
|
174
|
+
'multipart' : 'python-multipart>=0.0.20',
|
175
|
+
'httpx' : 'httpx>=0.28.1',
|
176
|
+
'httpcore' : 'httpcore>=1.0.9',
|
177
|
+
'valkey' : 'valkey>=6.1.0',
|
177
178
|
}
|
178
179
|
packages['api'].update(packages['sql'])
|
179
180
|
packages['api'].update(packages['formatting'])
|
@@ -216,3 +217,9 @@ for group, import_names in packages.items():
|
|
216
217
|
for import_name, install_name in import_names.items():
|
217
218
|
_full[import_name] = install_name
|
218
219
|
packages['full'] = _full
|
220
|
+
|
221
|
+
extras = {
|
222
|
+
group: list(import_names_install_names_map.values())
|
223
|
+
for group, import_names_install_names_map in packages.items()
|
224
|
+
if not group.startswith('_')
|
225
|
+
}
|
@@ -0,0 +1,181 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# vim:fenc=utf-8
|
3
|
+
|
4
|
+
"""
|
5
|
+
Define utilities for working with pipes.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from __future__ import annotations
|
9
|
+
|
10
|
+
from typing import Any, Dict, Callable
|
11
|
+
import re
|
12
|
+
import json
|
13
|
+
import ast
|
14
|
+
import copy
|
15
|
+
import uuid
|
16
|
+
|
17
|
+
from meerschaum.utils.typing import PipesDict, Optional, Any
|
18
|
+
import meerschaum as mrsm
|
19
|
+
|
20
|
+
|
21
|
+
def evaluate_pipe_access_chain(access_chain: str, pipe: mrsm.Pipe):
|
22
|
+
"""
|
23
|
+
Safely evaluate the access chain on a Pipe.
|
24
|
+
"""
|
25
|
+
expr = f"pipe{access_chain}"
|
26
|
+
tree = ast.parse(expr, mode='eval')
|
27
|
+
|
28
|
+
def _eval(node, context):
|
29
|
+
if isinstance(node, ast.Expression):
|
30
|
+
return _eval(node.body, context)
|
31
|
+
|
32
|
+
elif isinstance(node, ast.Name):
|
33
|
+
if node.id == "pipe":
|
34
|
+
return context
|
35
|
+
raise ValueError(f"Unknown variable: {node.id}")
|
36
|
+
|
37
|
+
elif isinstance(node, ast.Attribute):
|
38
|
+
value = _eval(node.value, context)
|
39
|
+
return getattr(value, node.attr)
|
40
|
+
|
41
|
+
elif isinstance(node, ast.Subscript):
|
42
|
+
value = _eval(node.value, context)
|
43
|
+
key = _eval(node.slice, context) if isinstance(node.slice, ast.Index) else _eval(node.slice, context)
|
44
|
+
return value[key]
|
45
|
+
|
46
|
+
elif isinstance(node, ast.Constant): # Python 3.8+
|
47
|
+
return node.value
|
48
|
+
|
49
|
+
elif isinstance(node, ast.Str): # Older Python
|
50
|
+
return node.s
|
51
|
+
|
52
|
+
elif isinstance(node, ast.Index): # Older Python AST style
|
53
|
+
return _eval(node.value, context)
|
54
|
+
|
55
|
+
else:
|
56
|
+
raise TypeError(f"Unsupported AST node: {ast.dump(node)}")
|
57
|
+
|
58
|
+
return _eval(tree, pipe)
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
def _evaluate_pipe_access_chain_from_match(pipe_match: re.Match) -> Any:
|
63
|
+
"""
|
64
|
+
Helper function to evaluate a pipe from a regex match object.
|
65
|
+
"""
|
66
|
+
from meerschaum.utils.warnings import warn
|
67
|
+
from meerschaum.utils.misc import parse_arguments_str
|
68
|
+
from meerschaum.utils.sql import sql_item_name
|
69
|
+
try:
|
70
|
+
args_str = pipe_match.group(1)
|
71
|
+
access_chain = pipe_match.group(2)
|
72
|
+
args, kwargs = parse_arguments_str(args_str)
|
73
|
+
pipe = mrsm.Pipe(*args, **kwargs)
|
74
|
+
except Exception as e:
|
75
|
+
warn(f"Failed to parse pipe from template string:\n{e}")
|
76
|
+
raise e
|
77
|
+
|
78
|
+
if not access_chain:
|
79
|
+
target = pipe.target
|
80
|
+
schema = (
|
81
|
+
pipe.instance_connector.get_pipe_schema(pipe)
|
82
|
+
if hasattr(pipe.instance_connector, 'get_pipe_schema')
|
83
|
+
else None
|
84
|
+
)
|
85
|
+
return (
|
86
|
+
sql_item_name(target, pipe.instance_connector.flavor, schema)
|
87
|
+
if pipe.instance_connector.type == 'sql'
|
88
|
+
else pipe.target
|
89
|
+
)
|
90
|
+
|
91
|
+
return evaluate_pipe_access_chain(access_chain, pipe)
|
92
|
+
|
93
|
+
|
94
|
+
def replace_pipes_syntax(text: str) -> Any:
|
95
|
+
"""
|
96
|
+
Parse a string containing the `{{ Pipe() }}` syntax.
|
97
|
+
"""
|
98
|
+
from meerschaum.utils.warnings import warn
|
99
|
+
from meerschaum.utils.sql import sql_item_name
|
100
|
+
from meerschaum.utils.dtypes import json_serialize_value
|
101
|
+
from meerschaum.utils.misc import parse_arguments_str
|
102
|
+
pattern = r'\{\{\s*(?:mrsm\.)?Pipe\((.*?)\)((?:\.[\w]+|\[[^\]]+\])*)\s*\}\}'
|
103
|
+
|
104
|
+
matches = list(re.finditer(pattern, text))
|
105
|
+
if not matches:
|
106
|
+
return text
|
107
|
+
|
108
|
+
placeholders = {}
|
109
|
+
for match in matches:
|
110
|
+
placeholder = f"__mrsm_pipe_placeholder_{uuid.uuid4().hex}__"
|
111
|
+
placeholders[placeholder] = match
|
112
|
+
|
113
|
+
substituted_text = text
|
114
|
+
for placeholder, match in placeholders.items():
|
115
|
+
substituted_text = substituted_text.replace(match.group(0), placeholder)
|
116
|
+
|
117
|
+
resolved_values = {}
|
118
|
+
for placeholder, match in placeholders.items():
|
119
|
+
try:
|
120
|
+
resolved_values[placeholder] = _evaluate_pipe_access_chain_from_match(match)
|
121
|
+
except Exception as e:
|
122
|
+
warn(f"Failed to resolve pipe syntax '{match.group(0)}': {e}")
|
123
|
+
resolved_values[placeholder] = match.group(0)
|
124
|
+
|
125
|
+
if len(matches) == 1:
|
126
|
+
match = matches[0]
|
127
|
+
placeholder = list(placeholders.keys())[0]
|
128
|
+
if text.strip() == match.group(0):
|
129
|
+
return resolved_values[placeholder]
|
130
|
+
|
131
|
+
final_text = substituted_text
|
132
|
+
for placeholder, value in resolved_values.items():
|
133
|
+
if isinstance(value, (dict, list, bool, int, float)) or value is None:
|
134
|
+
final_text = final_text.replace(placeholder, json.dumps(value, default=json_serialize_value))
|
135
|
+
else:
|
136
|
+
final_text = final_text.replace(placeholder, str(value))
|
137
|
+
|
138
|
+
return final_text
|
139
|
+
|
140
|
+
|
141
|
+
def replace_pipes_in_dict(
|
142
|
+
pipes: Optional[PipesDict] = None,
|
143
|
+
func: Callable[[Any], Any] = str,
|
144
|
+
debug: bool = False,
|
145
|
+
**kw
|
146
|
+
) -> PipesDict:
|
147
|
+
"""
|
148
|
+
Replace the Pipes in a Pipes dict with the result of another function.
|
149
|
+
|
150
|
+
Parameters
|
151
|
+
----------
|
152
|
+
pipes: Optional[PipesDict], default None
|
153
|
+
The pipes dict to be processed.
|
154
|
+
|
155
|
+
func: Callable[[Any], Any], default str
|
156
|
+
The function to be applied to every pipe.
|
157
|
+
Defaults to the string constructor.
|
158
|
+
|
159
|
+
debug: bool, default False
|
160
|
+
Verbosity toggle.
|
161
|
+
|
162
|
+
|
163
|
+
Returns
|
164
|
+
-------
|
165
|
+
A dictionary where every pipe is replaced with the output of a function.
|
166
|
+
|
167
|
+
"""
|
168
|
+
def change_dict(d : Dict[Any, Any], func : 'function') -> None:
|
169
|
+
for k, v in d.items():
|
170
|
+
if isinstance(v, dict):
|
171
|
+
change_dict(v, func)
|
172
|
+
else:
|
173
|
+
d[k] = func(v)
|
174
|
+
|
175
|
+
if pipes is None:
|
176
|
+
from meerschaum import get_pipes
|
177
|
+
pipes = get_pipes(debug=debug, **kw)
|
178
|
+
|
179
|
+
result = copy.deepcopy(pipes)
|
180
|
+
change_dict(result, func)
|
181
|
+
return result
|
meerschaum/utils/process.py
CHANGED
@@ -18,7 +18,7 @@ import platform
|
|
18
18
|
|
19
19
|
import meerschaum as mrsm
|
20
20
|
from meerschaum.utils.typing import Union, Optional, Any, Callable, Dict, Tuple
|
21
|
-
from meerschaum.
|
21
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
22
22
|
|
23
23
|
_child_processes = []
|
24
24
|
def signal_handler(sig, frame):
|
meerschaum/utils/prompt.py
CHANGED
@@ -399,6 +399,8 @@ def choose(
|
|
399
399
|
noask = noask,
|
400
400
|
**kw
|
401
401
|
)
|
402
|
+
if not answer:
|
403
|
+
continue
|
402
404
|
### Split along the delimiter.
|
403
405
|
_answers = [answer] if not multiple else [a for a in answer.split(delimiter)]
|
404
406
|
|
@@ -564,7 +566,7 @@ def check_noask(noask: bool = False) -> bool:
|
|
564
566
|
"""
|
565
567
|
Flip `noask` to `True` if `MRSM_NOASK` is set.
|
566
568
|
"""
|
567
|
-
from meerschaum.
|
569
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
568
570
|
NOASK = STATIC_CONFIG['environment']['noask']
|
569
571
|
if noask:
|
570
572
|
return True
|
meerschaum/utils/schedule.py
CHANGED
@@ -14,6 +14,7 @@ import meerschaum as mrsm
|
|
14
14
|
from meerschaum.utils.typing import Callable, Any, Optional, List, Dict
|
15
15
|
from meerschaum.utils.warnings import warn, error
|
16
16
|
|
17
|
+
|
17
18
|
STARTING_KEYWORD: str = 'starting'
|
18
19
|
INTERVAL_UNITS: List[str] = ['months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'years']
|
19
20
|
FREQUENCY_ALIASES: Dict[str, str] = {
|
@@ -292,7 +293,7 @@ def parse_start_time(schedule: str, now: Optional[datetime] = None) -> datetime:
|
|
292
293
|
>>> parse_start_time('hourly starting 00:30')
|
293
294
|
datetime.datetime(2024, 5, 13, 0, 30, tzinfo=datetime.timezone.utc)
|
294
295
|
"""
|
295
|
-
from meerschaum.utils.
|
296
|
+
from meerschaum.utils.dtypes import round_time
|
296
297
|
dateutil_parser = mrsm.attempt_import('dateutil.parser')
|
297
298
|
starting_parts = schedule.split(STARTING_KEYWORD)
|
298
299
|
starting_str = ('now' if len(starting_parts) == 1 else starting_parts[-1]).strip()
|