meerschaum 2.4.0.dev1__py3-none-any.whl → 2.4.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.
Files changed (66) hide show
  1. meerschaum/_internal/arguments/_parse_arguments.py +2 -5
  2. meerschaum/_internal/docs/index.py +3 -2
  3. meerschaum/_internal/entry.py +13 -7
  4. meerschaum/_internal/shell/Shell.py +38 -44
  5. meerschaum/_internal/term/TermPageHandler.py +2 -3
  6. meerschaum/_internal/term/__init__.py +13 -11
  7. meerschaum/actions/api.py +10 -7
  8. meerschaum/actions/bootstrap.py +2 -1
  9. meerschaum/actions/delete.py +4 -1
  10. meerschaum/actions/register.py +1 -3
  11. meerschaum/actions/stack.py +24 -19
  12. meerschaum/actions/start.py +25 -26
  13. meerschaum/actions/sync.py +53 -52
  14. meerschaum/api/__init__.py +48 -14
  15. meerschaum/api/_events.py +15 -10
  16. meerschaum/api/_oauth2.py +2 -2
  17. meerschaum/api/_websockets.py +5 -4
  18. meerschaum/api/dash/__init__.py +1 -11
  19. meerschaum/api/dash/callbacks/dashboard.py +47 -55
  20. meerschaum/api/dash/callbacks/jobs.py +15 -16
  21. meerschaum/api/dash/callbacks/login.py +16 -10
  22. meerschaum/api/dash/callbacks/pipes.py +3 -4
  23. meerschaum/api/dash/callbacks/plugins.py +1 -1
  24. meerschaum/api/dash/callbacks/register.py +15 -11
  25. meerschaum/api/dash/components.py +54 -59
  26. meerschaum/api/dash/jobs.py +5 -9
  27. meerschaum/api/dash/pages/pipes.py +4 -1
  28. meerschaum/api/dash/pipes.py +13 -17
  29. meerschaum/api/dash/plugins.py +6 -4
  30. meerschaum/api/dash/sessions.py +176 -0
  31. meerschaum/api/dash/users.py +2 -53
  32. meerschaum/api/dash/webterm.py +12 -17
  33. meerschaum/api/resources/static/js/terminado.js +1 -1
  34. meerschaum/api/routes/_actions.py +4 -20
  35. meerschaum/api/routes/_jobs.py +8 -7
  36. meerschaum/api/routes/_webterm.py +5 -6
  37. meerschaum/config/_default.py +6 -1
  38. meerschaum/config/_version.py +1 -1
  39. meerschaum/config/stack/__init__.py +9 -7
  40. meerschaum/config/static/__init__.py +4 -0
  41. meerschaum/connectors/__init__.py +15 -9
  42. meerschaum/connectors/api/{APIConnector.py → _APIConnector.py} +3 -1
  43. meerschaum/connectors/api/__init__.py +2 -1
  44. meerschaum/connectors/parse.py +18 -16
  45. meerschaum/connectors/sql/__init__.py +3 -1
  46. meerschaum/connectors/sql/_pipes.py +39 -39
  47. meerschaum/connectors/valkey/{ValkeyConnector.py → _ValkeyConnector.py} +5 -5
  48. meerschaum/connectors/valkey/__init__.py +3 -1
  49. meerschaum/connectors/valkey/_pipes.py +13 -8
  50. meerschaum/core/Pipe/_data.py +155 -100
  51. meerschaum/jobs/_Job.py +1 -6
  52. meerschaum/jobs/__init__.py +7 -2
  53. meerschaum/utils/dataframe.py +4 -1
  54. meerschaum/utils/formatting/_shell.py +5 -6
  55. meerschaum/utils/packages/__init__.py +14 -9
  56. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/METADATA +1 -1
  57. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/RECORD +65 -65
  58. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/WHEEL +1 -1
  59. meerschaum/api/dash/actions.py +0 -255
  60. /meerschaum/connectors/{Connector.py → _Connector.py} +0 -0
  61. /meerschaum/connectors/sql/{SQLConnector.py → _SQLConnector.py} +0 -0
  62. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/LICENSE +0 -0
  63. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/NOTICE +0 -0
  64. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/entry_points.txt +0 -0
  65. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/top_level.txt +0 -0
  66. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/zip-safe +0 -0
