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
@@ -13,6 +13,35 @@ import json
13
13
  import meerschaum as mrsm
14
14
  from meerschaum.utils.typing import Optional, Any, List, SuccessTuple, Dict
15
15
 
16
+
17
+ def get_plugins_pipe(self) -> mrsm.Pipe:
18
+ """
19
+ Return the internal metadata plugins pipe.
20
+ """
21
+ users_pipe = self.get_users_pipe()
22
+ user_id_dtype = users_pipe.dtypes.get('user_id', 'int')
23
+ return mrsm.Pipe(
24
+ 'mrsm', 'plugins',
25
+ instance=self,
26
+ temporary=True,
27
+ static=True,
28
+ null_indices=False,
29
+ columns={
30
+ 'primary': 'plugin_id',
31
+ 'user_id': 'user_id',
32
+ },
33
+ dtypes={
34
+ 'plugin_name': 'string',
35
+ 'user_id': user_id_dtype,
36
+ 'attributes': 'json',
37
+ 'version': 'string',
38
+ },
39
+ indices={
40
+ 'unique': 'plugin_name',
41
+ },
42
+ )
43
+
44
+
16
45
  def register_plugin(
17
46
  self,
18
47
  plugin: 'mrsm.core.Plugin',
@@ -17,7 +17,14 @@ from meerschaum.utils.debug import dprint
17
17
  from meerschaum.utils.warnings import warn
18
18
 
19
19
  ### database flavors that can use bulk insert
20
- _bulk_flavors = {'postgresql', 'postgis', 'timescaledb', 'citus', 'mssql'}
20
+ _bulk_flavors = {
21
+ 'postgresql',
22
+ 'postgis',
23
+ 'timescaledb',
24
+ 'timescaledb-ha',
25
+ 'citus',
26
+ 'mssql',
27
+ }
21
28
  ### flavors that do not support chunks
22
29
  _disallow_chunks_flavors = ['duckdb']
23
30
  _max_chunks_flavors = {'sqlite': 1000}
@@ -124,23 +131,28 @@ def read(
124
131
  """
125
132
  if chunks is not None and chunks <= 0:
126
133
  return []
134
+
127
135
  from meerschaum.utils.sql import sql_item_name, truncate_item_name
128
136
  from meerschaum.utils.dtypes import are_dtypes_equal, coerce_timezone
129
137
  from meerschaum.utils.dtypes.sql import TIMEZONE_NAIVE_FLAVORS
130
138
  from meerschaum.utils.packages import attempt_import, import_pandas
131
139
  from meerschaum.utils.pool import get_pool
132
140
  from meerschaum.utils.dataframe import chunksize_to_npartitions, get_numeric_cols
141
+ from meerschaum.utils.misc import filter_arguments
133
142
  import warnings
134
143
  import traceback
135
144
  from decimal import Decimal
145
+
136
146
  pd = import_pandas()
137
147
  dd = None
148
+
138
149
  is_dask = 'dask' in pd.__name__
139
150
  pandas = attempt_import('pandas')
140
151
  is_dask = dd is not None
141
152
  npartitions = chunksize_to_npartitions(chunksize)
142
153
  if is_dask:
143
154
  chunksize = None
155
+
144
156
  schema = schema or self.schema
145
157
  utc_dt_cols = [
146
158
  col
@@ -151,7 +163,7 @@ def read(
151
163
  if dtype and utc_dt_cols and self.flavor in TIMEZONE_NAIVE_FLAVORS:
152
164
  dtype = dtype.copy()
153
165
  for col in utc_dt_cols:
154
- dtype[col] = 'datetime64[ns]'
166
+ dtype[col] = 'datetime64[us]'
155
167
 
156
168
  pool = get_pool(workers=workers)
157
169
  sqlalchemy = attempt_import("sqlalchemy", lazy=False)
@@ -215,26 +227,33 @@ def read(
215
227
  else format_sql_query_for_dask(str_query)
216
228
  )
217
229
 
230
+ def _get_chunk_args_kwargs(_chunk):
231
+ return filter_arguments(
232
+ chunk_hook,
233
+ _chunk,
234
+ workers=workers,
235
+ chunksize=chunksize,
236
+ debug=debug,
237
+ **kw
238
+ )
239
+
218
240
  chunk_list = []
219
241
  chunk_hook_results = []
220
242
  def _process_chunk(_chunk, _retry_on_failure: bool = True):
221
243
  if self.flavor in TIMEZONE_NAIVE_FLAVORS:
222
244
  for col in utc_dt_cols:
223
- _chunk[col] = coerce_timezone(_chunk[col], strip_timezone=False)
245
+ _chunk[col] = coerce_timezone(_chunk[col], strip_utc=False)
224
246
  if not as_hook_results:
225
247
  chunk_list.append(_chunk)
248
+
226
249
  if chunk_hook is None:
227
250
  return None
228
251
 
252
+ chunk_args, chunk_kwargs = _get_chunk_args_kwargs(_chunk)
253
+
229
254
  result = None
230
255
  try:
231
- result = chunk_hook(
232
- _chunk,
233
- workers=workers,
234
- chunksize=chunksize,
235
- debug=debug,
236
- **kw
237
- )
256
+ result = chunk_hook(*chunk_args, **chunk_kwargs)
238
257
  except Exception:
239
258
  result = False, traceback.format_exc()
240
259
  from meerschaum.utils.formatting import get_console
@@ -285,8 +304,16 @@ def read(
285
304
  self.engine,
286
305
  **read_sql_query_kwargs
287
306
  )
307
+
288
308
  to_return = (
289
- chunk_generator
309
+ (
310
+ chunk_generator
311
+ if not (as_hook_results or chunksize is None)
312
+ else (
313
+ _process_chunk(_chunk)
314
+ for _chunk in chunk_generator
315
+ )
316
+ )
290
317
  if as_iterator or chunksize is None
291
318
  else (
292
319
  list(pool.imap(_process_chunk, chunk_generator))
@@ -332,9 +359,8 @@ def read(
332
359
  try:
333
360
  for chunk in chunk_generator:
334
361
  if chunk_hook is not None:
335
- chunk_hook_results.append(
336
- chunk_hook(chunk, chunksize=chunksize, debug=debug, **kw)
337
- )
362
+ chunk_args, chunk_kwargs = _get_chunk_args_kwargs(chunk)
363
+ chunk_hook_results.append(chunk_hook(*chunk_args, **chunk_kwargs))
338
364
  chunk_list.append(chunk)
339
365
  read_chunks += 1
340
366
  if chunks is not None and read_chunks >= chunks:
@@ -349,9 +375,8 @@ def read(
349
375
  try:
350
376
  for chunk in chunk_generator:
351
377
  if chunk_hook is not None:
352
- chunk_hook_results.append(
353
- chunk_hook(chunk, chunksize=chunksize, debug=debug, **kw)
354
- )
378
+ chunk_args, chunk_kwargs = _get_chunk_args_kwargs(chunk)
379
+ chunk_hook_results.append(chunk_hook(*chunk_args, **chunk_kwargs))
355
380
  chunk_list.append(chunk)
356
381
  read_chunks += 1
357
382
  if chunks is not None and read_chunks >= chunks:
@@ -382,9 +407,8 @@ def read(
382
407
  ### call the hook on any missed chunks.
383
408
  if chunk_hook is not None and len(chunk_list) > len(chunk_hook_results):
384
409
  for c in chunk_list[len(chunk_hook_results):]:
385
- chunk_hook_results.append(
386
- chunk_hook(c, chunksize=chunksize, debug=debug, **kw)
387
- )
410
+ chunk_args, chunk_kwargs = _get_chunk_args_kwargs(c)
411
+ chunk_hook_results.append(chunk_hook(*chunk_args, **chunk_kwargs))
388
412
 
389
413
  ### chunksize is not None so must iterate
390
414
  if debug:
@@ -777,6 +801,7 @@ def to_sql(
777
801
  from meerschaum.utils.warnings import error, warn
778
802
  import warnings
779
803
  import functools
804
+ import traceback
780
805
 
781
806
  if name is None:
782
807
  error(f"Name must not be `None` to insert data into {self}.")
@@ -1050,7 +1075,7 @@ def to_sql(
1050
1075
  except Exception as e:
1051
1076
  if not silent:
1052
1077
  warn(str(e))
1053
- success, msg = False, str(e)
1078
+ success, msg = False, traceback.format_exc()
1054
1079
 
1055
1080
  end = time.perf_counter()
1056
1081
  if success:
@@ -12,6 +12,39 @@ import meerschaum as mrsm
12
12
  from meerschaum.utils.typing import SuccessTuple, Optional, Any, Dict, List, Union
13
13
 
14
14
 
15
+ def get_users_pipe(self) -> mrsm.Pipe:
16
+ """
17
+ Return the internal metadata pipe for users management.
18
+ """
19
+ if '_users_pipe' in self.__dict__:
20
+ return self._users_pipe
21
+
22
+ cache_connector = self.__dict__.get('_cache_connector', None)
23
+ self._users_pipe = mrsm.Pipe(
24
+ 'mrsm', 'users',
25
+ temporary=True,
26
+ cache=True,
27
+ cache_connector_keys=cache_connector,
28
+ static=True,
29
+ null_indices=False,
30
+ enforce=False,
31
+ autoincrement=True,
32
+ columns={
33
+ 'primary': 'user_id',
34
+ },
35
+ dtypes={
36
+ 'user_id': 'int',
37
+ 'username': 'string',
38
+ 'attributes': 'json',
39
+ 'user_type': 'string',
40
+ },
41
+ indices={
42
+ 'unique': 'username',
43
+ },
44
+ )
45
+ return self._users_pipe
46
+
47
+
15
48
  def register_user(
16
49
  self,
17
50
  user: mrsm.core.User,
@@ -64,7 +97,7 @@ def register_user(
64
97
 
65
98
  def valid_username(username: str) -> SuccessTuple:
66
99
  """Verify that a given username is valid."""
67
- from meerschaum.config.static import STATIC_CONFIG
100
+ from meerschaum._internal.static import STATIC_CONFIG
68
101
  fail_reasons = []
69
102
 
70
103
  min_length = STATIC_CONFIG['users']['min_username_length']
@@ -104,6 +137,7 @@ def edit_user(
104
137
  ) -> SuccessTuple:
105
138
  """Update an existing user's metadata."""
106
139
  from meerschaum.utils.packages import attempt_import
140
+ from meerschaum.utils.sql import json_flavors
107
141
  sqlalchemy = attempt_import('sqlalchemy', lazy=False)
108
142
  from meerschaum.connectors.sql.tables import get_tables
109
143
  users_tbl = get_tables(mrsm_instance=self, debug=debug)['users']
@@ -131,7 +165,7 @@ def edit_user(
131
165
  bind_variables['email'] = user.email
132
166
  if user.attributes is not None and user.attributes != {}:
133
167
  bind_variables['attributes'] = (
134
- json.dumps(user.attributes) if self.flavor in ('duckdb',)
168
+ json.dumps(user.attributes) if self.flavor not in json_flavors
135
169
  else user.attributes
136
170
  )
137
171
  if user.type != '':