meerschaum 2.9.5__py3-none-any.whl → 3.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. meerschaum/__init__.py +5 -2
  2. meerschaum/_internal/__init__.py +1 -0
  3. meerschaum/_internal/arguments/_parse_arguments.py +4 -4
  4. meerschaum/_internal/arguments/_parser.py +33 -4
  5. meerschaum/_internal/cli/__init__.py +6 -0
  6. meerschaum/_internal/cli/daemons.py +103 -0
  7. meerschaum/_internal/cli/entry.py +220 -0
  8. meerschaum/_internal/cli/workers.py +435 -0
  9. meerschaum/_internal/docs/index.py +48 -2
  10. meerschaum/_internal/entry.py +50 -14
  11. meerschaum/_internal/shell/Shell.py +121 -29
  12. meerschaum/_internal/shell/__init__.py +4 -1
  13. meerschaum/_internal/static.py +359 -0
  14. meerschaum/_internal/term/TermPageHandler.py +1 -2
  15. meerschaum/_internal/term/__init__.py +40 -6
  16. meerschaum/_internal/term/tools.py +33 -8
  17. meerschaum/actions/__init__.py +6 -4
  18. meerschaum/actions/api.py +53 -13
  19. meerschaum/actions/attach.py +1 -0
  20. meerschaum/actions/bootstrap.py +8 -8
  21. meerschaum/actions/delete.py +4 -2
  22. meerschaum/actions/edit.py +171 -25
  23. meerschaum/actions/login.py +8 -8
  24. meerschaum/actions/register.py +143 -6
  25. meerschaum/actions/reload.py +22 -5
  26. meerschaum/actions/restart.py +14 -0
  27. meerschaum/actions/show.py +184 -31
  28. meerschaum/actions/start.py +166 -17
  29. meerschaum/actions/stop.py +38 -2
  30. meerschaum/actions/sync.py +7 -2
  31. meerschaum/actions/tag.py +9 -8
  32. meerschaum/actions/verify.py +5 -8
  33. meerschaum/api/__init__.py +45 -15
  34. meerschaum/api/_events.py +46 -4
  35. meerschaum/api/_oauth2.py +162 -9
  36. meerschaum/api/_tokens.py +102 -0
  37. meerschaum/api/dash/__init__.py +0 -3
  38. meerschaum/api/dash/callbacks/__init__.py +1 -0
  39. meerschaum/api/dash/callbacks/custom.py +4 -3
  40. meerschaum/api/dash/callbacks/dashboard.py +198 -118
  41. meerschaum/api/dash/callbacks/jobs.py +14 -7
  42. meerschaum/api/dash/callbacks/login.py +10 -1
  43. meerschaum/api/dash/callbacks/pipes.py +194 -14
  44. meerschaum/api/dash/callbacks/plugins.py +0 -1
  45. meerschaum/api/dash/callbacks/register.py +10 -3
  46. meerschaum/api/dash/callbacks/settings/password_reset.py +2 -2
  47. meerschaum/api/dash/callbacks/tokens.py +389 -0
  48. meerschaum/api/dash/components.py +36 -15
  49. meerschaum/api/dash/jobs.py +1 -1
  50. meerschaum/api/dash/keys.py +35 -93
  51. meerschaum/api/dash/pages/__init__.py +2 -1
  52. meerschaum/api/dash/pages/dashboard.py +1 -20
  53. meerschaum/api/dash/pages/{job.py → jobs.py} +10 -7
  54. meerschaum/api/dash/pages/login.py +2 -2
  55. meerschaum/api/dash/pages/pipes.py +16 -5
  56. meerschaum/api/dash/pages/settings/password_reset.py +1 -1
  57. meerschaum/api/dash/pages/tokens.py +53 -0
  58. meerschaum/api/dash/pipes.py +382 -95
  59. meerschaum/api/dash/sessions.py +12 -0
  60. meerschaum/api/dash/tokens.py +603 -0
  61. meerschaum/api/dash/websockets.py +1 -1
  62. meerschaum/api/dash/webterm.py +18 -6
  63. meerschaum/api/models/__init__.py +23 -3
  64. meerschaum/api/models/_actions.py +22 -0
  65. meerschaum/api/models/_pipes.py +91 -7
  66. meerschaum/api/models/_tokens.py +81 -0
  67. meerschaum/api/resources/static/js/terminado.js +3 -0
  68. meerschaum/api/resources/static/js/xterm-addon-unicode11.js +2 -0
  69. meerschaum/api/resources/templates/termpage.html +13 -0
  70. meerschaum/api/routes/__init__.py +1 -0
  71. meerschaum/api/routes/_actions.py +3 -4
  72. meerschaum/api/routes/_connectors.py +3 -7
  73. meerschaum/api/routes/_jobs.py +26 -35
  74. meerschaum/api/routes/_login.py +120 -15
  75. meerschaum/api/routes/_misc.py +5 -10
  76. meerschaum/api/routes/_pipes.py +178 -143
  77. meerschaum/api/routes/_plugins.py +38 -28
  78. meerschaum/api/routes/_tokens.py +236 -0
  79. meerschaum/api/routes/_users.py +47 -35
  80. meerschaum/api/routes/_version.py +3 -3
  81. meerschaum/api/routes/_webterm.py +3 -3
  82. meerschaum/config/__init__.py +100 -30
  83. meerschaum/config/_default.py +132 -64
  84. meerschaum/config/_edit.py +38 -32
  85. meerschaum/config/_formatting.py +2 -0
  86. meerschaum/config/_patch.py +10 -8
  87. meerschaum/config/_paths.py +133 -13
  88. meerschaum/config/_read_config.py +87 -36
  89. meerschaum/config/_sync.py +6 -3
  90. meerschaum/config/_version.py +1 -1
  91. meerschaum/config/environment.py +262 -0
  92. meerschaum/config/stack/__init__.py +37 -15
  93. meerschaum/config/static.py +18 -0
  94. meerschaum/connectors/_Connector.py +11 -6
  95. meerschaum/connectors/__init__.py +41 -22
  96. meerschaum/connectors/api/_APIConnector.py +34 -6
  97. meerschaum/connectors/api/_actions.py +2 -2
  98. meerschaum/connectors/api/_jobs.py +12 -1
  99. meerschaum/connectors/api/_login.py +33 -7
  100. meerschaum/connectors/api/_misc.py +2 -2
  101. meerschaum/connectors/api/_pipes.py +23 -32
  102. meerschaum/connectors/api/_plugins.py +2 -2
  103. meerschaum/connectors/api/_request.py +1 -1
  104. meerschaum/connectors/api/_tokens.py +146 -0
  105. meerschaum/connectors/api/_users.py +70 -58
  106. meerschaum/connectors/instance/_InstanceConnector.py +83 -0
  107. meerschaum/connectors/instance/__init__.py +10 -0
  108. meerschaum/connectors/instance/_pipes.py +442 -0
  109. meerschaum/connectors/instance/_plugins.py +159 -0
  110. meerschaum/connectors/instance/_tokens.py +317 -0
  111. meerschaum/connectors/instance/_users.py +188 -0
  112. meerschaum/connectors/parse.py +5 -2
  113. meerschaum/connectors/sql/_SQLConnector.py +22 -5
  114. meerschaum/connectors/sql/_cli.py +12 -11
  115. meerschaum/connectors/sql/_create_engine.py +12 -168
  116. meerschaum/connectors/sql/_fetch.py +2 -18
  117. meerschaum/connectors/sql/_pipes.py +295 -278
  118. meerschaum/connectors/sql/_plugins.py +29 -0
  119. meerschaum/connectors/sql/_sql.py +46 -21
  120. meerschaum/connectors/sql/_users.py +36 -2
  121. meerschaum/connectors/sql/tables/__init__.py +254 -122
  122. meerschaum/connectors/valkey/_ValkeyConnector.py +5 -7
  123. meerschaum/connectors/valkey/_pipes.py +60 -31
  124. meerschaum/connectors/valkey/_plugins.py +2 -26
  125. meerschaum/core/Pipe/__init__.py +115 -85
  126. meerschaum/core/Pipe/_attributes.py +425 -124
  127. meerschaum/core/Pipe/_bootstrap.py +54 -24
  128. meerschaum/core/Pipe/_cache.py +555 -0
  129. meerschaum/core/Pipe/_clear.py +0 -11
  130. meerschaum/core/Pipe/_data.py +96 -68
  131. meerschaum/core/Pipe/_deduplicate.py +0 -13
  132. meerschaum/core/Pipe/_delete.py +12 -21
  133. meerschaum/core/Pipe/_drop.py +11 -23
  134. meerschaum/core/Pipe/_dtypes.py +49 -19
  135. meerschaum/core/Pipe/_edit.py +14 -4
  136. meerschaum/core/Pipe/_fetch.py +1 -1
  137. meerschaum/core/Pipe/_index.py +8 -14
  138. meerschaum/core/Pipe/_show.py +5 -5
  139. meerschaum/core/Pipe/_sync.py +123 -204
  140. meerschaum/core/Pipe/_verify.py +4 -4
  141. meerschaum/{plugins → core/Plugin}/_Plugin.py +16 -12
  142. meerschaum/core/Plugin/__init__.py +1 -1
  143. meerschaum/core/Token/_Token.py +220 -0
  144. meerschaum/core/Token/__init__.py +12 -0
  145. meerschaum/core/User/_User.py +35 -10
  146. meerschaum/core/User/__init__.py +9 -1
  147. meerschaum/core/__init__.py +1 -0
  148. meerschaum/jobs/_Executor.py +88 -4
  149. meerschaum/jobs/_Job.py +149 -38
  150. meerschaum/jobs/__init__.py +3 -2
  151. meerschaum/jobs/systemd.py +8 -3
  152. meerschaum/models/__init__.py +35 -0
  153. meerschaum/models/pipes.py +247 -0
  154. meerschaum/models/tokens.py +38 -0
  155. meerschaum/models/users.py +26 -0
  156. meerschaum/plugins/__init__.py +301 -88
  157. meerschaum/plugins/bootstrap.py +510 -4
  158. meerschaum/utils/_get_pipes.py +97 -30
  159. meerschaum/utils/daemon/Daemon.py +199 -43
  160. meerschaum/utils/daemon/FileDescriptorInterceptor.py +0 -1
  161. meerschaum/utils/daemon/RotatingFile.py +63 -36
  162. meerschaum/utils/daemon/StdinFile.py +53 -13
  163. meerschaum/utils/daemon/__init__.py +47 -6
  164. meerschaum/utils/daemon/_names.py +6 -3
  165. meerschaum/utils/dataframe.py +479 -81
  166. meerschaum/utils/debug.py +49 -19
  167. meerschaum/utils/dtypes/__init__.py +476 -34
  168. meerschaum/utils/dtypes/sql.py +369 -29
  169. meerschaum/utils/formatting/__init__.py +5 -2
  170. meerschaum/utils/formatting/_jobs.py +1 -1
  171. meerschaum/utils/formatting/_pipes.py +52 -50
  172. meerschaum/utils/formatting/_pprint.py +1 -0
  173. meerschaum/utils/formatting/_shell.py +44 -18
  174. meerschaum/utils/misc.py +268 -186
  175. meerschaum/utils/packages/__init__.py +25 -40
  176. meerschaum/utils/packages/_packages.py +42 -34
  177. meerschaum/utils/pipes.py +213 -0
  178. meerschaum/utils/process.py +2 -2
  179. meerschaum/utils/prompt.py +175 -144
  180. meerschaum/utils/schedule.py +2 -1
  181. meerschaum/utils/sql.py +134 -47
  182. meerschaum/utils/threading.py +42 -0
  183. meerschaum/utils/typing.py +1 -4
  184. meerschaum/utils/venv/_Venv.py +2 -2
  185. meerschaum/utils/venv/__init__.py +7 -7
  186. meerschaum/utils/warnings.py +19 -13
  187. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/METADATA +94 -96
  188. meerschaum-3.0.0.dist-info/RECORD +289 -0
  189. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/WHEEL +1 -1
  190. meerschaum-3.0.0.dist-info/licenses/NOTICE +2 -0
  191. meerschaum/api/models/_interfaces.py +0 -15
  192. meerschaum/api/models/_locations.py +0 -15
  193. meerschaum/api/models/_metrics.py +0 -15
  194. meerschaum/config/_environment.py +0 -145
  195. meerschaum/config/static/__init__.py +0 -186
  196. meerschaum-2.9.5.dist-info/RECORD +0 -263
  197. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/entry_points.txt +0 -0
  198. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/licenses/LICENSE +0 -0
  199. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.dist-info}/top_level.txt +0 -0
  200. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0.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 = [pathlib.Path(site.getusersitepackages())]
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 = [
@@ -134,17 +136,17 @@ def get_module_path(
134
136
 
135
137
 
136
138
  def manually_import_module(
137
- import_name: str,
138
- venv: Optional[str] = 'mrsm',
139
- check_update: bool = True,
140
- check_pypi: bool = False,
141
- install: bool = True,
142
- split: bool = True,
143
- warn: bool = True,
144
- color: bool = True,
145
- debug: bool = False,
146
- use_sys_modules: bool = True,
147
- ) -> Union['ModuleType', None]:
139
+ import_name: str,
140
+ venv: Optional[str] = 'mrsm',
141
+ check_update: bool = True,
142
+ check_pypi: bool = False,
143
+ install: bool = True,
144
+ split: bool = True,
145
+ warn: bool = True,
146
+ color: bool = True,
147
+ debug: bool = False,
148
+ use_sys_modules: bool = True,
149
+ ) -> Union['ModuleType', None]:
148
150
  """
149
151
  Manually import a module from a virtual environment (or the base environment).
150
152
 
@@ -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.config.static import STATIC_CONFIG
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.config.static import STATIC_CONFIG
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 []
@@ -1177,7 +1179,8 @@ def run_python_package(
1177
1179
  Either a return code integer or a `subprocess.Popen` object
1178
1180
  (or `None` if a `KeyboardInterrupt` occurs and as_proc is `True`).
1179
1181
  """
1180
- import sys, platform
1182
+ import sys
1183
+ import platform
1181
1184
  import subprocess
1182
1185
  from meerschaum.config._paths import VIRTENV_RESOURCES_PATH
1183
1186
  from meerschaum.utils.process import run_process
@@ -1204,7 +1207,7 @@ def run_python_package(
1204
1207
  capture_output=capture_output,
1205
1208
  **kw
1206
1209
  )
1207
- except Exception as e:
1210
+ except Exception:
1208
1211
  msg = f"Failed to execute {command}, will try again:\n{traceback.format_exc()}"
1209
1212
  warn(msg, color=False)
1210
1213
  stdout, stderr = (
@@ -1216,6 +1219,7 @@ def run_python_package(
1216
1219
  command,
1217
1220
  stdout=stdout,
1218
1221
  stderr=stderr,
1222
+ stdin=sys.stdin,
1219
1223
  env=env_dict,
1220
1224
  )
1221
1225
  to_return = proc if as_proc else proc.wait()
@@ -1500,15 +1504,12 @@ def import_pandas(
1500
1504
  def import_rich(
1501
1505
  lazy: bool = True,
1502
1506
  debug: bool = False,
1503
- **kw : Any
1507
+ **kw: Any
1504
1508
  ) -> 'ModuleType':
1505
1509
  """
1506
1510
  Quality of life function for importing `rich`.
1507
1511
  """
1508
1512
  from meerschaum.utils.formatting import ANSI, UNICODE
1509
- if not ANSI and not UNICODE:
1510
- return None
1511
-
1512
1513
  ## need typing_extensions for `from rich import box`
1513
1514
  typing_extensions = attempt_import(
1514
1515
  'typing_extensions', lazy=False, debug=debug
@@ -1773,6 +1774,10 @@ def is_installed(
1773
1774
  allow_outside_venv: bool, default True
1774
1775
  If `True`, search outside of the specified virtual environment
1775
1776
  if the package cannot be found.
1777
+
1778
+ Returns
1779
+ -------
1780
+ A bool indicating whether a package may be imported.
1776
1781
  """
1777
1782
  if debug:
1778
1783
  from meerschaum.utils.debug import dprint
@@ -1864,26 +1869,6 @@ def ensure_readline() -> 'ModuleType':
1864
1869
  sys.modules['readline'] = readline
1865
1870
  return readline
1866
1871
 
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
1872
 
1888
1873
  def _get_pip_os_env(color: bool = True):
1889
1874
  """
@@ -13,8 +13,7 @@ packages dictionary is structured in the following schema:
13
13
  }
14
14
  """
15
15
 
16
- from __future__ import annotations
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
- "APScheduler-4.0.0a5.post87+mrsm-py3-none-any.whl>=4.0.0a5"
62
+ "apscheduler-4.0.0a6.post8+mrsm-py3-none-any.whl>=4.0.0a6"
62
63
  ),
63
- 'dataclass_wizard' : 'dataclass-wizard>=0.28.0',
64
+ 'dataclass_wizard' : 'dataclass-wizard>=0.35.0',
64
65
  },
65
66
  'jobs': {
66
- 'dill' : 'dill>=0.3.3',
67
- 'daemon' : 'python-daemon>=0.2.3',
68
- 'watchfiles' : 'watchfiles>=0.21.0',
69
- 'psutil' : 'psutil>=5.8.0',
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.1',
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==3.0.3',
126
+ 'jinja2' : 'jinja2>=3.1.6',
126
127
  },
127
128
  'gui': {
128
129
  'webview' : 'pywebview>=3.6.3',
@@ -137,43 +138,44 @@ packages: Dict[str, Dict[str, str]] = {
137
138
  },
138
139
  }
139
140
  packages['sql'] = {
140
- 'numpy' : 'numpy>=1.18.5',
141
- 'pandas' : 'pandas[parquet]>=2.0.1',
142
- 'pyarrow' : 'pyarrow>=16.1.0',
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>=0.17.0',
147
- 'sqlalchemy' : 'SQLAlchemy>=2.0.5',
147
+ 'joblib' : 'joblib>=1.5.1',
148
+ 'sqlalchemy' : 'SQLAlchemy>=2.0.41',
148
149
  'geoalchemy' : 'GeoAlchemy2>=0.17.1',
149
- 'databases' : 'databases>=0.4.0',
150
- 'aiosqlite' : 'aiosqlite>=0.16.0',
151
- 'asyncpg' : 'asyncpg>=0.21.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.10.1',
158
- 'dash' : 'dash>=2.6.2',
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>=1.0.4',
162
- 'dash_daq' : 'dash-daq>=0.5.0',
163
- 'terminado' : 'terminado>=0.12.1',
164
- 'tornado' : 'tornado>=6.1.0',
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.29.0',
168
- 'gunicorn' : 'gunicorn>=22.0.0',
169
- 'dotenv' : 'python-dotenv>=0.20.0',
170
- 'websockets' : 'websockets>=11.0.3',
171
- 'fastapi' : 'fastapi>=0.111.0',
172
- 'fastapi_login' : 'fastapi-login>=1.7.2',
173
- 'multipart' : 'python-multipart>=0.0.9',
174
- 'httpx' : 'httpx>=0.27.2',
175
- 'httpcore' : 'httpcore>=1.0.6',
176
- 'valkey' : 'valkey>=6.0.0',
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',
178
+ 'jose' : 'python-jose>=3.5.0',
177
179
  }
178
180
  packages['api'].update(packages['sql'])
179
181
  packages['api'].update(packages['formatting'])
@@ -216,3 +218,9 @@ for group, import_names in packages.items():
216
218
  for import_name, install_name in import_names.items():
217
219
  _full[import_name] = install_name
218
220
  packages['full'] = _full
221
+
222
+ extras = {
223
+ group: list(import_names_install_names_map.values())
224
+ for group, import_names_install_names_map in packages.items()
225
+ if not group.startswith('_')
226
+ }
@@ -0,0 +1,213 @@
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
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.dtypes import json_serialize_value
100
+ pattern = r'\{\{\s*(?:mrsm\.)?Pipe\((.*?)\)((?:\.[\w]+|\[[^\]]+\])*)\s*\}\}'
101
+
102
+ matches = list(re.finditer(pattern, text))
103
+ if not matches:
104
+ return text
105
+
106
+ placeholders = {}
107
+ for match in matches:
108
+ placeholder = f"__mrsm_pipe_placeholder_{uuid.uuid4().hex}__"
109
+ placeholders[placeholder] = match
110
+
111
+ substituted_text = text
112
+ for placeholder, match in placeholders.items():
113
+ substituted_text = substituted_text.replace(match.group(0), placeholder)
114
+
115
+ resolved_values = {}
116
+ for placeholder, match in placeholders.items():
117
+ try:
118
+ resolved_values[placeholder] = _evaluate_pipe_access_chain_from_match(match)
119
+ except Exception as e:
120
+ warn(f"Failed to resolve pipe syntax '{match.group(0)}': {e}")
121
+ resolved_values[placeholder] = match.group(0)
122
+
123
+ if len(matches) == 1:
124
+ match = matches[0]
125
+ placeholder = list(placeholders.keys())[0]
126
+ if text.strip() == match.group(0):
127
+ return resolved_values[placeholder]
128
+
129
+ final_text = substituted_text
130
+ for placeholder, value in resolved_values.items():
131
+ if isinstance(value, (dict, list, bool, int, float)) or value is None:
132
+ final_text = final_text.replace(placeholder, json.dumps(value, default=json_serialize_value))
133
+ else:
134
+ final_text = final_text.replace(placeholder, str(value))
135
+
136
+ return final_text
137
+
138
+
139
+ def replace_pipes_in_dict(
140
+ pipes: Optional[PipesDict] = None,
141
+ func: Callable[[Any], Any] = str,
142
+ debug: bool = False,
143
+ **kw
144
+ ) -> PipesDict:
145
+ """
146
+ Replace the Pipes in a Pipes dict with the result of another function.
147
+
148
+ Parameters
149
+ ----------
150
+ pipes: Optional[PipesDict], default None
151
+ The pipes dict to be processed.
152
+
153
+ func: Callable[[Any], Any], default str
154
+ The function to be applied to every pipe.
155
+ Defaults to the string constructor.
156
+
157
+ debug: bool, default False
158
+ Verbosity toggle.
159
+
160
+ Returns
161
+ -------
162
+ A dictionary where every pipe is replaced with the output of a function.
163
+
164
+ """
165
+ def change_dict(d: Dict[Any, Any]) -> None:
166
+ for k, v in d.items():
167
+ if isinstance(v, dict):
168
+ change_dict(v)
169
+ elif isinstance(v, list):
170
+ d[k] = [func(i) for i in v]
171
+ elif isinstance(v, tuple):
172
+ d[k] = tuple([func(i) for i in v])
173
+ else:
174
+ d[k] = func(v)
175
+
176
+ if pipes is None:
177
+ from meerschaum import get_pipes
178
+ pipes = get_pipes(debug=debug, **kw)
179
+
180
+ result = copy.deepcopy(pipes)
181
+ change_dict(result)
182
+ return result
183
+
184
+
185
+ def is_pipe_registered(
186
+ pipe: mrsm.Pipe,
187
+ pipes: PipesDict,
188
+ debug: bool = False
189
+ ) -> bool:
190
+ """
191
+ Check if a Pipe is inside the pipes dictionary.
192
+
193
+ Parameters
194
+ ----------
195
+ pipe: meerschaum.Pipe
196
+ The pipe to see if it's in the dictionary.
197
+
198
+ pipes: PipesDict
199
+ The dictionary to search inside.
200
+
201
+ debug: bool, default False
202
+ Verbosity toggle.
203
+
204
+ Returns
205
+ -------
206
+ A bool indicating whether the pipe is inside the dictionary.
207
+ """
208
+ from meerschaum.utils.debug import dprint
209
+ ck, mk, lk = pipe.connector_keys, pipe.metric_key, pipe.location_key
210
+ if debug:
211
+ dprint(f'{ck}, {mk}, {lk}')
212
+ dprint(f'{pipe}, {pipes}')
213
+ return ck in pipes and mk in pipes[ck] and lk in pipes[ck][mk]
@@ -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.config.static import STATIC_CONFIG
21
+ from meerschaum._internal.static import STATIC_CONFIG
22
22
 
23
23
  _child_processes = []
24
24
  def signal_handler(sig, frame):
@@ -178,7 +178,7 @@ def run_process(
178
178
  # make us tty's foreground again
179
179
  try:
180
180
  os.tcsetpgrp(sys.stdin.fileno(), old_pgrp)
181
- except Exception as e:
181
+ except Exception:
182
182
  pass
183
183
  # now restore the handler
184
184
  signal.signal(signal.SIGTTOU, hdlr)