@@ -7,28 +7,13 @@ Execute Meerschaum Actions via the API
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
- import asyncio
11
- import traceback
12
- import shlex
13
- from functools import partial
14
- from datetime import datetime, timezone
15
-
16
- from fastapi import WebSocket, WebSocketDisconnect
17
- from websockets.exceptions import ConnectionClosedError
18
-
19
- from meerschaum.utils.misc import generate_password
20
- from meerschaum.jobs import Job
21
- from meerschaum.utils.warnings import warn
22
- from meerschaum.utils.typing import SuccessTuple, Union, List, Dict, Any
10
+
11
+ from meerschaum.utils.typing import SuccessTuple, List, Dict, Any
23
12
  from meerschaum.api import (
24
13
  fastapi, app, endpoints, get_api_connector, debug, manager, private, no_auth
25
14
  )
26
15
  from meerschaum.actions import actions
27
- import meerschaum.core
28
16
  from meerschaum.config import get_config
29
- from meerschaum._internal.arguments._parse_arguments import parse_dict_to_sysargs, parse_arguments
30
- from meerschaum.api.routes._jobs import clean_sysargs
31
- from meerschaum.jobs._Job import StopMonitoringLogs
32
17
 
33
18
  actions_endpoint = endpoints['actions']
34
19
 
@@ -82,7 +67,7 @@ def do_action_legacy(
82
67
  ----------
83
68
  action: str
84
69
  The action to perform.
85
-
70
+
86
71
  keywords: Dict[str, Any]
87
72
  The keywords dictionary to pass to the action.
88
73
 
@@ -91,7 +76,6 @@ def do_action_legacy(
91
76
  A `SuccessTuple`.
92
77
  """
93
78
  if curr_user is not None and curr_user.type != 'admin':
94
- from meerschaum.config import get_config
95
79
  allow_non_admin = get_config(
96
80
  'system', 'api', 'permissions', 'actions', 'non_admin', patch=True
97
81
  )
@@ -103,7 +87,7 @@ def do_action_legacy(
103
87
  + "and search for 'permissions'. "
104
88
  + "\nUnder the keys 'api:permissions:actions', "
105
89
  + "you can allow non-admin users to perform actions."
106
- )
90
+ )
107
91
 
108
92
  if action not in actions:
109
93
  return False, f"Invalid action '{action}'."
@@ -9,7 +9,6 @@ Manage jobs via the Meerschaum API.
9
9
  from __future__ import annotations
10
10
 
11
11
  import os
12
- import select
13
12
  import asyncio
14
13
  import traceback
15
14
  from datetime import datetime
@@ -18,12 +17,10 @@ from functools import partial
18
17
 
19
18
  from fastapi import WebSocket, WebSocketDisconnect
20
19
 
21
- from meerschaum.utils.typing import Dict, Any, SuccessTuple, List, Optional, Union
20
+ from meerschaum.utils.typing import Dict, Any, SuccessTuple, List, Union
22
21
  from meerschaum.jobs import (
23
22
  get_jobs as _get_jobs,
24
23
  Job,
25
- StopMonitoringLogs,
26
- get_executor_keys_from_context,
27
24
  )
28
25
  from meerschaum.utils.warnings import warn
29
26
 
@@ -32,14 +29,13 @@ from meerschaum.api import (
32
29
  app,
33
30
  endpoints,
34
31
  manager,
35
- debug,
36
32
  no_auth,
37
- private,
38
33
  )
39
34
  from meerschaum.config.static import STATIC_CONFIG
40
35
 
41
36
  JOBS_STDIN_MESSAGE: str = STATIC_CONFIG['api']['jobs']['stdin_message']
42
37
  JOBS_STOP_MESSAGE: str = STATIC_CONFIG['api']['jobs']['stop_message']
38
+ NONINTERACTIVE_ENV: str = STATIC_CONFIG['environment']['noninteractive']
43
39
  EXECUTOR_KEYS: str = 'local'
44
40
 
45
41
 
@@ -48,7 +44,8 @@ def _get_job(name: str):
48
44
  if systemd_job.exists():
49
45
  return systemd_job
50
46
 
51
- return Job(name, executor_keys=EXECUTOR_KEYS)
47
+ job = Job(name, executor_keys=EXECUTOR_KEYS)
48
+ return job
52
49
 
53
50
 
54
51
  @app.get(endpoints['jobs'], tags=['Jobs'])
@@ -150,6 +147,10 @@ def create_job(
150
147
  name,
151
148
  clean_sysargs(sysargs),
152
149
  executor_keys=EXECUTOR_KEYS,
150
+ env={
151
+ NONINTERACTIVE_ENV: '1',
152
+ **dict(os.environ)
153
+ },
153
154
  _properties=properties,
154
155
  )
155
156
  if job.exists():
@@ -8,10 +8,9 @@ Routes to the Webterm proxy.
8
8
 
9
9
  import asyncio
10
10
  from meerschaum.utils.typing import Optional
11
- from meerschaum.api import app, no_auth, manager, endpoints
11
+ from meerschaum.api import app, endpoints
12
12
  from meerschaum.utils.packages import attempt_import
13
- from meerschaum.api.dash import active_sessions
14
- from meerschaum.api.dash.users import is_session_authenticated
13
+ from meerschaum.api.dash.sessions import is_session_authenticated
15
14
  fastapi, fastapi_responses = attempt_import('fastapi', 'fastapi.responses')
16
15
  import starlette
17
16
  httpx = attempt_import('httpx')
@@ -25,9 +24,9 @@ PlainTextResponse = fastapi_responses.PlainTextResponse
25
24
 
26
25
  @app.get(endpoints['webterm'], tags=["Webterm"])
27
26
  async def get_webterm(
28
- request: Request,
29
- s: Optional[str] = None,
30
- ) -> HTMLResponse:
27
+ request: Request,
28
+ s: Optional[str] = None,
29
+ ) -> HTMLResponse:
31
30
  """
32
31
  Get the main HTML template for the Webterm.
33
32
  """
@@ -96,6 +96,10 @@ default_system_config = {
96
96
  'proxy_headers': True,
97
97
  'forwarded_allow_ips': '*',
98
98
  },
99
+ 'cache': {
100
+ 'connector': 'valkey:main',
101
+ 'session_expires_minutes': 43200,
102
+ },
99
103
  'permissions': {
100
104
  'registration': {
101
105
  'users': True,
@@ -105,7 +109,7 @@ default_system_config = {
105
109
  'actions': {
106
110
  'non_admin': True,
107
111
  },
108
- 'chaining' : {
112
+ 'chaining': {
109
113
  'insecure_parent_instance': False,
110
114
  'child_apis': False,
111
115
  },
@@ -120,6 +124,7 @@ default_system_config = {
120
124
  'inplace_sync': True,
121
125
  'uv_pip': True,
122
126
  'systemd_healthcheck': False,
127
+ 'valkey_session_cache': True,
123
128
  },
124
129
  }
125
130
  default_pipes_config = {
@@ -2,4 +2,4 @@
2
2
  Specify the Meerschaum release version.
3
3
  """
4
4
 
5
- __version__ = "2.4.0.dev1"
5
+ __version__ = "2.4.0rc2"
@@ -52,8 +52,8 @@ env_dict = {
52
52
  ### apply patch to host config to change hostname to the Docker service name
53
53
  env_dict['MEERSCHAUM_API_CONFIG'] = json.dumps(
54
54
  {
55
- 'meerschaum' : 'MRSM{!meerschaum}',
56
- 'system' : 'MRSM{!system}',
55
+ 'meerschaum': 'MRSM{!meerschaum}',
56
+ 'system': 'MRSM{!system}',
57
57
  },
58
58
  indent = 4,
59
59
  ).replace(
@@ -82,12 +82,14 @@ env_dict['MEERSCHAUM_API_PATCH'] = json.dumps(
82
82
  'port': 5432,
83
83
  },
84
84
  'local': {
85
- 'database': volumes['api_root'] + '/sqlite/mrsm_local.db'
85
+ 'database': volumes['api_root'] + '/sqlite/mrsm_local.db',
86
86
  },
87
87
  },
88
88
  'valkey': {
89
- 'host': valkey_host,
90
- 'port': 6379,
89
+ 'main': {
90
+ 'host': valkey_host,
91
+ 'port': 6379,
92
+ },
91
93
  },
92
94
  },
93
95
  },
@@ -133,7 +135,7 @@ default_docker_compose_config = {
133
135
  'ports': [
134
136
  f'{db_port}:5432',
135
137
  ],
136
- 'hostname': f'{db_hostname}',
138
+ 'hostname': db_hostname,
137
139
  'volumes': [
138
140
  'meerschaum_db_data:' + volumes['meerschaum_db_data'],
139
141
  ],
@@ -178,7 +180,7 @@ default_docker_compose_config = {
178
180
  ],
179
181
  },
180
182
  'valkey': {
181
- 'image': 'bitnami/valkey',
183
+ 'image': 'bitnami/valkey:latest',
182
184
  'restart': 'always',
183
185
  'environment': {
184
186
  'VALKEY_PASSWORD': '<DOLLAR>VALKEY_PASSWORD',
@@ -53,6 +53,9 @@ STATIC_CONFIG: Dict[str, Any] = {
53
53
  'internal_schema': '_mrsm_internal',
54
54
  'instance_schema': 'mrsm',
55
55
  },
56
+ 'valkey': {
57
+ 'colon': '-_',
58
+ },
56
59
  'environment': {
57
60
  'config': 'MRSM_CONFIG',
58
61
  'config_dir': 'MRSM_CONFIG_DIR',
@@ -69,6 +72,7 @@ STATIC_CONFIG: Dict[str, Any] = {
69
72
  'uid': 'MRSM_UID',
70
73
  'gid': 'MRSM_GID',
71
74
  'noask': 'MRSM_NOASK',
75
+ 'noninteractive': 'MRSM_NONINTERACTIVE',
72
76
  'id': 'MRSM_SERVER_ID',
73
77
  'daemon_id': 'MRSM_DAEMON_ID',
74
78
  'systemd_log_path': 'MRSM_SYSTEMD_LOG_PATH',
@@ -14,13 +14,13 @@ For ease of use, you can also import from the root `meerschaum` module:
14
14
  from __future__ import annotations
15
15
 
16
16
  import meerschaum as mrsm
17
- from meerschaum.utils.typing import Any, SuccessTuple, Union, Optional, List, Dict
18
- from meerschaum.utils.threading import Lock, RLock
19
- from meerschaum.utils.warnings import error, warn
17
+ from meerschaum.utils.typing import Any, Union, List, Dict
18
+ from meerschaum.utils.threading import RLock
19
+ from meerschaum.utils.warnings import warn
20
20
 
21
- from meerschaum.connectors.Connector import Connector, InvalidAttributesError
22
- from meerschaum.connectors.sql.SQLConnector import SQLConnector
23
- from meerschaum.connectors.api.APIConnector import APIConnector
21
+ from meerschaum.connectors._Connector import Connector, InvalidAttributesError
22
+ from meerschaum.connectors.sql._SQLConnector import SQLConnector
23
+ from meerschaum.connectors.api._APIConnector import APIConnector
24
24
  from meerschaum.connectors.sql._create_engine import flavor_configs as sql_flavor_configs
25
25
 
26
26
  __all__ = (
@@ -31,6 +31,9 @@ __all__ = (
31
31
  "get_connector",
32
32
  "is_connected",
33
33
  "poll",
34
+ "api",
35
+ "sql",
36
+ "valkey",
34
37
  )
35
38
 
36
39
  ### store connectors partitioned by
@@ -54,7 +57,10 @@ attributes: Dict[str, Dict[str, Any]] = {
54
57
  'required': [
55
58
  'host',
56
59
  'username',
57
- 'password'
60
+ 'password',
61
+ ],
62
+ 'optional': [
63
+ 'port',
58
64
  ],
59
65
  'default': {
60
66
  'protocol': 'http',
@@ -263,11 +269,11 @@ def is_connected(keys: str, **kw) -> bool:
263
269
 
264
270
  try:
265
271
  typ, label = keys.split(':')
266
- except Exception as e:
272
+ except Exception:
267
273
  return False
268
274
  if typ not in instance_types:
269
275
  return False
270
- if not (label in connectors.get(typ, {})):
276
+ if label not in connectors.get(typ, {}):
271
277
  return False
272
278
 
273
279
  from meerschaum.connectors.parse import parse_instance_keys
@@ -7,7 +7,7 @@ Interact with Meerschaum APIs. May be chained together (see 'meerschaum:api_inst
7
7
  """
8
8
 
9
9
  from datetime import datetime, timedelta, timezone
10
- from meerschaum.utils.typing import Optional
10
+ from meerschaum.utils.typing import Optional, List
11
11
  from meerschaum.connectors import Connector
12
12
  from meerschaum.utils.warnings import warn, error
13
13
  from meerschaum.utils.packages import attempt_import
@@ -24,6 +24,8 @@ class APIConnector(Connector):
24
24
  IS_INSTANCE: bool = True
25
25
  IS_THREAD_SAFE: bool = False
26
26
 
27
+ OPTIONAL_ATTRIBUTES: List[str] = ['port']
28
+
27
29
  from ._request import (
28
30
  make_request,
29
31
  get,
@@ -6,5 +6,6 @@
6
6
  Interact with the Meerschaum API (send commands, pull data, etc.)
7
7
  """
8
8
 
9
- from meerschaum.connectors.api.APIConnector import APIConnector
9
+ from meerschaum.connectors.api._APIConnector import APIConnector
10
10
 
11
+ __all__ = ('APIConnector',)
@@ -7,7 +7,10 @@ Utility functions for parsing connector keys.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
- from meerschaum.utils.typing import Mapping, Any, SuccessTuple, Union, Optional, Dict, Tuple
10
+
11
+ import meerschaum as mrsm
12
+ from meerschaum.utils.typing import Any, Union, Optional, Dict, Tuple
13
+
11
14
 
12
15
  def parse_connector_keys(
13
16
  keys: str,
@@ -15,20 +18,20 @@ def parse_connector_keys(
15
18
  as_tuple: bool = False,
16
19
  **kw: Any
17
20
  ) -> (
18
- Union[
19
- meerschaum.connectors.Connector,
20
- Dict[str, Any],
21
- Tuple[
22
- Union[
23
- meerschaum.connectors.Connector,
24
- Dict[str, Any],
25
- None
26
- ],
27
- str
21
+ Union[
22
+ mrsm.connectors.Connector,
23
+ Dict[str, Any],
24
+ Tuple[
25
+ Union[
26
+ mrsm.connectors.Connector,
27
+ Dict[str, Any],
28
+ None,
28
29
  ],
29
- None
30
- ]
31
- ):
30
+ str
31
+ ],
32
+ None
33
+ ]
34
+ ):
32
35
  """
33
36
  Convenience function for parsing connector keys and returning Connector objects.
34
37
 
@@ -95,13 +98,12 @@ def parse_instance_keys(
95
98
  """
96
99
  Parse the Meerschaum instance value into a Connector object.
97
100
  """
98
- from meerschaum.utils.warnings import warn
99
101
  from meerschaum.config import get_config
100
102
 
101
103
  if keys is None:
102
104
  keys = get_config('meerschaum', 'instance')
103
105
  keys = str(keys)
104
-
106
+
105
107
  return parse_connector_keys(keys, construct=construct, as_tuple=as_tuple, **kw)
106
108
 
107
109
 
@@ -6,4 +6,6 @@
6
6
  Subpackage for SQLConnector subclass
7
7
  """
8
8
 
9
- from meerschaum.connectors.sql.SQLConnector import SQLConnector
9
+ from meerschaum.connectors.sql._SQLConnector import SQLConnector
10
+
11
+ __all__ = ('SQLConnector',)
@@ -821,7 +821,8 @@ def get_pipe_data_query(
821
821
  begin: Union[datetime, int, str, None] = None,
822
822
  end: Union[datetime, int, str, None] = None,
823
823
  params: Optional[Dict[str, Any]] = None,
824
- order: str = 'asc',
824
+ order: Optional[str] = 'asc',
825
+ sort_datetimes: bool = False,
825
826
  limit: Optional[int] = None,
826
827
  begin_add_minutes: int = 0,
827
828
  end_add_minutes: int = 0,
@@ -854,10 +855,13 @@ def get_pipe_data_query(
854
855
  Additional parameters to filter by.
855
856
  See `meerschaum.connectors.sql.build_where`.
856
857
 
857
- order: Optional[str], default 'asc'
858
+ order: Optional[str], default None
858
859
  The selection order for all of the indices in the query.
859
860
  If `None`, omit the `ORDER BY` clause.
860
861
 
862
+ sort_datetimes: bool, default False
863
+ Alias for `order='desc'`.
864
+
861
865
  limit: Optional[int], default None
862
866
  If specified, limit the number of rows retrieved to this value.
863
867
 
@@ -880,7 +884,6 @@ def get_pipe_data_query(
880
884
  -------
881
885
  A `SELECT` query to retrieve a pipe's data.
882
886
  """
883
- import json
884
887
  from meerschaum.utils.debug import dprint
885
888
  from meerschaum.utils.misc import items_str
886
889
  from meerschaum.utils.sql import sql_item_name, dateadd_str
@@ -895,6 +898,9 @@ def get_pipe_data_query(
895
898
  if omit_columns:
896
899
  select_columns = [col for col in select_columns if col not in omit_columns]
897
900
 
901
+ if order is None and sort_datetimes:
902
+ order = 'desc'
903
+
898
904
  if begin == '':
899
905
  begin = pipe.get_sync_time(debug=debug)
900
906
  backtrack_interval = pipe.get_backtrack_interval(debug=debug)
@@ -960,10 +966,10 @@ def get_pipe_data_query(
960
966
  is_dt_bound = False
961
967
  if begin is not None and _dt in existing_cols:
962
968
  begin_da = dateadd_str(
963
- flavor = self.flavor,
964
- datepart = 'minute',
965
- number = begin_add_minutes,
966
- begin = begin
969
+ flavor=self.flavor,
970
+ datepart='minute',
971
+ number=begin_add_minutes,
972
+ begin=begin,
967
973
  )
968
974
  where += f"{dt} >= {begin_da}" + (" AND " if end is not None else "")
969
975
  is_dt_bound = True
@@ -972,10 +978,10 @@ def get_pipe_data_query(
972
978
  if 'int' in str(type(end)).lower() and end == begin:
973
979
  end += 1
974
980
  end_da = dateadd_str(
975
- flavor = self.flavor,
976
- datepart = 'minute',
977
- number = end_add_minutes,
978
- begin = end
981
+ flavor=self.flavor,
982
+ datepart='minute',
983
+ number=end_add_minutes,
984
+ begin=end
979
985
  )
980
986
  where += f"{dt} < {end_da}"
981
987
  is_dt_bound = True
@@ -1599,45 +1605,39 @@ def sync_pipe_inplace(
1599
1605
 
1600
1606
  backtrack_def = self.get_pipe_data_query(
1601
1607
  pipe,
1602
- begin = begin,
1603
- end = end,
1604
- begin_add_minutes = 0,
1605
- end_add_minutes = 1,
1606
- params = params,
1607
- debug = debug,
1608
- order = None,
1608
+ begin=begin,
1609
+ end=end,
1610
+ begin_add_minutes=0,
1611
+ end_add_minutes=1,
1612
+ params=params,
1613
+ debug=debug,
1614
+ order=None,
1609
1615
  )
1610
1616
 
1611
- select_backtrack_query = format_cte_subquery(
1612
- backtrack_def,
1613
- self.flavor,
1614
- sub_name = 'backtrack_def',
1615
- )
1616
1617
  create_backtrack_query = get_create_table_query(
1617
1618
  backtrack_def,
1618
1619
  temp_tables['backtrack'],
1619
1620
  self.flavor,
1620
- schema = internal_schema,
1621
+ schema=internal_schema,
1621
1622
  )
1622
1623
  (create_backtrack_success, create_backtrack_msg), create_backtrack_results = session_execute(
1623
1624
  session,
1624
1625
  create_backtrack_query,
1625
- with_results = True,
1626
- debug = debug,
1626
+ with_results=True,
1627
+ debug=debug,
1627
1628
  ) if not upsert else (True, "Success"), None
1628
1629
 
1629
1630
  if not create_backtrack_success:
1630
1631
  _ = clean_up_temp_tables()
1631
1632
  return create_backtrack_success, create_backtrack_msg
1632
- bactrack_count = create_backtrack_results[0].rowcount if create_backtrack_results else 0
1633
1633
 
1634
1634
  backtrack_cols_types = get_table_cols_types(
1635
1635
  temp_tables['backtrack'],
1636
- connectable = connectable,
1637
- flavor = self.flavor,
1638
- schema = internal_schema,
1639
- database = database,
1640
- debug = debug,
1636
+ connectable=connectable,
1637
+ flavor=self.flavor,
1638
+ schema=internal_schema,
1639
+ database=database,
1640
+ debug=debug,
1641
1641
  ) if not upsert else new_cols_types
1642
1642
 
1643
1643
  common_cols = [col for col in new_cols if col in backtrack_cols_types]
@@ -1663,7 +1663,7 @@ def sync_pipe_inplace(
1663
1663
  )
1664
1664
 
1665
1665
  select_delta_query = (
1666
- f"SELECT\n"
1666
+ "SELECT\n"
1667
1667
  + null_replace_new_cols_str + "\n"
1668
1668
  + f"\nFROM {temp_table_names['new']}\n"
1669
1669
  + f"LEFT OUTER JOIN {temp_table_names['backtrack']}\nON\n"
@@ -1693,12 +1693,12 @@ def sync_pipe_inplace(
1693
1693
  select_delta_query,
1694
1694
  temp_tables['delta'],
1695
1695
  self.flavor,
1696
- schema = internal_schema,
1696
+ schema=internal_schema,
1697
1697
  )
1698
1698
  create_delta_success, create_delta_msg = session_execute(
1699
1699
  session,
1700
1700
  create_delta_query,
1701
- debug = debug,
1701
+ debug=debug,
1702
1702
  ) if not upsert else (True, "Success")
1703
1703
  if not create_delta_success:
1704
1704
  _ = clean_up_temp_tables()
@@ -1707,10 +1707,10 @@ def sync_pipe_inplace(
1707
1707
  delta_cols_types = get_table_cols_types(
1708
1708
  temp_tables['delta'],
1709
1709
  connectable = connectable,
1710
- flavor = self.flavor,
1711
- schema = internal_schema,
1712
- database = database,
1713
- debug = debug,
1710
+ flavor=self.flavor,
1711
+ schema=internal_schema,
1712
+ database=database,
1713
+ debug=debug,
1714
1714
  ) if not upsert else new_cols_types
1715
1715
 
1716
1716
  ### This is a weird bug on SQLite.
@@ -11,9 +11,8 @@ from datetime import datetime, timezone
11
11
 
12
12
  import meerschaum as mrsm
13
13
  from meerschaum.connectors import Connector, make_connector
14
- from meerschaum.utils.typing import List, Dict, Any, Iterator, Optional, Union
15
- from meerschaum.utils.warnings import warn, dprint
16
- from meerschaum.utils.misc import json_serialize_datetime
14
+ from meerschaum.utils.typing import List, Dict, Any, Optional, Union
15
+ from meerschaum.utils.warnings import dprint
17
16
 
18
17
 
19
18
  @make_connector
@@ -141,11 +140,11 @@ class ValkeyConnector(Connector):
141
140
 
142
141
  return uri
143
142
 
144
- def set(self, key: str, value: Any) -> None:
143
+ def set(self, key: str, value: Any, **kwargs: Any) -> None:
145
144
  """
146
145
  Set the `key` to `value`.
147
146
  """
148
- return self.client.set(key, value)
147
+ return self.client.set(key, value, **kwargs)
149
148
 
150
149
  def get(self, key: str) -> Union[str, None]:
151
150
  """
@@ -243,6 +242,7 @@ class ValkeyConnector(Connector):
243
242
  -------
244
243
  The current index counter value (how many docs have been pushed).
245
244
  """
245
+ from meerschaum.utils.misc import json_serialize_datetime
246
246
  table_name = self.quote_table(table)
247
247
  datetime_column_key = self.get_datetime_column_key(table)
248
248
  remote_datetime_column = self.get(datetime_column_key)
@@ -5,4 +5,6 @@
5
5
  Import the `ValkeyConnector`.
6
6
  """
7
7
 
8
- from meerschaum.connectors.valkey.ValkeyConnector import ValkeyConnector
8
+ from meerschaum.connectors.valkey._ValkeyConnector import ValkeyConnector
9
+
10
+ __all__ = ('ValkeyConnector',)
@@ -6,15 +6,17 @@ Define pipes methods for `ValkeyConnector`.
6
6
  """
7
7
 
8
8
  import json
9
- from datetime import datetime, timedelta, timezone
9
+ from datetime import datetime, timezone
10
10
 
11
11
  import meerschaum as mrsm
12
12
  from meerschaum.utils.typing import SuccessTuple, Any, Union, Optional, Dict, List, Tuple
13
13
  from meerschaum.utils.misc import json_serialize_datetime, string_to_dict
14
- from meerschaum.utils.warnings import dprint, warn
14
+ from meerschaum.utils.warnings import warn
15
+ from meerschaum.config.static import STATIC_CONFIG
15
16
 
16
17
  PIPES_TABLE: str = 'mrsm_pipes'
17
18
  PIPES_COUNTER: str = 'mrsm_pipes:counter'
19
+ COLON: str = STATIC_CONFIG['valkey']['colon']
18
20
 
19
21
 
20
22
  def get_pipe_key(pipe: mrsm.Pipe) -> str:
@@ -88,7 +90,7 @@ def get_document_key(
88
90
  indices_str = ((table_name + ':indices:') if table_name else '') + ','.join(
89
91
  sorted(
90
92
  [
91
- f'{key}:{val}'
93
+ f'{key}{COLON}{val}'
92
94
  for key, val in index_vals.items()
93
95
  ]
94
96
  )
@@ -413,7 +415,7 @@ def get_pipe_data(
413
415
  table_name = self.quote_table(pipe.target)
414
416
  indices = [col for col in pipe.columns.values() if col]
415
417
  ix_docs = [
416
- string_to_dict(doc['ix'])
418
+ string_to_dict(doc['ix'].replace(COLON, ':'))
417
419
  for doc in self.read_docs(
418
420
  pipe.target,
419
421
  begin=begin,
@@ -505,6 +507,7 @@ def sync_pipe(
505
507
  is_dask = 'dask' in df.__module__
506
508
  if is_dask:
507
509
  df = df.compute()
510
+ upsert = pipe.parameters.get('upsert', False)
508
511
 
509
512
  def _serialize_indices_docs(_docs):
510
513
  return [
@@ -546,16 +549,18 @@ def sync_pipe(
546
549
  if not edit_success:
547
550
  return edit_success, edit_msg
548
551
 
549
- # df = pipe.enforce_dtypes(df, debug=debug)
550
-
551
552
  unseen_df, update_df, delta_df = (
552
553
  pipe.filter_existing(df, include_unchanged_columns=True, debug=debug)
553
- if check_existing
554
+ if check_existing and not upsert
554
555
  else (df, None, df)
555
556
  )
556
557
  num_insert = len(unseen_df) if unseen_df is not None else 0
557
558
  num_update = len(update_df) if update_df is not None else 0
558
- msg = f"Inserted {num_insert}, updated {num_update} rows."
559
+ msg = (
560
+ f"Inserted {num_insert}, updated {num_update} rows."
561
+ if not upsert
562
+ else f"Upserted {num_insert} rows."
563
+ )
559
564
  if len(delta_df) == 0:
560
565
  return True, msg
561
566