meerschaum 2.3.6__py3-none-any.whl → 2.4.0.dev1__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 (53) hide show
  1. meerschaum/actions/bootstrap.py +36 -10
  2. meerschaum/actions/copy.py +3 -3
  3. meerschaum/actions/start.py +13 -14
  4. meerschaum/api/dash/__init__.py +7 -6
  5. meerschaum/api/dash/callbacks/__init__.py +1 -0
  6. meerschaum/api/dash/callbacks/dashboard.py +7 -5
  7. meerschaum/api/dash/callbacks/pipes.py +42 -0
  8. meerschaum/api/dash/pages/__init__.py +1 -0
  9. meerschaum/api/dash/pages/pipes.py +16 -0
  10. meerschaum/api/dash/pipes.py +79 -47
  11. meerschaum/api/dash/users.py +19 -6
  12. meerschaum/api/routes/_login.py +4 -4
  13. meerschaum/api/routes/_pipes.py +3 -3
  14. meerschaum/config/_default.py +9 -1
  15. meerschaum/config/_version.py +1 -1
  16. meerschaum/config/stack/__init__.py +59 -16
  17. meerschaum/connectors/Connector.py +19 -13
  18. meerschaum/connectors/__init__.py +9 -5
  19. meerschaum/connectors/poll.py +30 -24
  20. meerschaum/connectors/sql/_pipes.py +126 -154
  21. meerschaum/connectors/sql/_plugins.py +45 -43
  22. meerschaum/connectors/sql/_users.py +46 -38
  23. meerschaum/connectors/valkey/ValkeyConnector.py +535 -0
  24. meerschaum/connectors/valkey/__init__.py +8 -0
  25. meerschaum/connectors/valkey/_fetch.py +75 -0
  26. meerschaum/connectors/valkey/_pipes.py +839 -0
  27. meerschaum/connectors/valkey/_plugins.py +265 -0
  28. meerschaum/connectors/valkey/_users.py +305 -0
  29. meerschaum/core/Pipe/__init__.py +3 -0
  30. meerschaum/core/Pipe/_attributes.py +1 -2
  31. meerschaum/core/Pipe/_clear.py +16 -13
  32. meerschaum/core/Pipe/_copy.py +106 -0
  33. meerschaum/core/Pipe/_drop.py +4 -4
  34. meerschaum/core/Pipe/_dtypes.py +14 -14
  35. meerschaum/core/Pipe/_edit.py +15 -14
  36. meerschaum/core/Pipe/_sync.py +134 -51
  37. meerschaum/core/Pipe/_verify.py +11 -11
  38. meerschaum/core/User/_User.py +14 -12
  39. meerschaum/plugins/_Plugin.py +17 -13
  40. meerschaum/utils/_get_pipes.py +14 -20
  41. meerschaum/utils/dataframe.py +288 -101
  42. meerschaum/utils/dtypes/__init__.py +31 -6
  43. meerschaum/utils/dtypes/sql.py +4 -4
  44. meerschaum/utils/misc.py +3 -3
  45. meerschaum/utils/packages/_packages.py +1 -0
  46. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/METADATA +3 -1
  47. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/RECORD +53 -44
  48. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/WHEEL +1 -1
  49. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/LICENSE +0 -0
  50. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/NOTICE +0 -0
  51. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/entry_points.txt +0 -0
  52. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/top_level.txt +0 -0
  53. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/zip-safe +0 -0
@@ -31,15 +31,23 @@ db_host = 'MRSM{stack:' + str(STACK_COMPOSE_FILENAME) + ':services:db:hostname}'
31
31
  api_port = "MRSM{meerschaum:connectors:api:main:port}"
32
32
  api_host = "api"
33
33
 
34
+ valkey_hostname = "valkey"
35
+ valkey_host = 'MRSM{stack:' + str(STACK_COMPOSE_FILENAME) + ':services:valkey:hostname}'
36
+ valkey_port = "MRSM{meerschaum:connectors:valkey:main:port}"
37
+ valkey_username = 'MRSM{meerschaum:connectors:valkey:main:username}'
38
+ valkey_password = 'MRSM{meerschaum:connectors:valkey:main:password}'
39
+
34
40
  env_dict = {
35
- 'COMPOSE_PROJECT_NAME' : 'mrsm',
36
- 'TIMESCALEDB_VERSION' : 'latest-pg16-oss',
37
- 'POSTGRES_USER' : f'{db_user}',
38
- 'POSTGRES_PASSWORD' : f'{db_pass}',
39
- 'POSTGRES_DB' : f'{db_base}',
40
- 'MEERSCHAUM_API_HOSTNAME' : f'{api_host}',
41
- 'ALLOW_IP_RANGE' : '0.0.0.0/0',
42
- 'MEERSCHAUM_API_CONFIG_RESOURCES' : '/meerschaum',
41
+ 'COMPOSE_PROJECT_NAME': 'mrsm',
42
+ 'TIMESCALEDB_VERSION': 'latest-pg16-oss',
43
+ 'POSTGRES_USER': db_user,
44
+ 'POSTGRES_PASSWORD': db_pass,
45
+ 'POSTGRES_DB': db_base,
46
+ 'VALKEY_USERNAME': valkey_username,
47
+ 'VALKEY_PASSWORD': valkey_password,
48
+ 'MEERSCHAUM_API_HOSTNAME': api_host,
49
+ 'ALLOW_IP_RANGE': '0.0.0.0/0',
50
+ 'MEERSCHAUM_API_CONFIG_RESOURCES': '/meerschaum',
43
51
  }
44
52
  ### apply patch to host config to change hostname to the Docker service name
45
53
  env_dict['MEERSCHAUM_API_CONFIG'] = json.dumps(
@@ -58,6 +66,7 @@ volumes = {
58
66
  'api_root': '/meerschaum',
59
67
  'meerschaum_db_data': '/var/lib/postgresql/data',
60
68
  'grafana_storage': '/var/lib/grafana',
69
+ 'valkey_data': '/bitnami/valkey/data',
61
70
  }
62
71
  networks = {
63
72
  'frontend': None,
@@ -76,10 +85,14 @@ env_dict['MEERSCHAUM_API_PATCH'] = json.dumps(
76
85
  'database': volumes['api_root'] + '/sqlite/mrsm_local.db'
77
86
  },
78
87
  },
88
+ 'valkey': {
89
+ 'host': valkey_host,
90
+ 'port': 6379,
91
+ },
79
92
  },
80
93
  },
81
94
  },
82
- indent = 4,
95
+ indent=4,
83
96
  )
84
97
 
85
98
  compose_header = """
@@ -113,19 +126,19 @@ default_docker_compose_config = {
113
126
  ],
114
127
  'interval': '5s',
115
128
  'timeout': '3s',
116
- 'retries': 3
129
+ 'retries': 5
117
130
  },
118
131
  'restart': 'always',
119
- 'image' : 'timescale/timescaledb:' + env_dict['TIMESCALEDB_VERSION'],
120
- 'ports' : [
132
+ 'image': 'timescale/timescaledb:' + env_dict['TIMESCALEDB_VERSION'],
133
+ 'ports': [
121
134
  f'{db_port}:5432',
122
135
  ],
123
- 'hostname' : f'{db_hostname}',
124
- 'volumes' : [
136
+ 'hostname': f'{db_hostname}',
137
+ 'volumes': [
125
138
  'meerschaum_db_data:' + volumes['meerschaum_db_data'],
126
139
  ],
127
140
  'shm_size': '1024m',
128
- 'networks' : [
141
+ 'networks': [
129
142
  'backend',
130
143
  ],
131
144
  },
@@ -156,11 +169,41 @@ default_docker_compose_config = {
156
169
  'db': {
157
170
  'condition': 'service_healthy',
158
171
  },
172
+ 'valkey': {
173
+ 'condition': 'service_healthy',
174
+ },
159
175
  },
160
- 'volumes' : [
176
+ 'volumes': [
161
177
  'api_root:' + volumes['api_root'],
162
178
  ],
163
179
  },
180
+ 'valkey': {
181
+ 'image': 'bitnami/valkey',
182
+ 'restart': 'always',
183
+ 'environment': {
184
+ 'VALKEY_PASSWORD': '<DOLLAR>VALKEY_PASSWORD',
185
+ 'VALKEY_RDB_POLICY_DISABLED': 'no',
186
+ 'VALKEY_RDB_POLICY': '900#1 600#5 300#10 120#50 60#1000 30#10000',
187
+ },
188
+ 'hostname': valkey_hostname,
189
+ 'ports': [
190
+ f'{valkey_port}:6379',
191
+ ],
192
+ 'volumes': [
193
+ 'valkey_data:' + volumes['valkey_data'],
194
+ ],
195
+ 'healthcheck': {
196
+ 'test': [
197
+ 'CMD', 'valkey-cli', 'ping',
198
+ ],
199
+ 'interval': '5s',
200
+ 'timeout': '3s',
201
+ 'retries': 5,
202
+ },
203
+ 'networks': [
204
+ 'backend',
205
+ ],
206
+ },
164
207
  'grafana': {
165
208
  'image': 'grafana/grafana:latest',
166
209
  'ports': [
@@ -53,17 +53,23 @@ class Connector(metaclass=abc.ABCMeta):
53
53
  """
54
54
  self._original_dict = copy.deepcopy(self.__dict__)
55
55
  self._set_attributes(type=type, label=label, **kw)
56
- self.verify_attributes(getattr(self, 'REQUIRED_ATTRIBUTES', None))
56
+
57
+ ### NOTE: Override `REQUIRED_ATTRIBUTES` if `uri` is set.
58
+ self.verify_attributes(
59
+ ['uri']
60
+ if 'uri' in self.__dict__
61
+ else getattr(self, 'REQUIRED_ATTRIBUTES', None)
62
+ )
57
63
 
58
64
  def _reset_attributes(self):
59
65
  self.__dict__ = self._original_dict
60
66
 
61
67
  def _set_attributes(
62
- self,
63
- *args,
64
- inherit_default: bool = True,
65
- **kw: Any
66
- ):
68
+ self,
69
+ *args,
70
+ inherit_default: bool = True,
71
+ **kw: Any
72
+ ):
67
73
  from meerschaum.config.static import STATIC_CONFIG
68
74
  from meerschaum.utils.warnings import error
69
75
 
@@ -114,12 +120,11 @@ class Connector(metaclass=abc.ABCMeta):
114
120
  ### finally, update __dict__ with _attributes.
115
121
  self.__dict__.update(self._attributes)
116
122
 
117
-
118
123
  def verify_attributes(
119
- self,
120
- required_attributes: Optional[List[str]] = None,
121
- debug: bool = False
122
- ) -> None:
124
+ self,
125
+ required_attributes: Optional[List[str]] = None,
126
+ debug: bool = False,
127
+ ) -> None:
123
128
  """
124
129
  Ensure that the required attributes have been met.
125
130
 
@@ -147,6 +152,7 @@ class Connector(metaclass=abc.ABCMeta):
147
152
  from meerschaum.utils.misc import items_str
148
153
  if required_attributes is None:
149
154
  required_attributes = ['label']
155
+
150
156
  missing_attributes = set()
151
157
  for a in required_attributes:
152
158
  if a not in self.__dict__:
@@ -158,8 +164,8 @@ class Connector(metaclass=abc.ABCMeta):
158
164
  + f"for connector '{self.type}:{self.label}'."
159
165
  ),
160
166
  InvalidAttributesError,
161
- silent = True,
162
- stack = False
167
+ silent=True,
168
+ stack=False
163
169
  )
164
170
 
165
171
 
@@ -39,6 +39,7 @@ connectors: Dict[str, Dict[str, Connector]] = {
39
39
  'api' : {},
40
40
  'sql' : {},
41
41
  'plugin' : {},
42
+ 'valkey' : {},
42
43
  }
43
44
  instance_types: List[str] = ['sql', 'api']
44
45
  _locks: Dict[str, RLock] = {
@@ -164,13 +165,15 @@ def get_connector(
164
165
 
165
166
  if 'sql' not in types:
166
167
  from meerschaum.connectors.plugin import PluginConnector
168
+ from meerschaum.connectors.valkey import ValkeyConnector
167
169
  with _locks['types']:
168
170
  types.update({
169
- 'api' : APIConnector,
170
- 'sql' : SQLConnector,
171
+ 'api': APIConnector,
172
+ 'sql': SQLConnector,
171
173
  'plugin': PluginConnector,
174
+ 'valkey': ValkeyConnector,
172
175
  })
173
-
176
+
174
177
  ### determine if we need to call the constructor
175
178
  if not refresh:
176
179
  ### see if any user-supplied arguments differ from the existing instance
@@ -273,7 +276,7 @@ def is_connected(keys: str, **kw) -> bool:
273
276
  with warnings.catch_warnings():
274
277
  warnings.filterwarnings('ignore')
275
278
  return conn.test_connection(**kw)
276
- except Exception as e:
279
+ except Exception:
277
280
  return False
278
281
 
279
282
 
@@ -340,7 +343,7 @@ def load_plugin_connectors():
340
343
  to_import.append(plugin.name)
341
344
  if not to_import:
342
345
  return
343
- import_plugins(*to_import)
346
+ import_plugins(*to_import)
344
347
 
345
348
 
346
349
  def get_connector_plugin(
@@ -378,3 +381,4 @@ def _load_builtin_custom_connectors():
378
381
  Import custom connectors decorated with `@make_connector` or `@make_executor`.
379
382
  """
380
383
  import meerschaum.jobs.systemd
384
+ import meerschaum.connectors.valkey
@@ -9,16 +9,16 @@ Poll database and API connections.
9
9
  from meerschaum.utils.typing import InstanceConnector, Union, Optional, Dict, Any
10
10
 
11
11
  def retry_connect(
12
- connector: Union[InstanceConnector, None] = None,
13
- max_retries: int = 50,
14
- retry_wait: int = 3,
15
- workers: int = 1,
16
- warn: bool = True,
17
- print_on_connect: bool = False,
18
- enforce_chaining: bool = True,
19
- enforce_login: bool = True,
20
- debug: bool = False,
21
- ) -> bool:
12
+ connector: Union[InstanceConnector, None] = None,
13
+ max_retries: int = 50,
14
+ retry_wait: int = 3,
15
+ workers: int = 1,
16
+ warn: bool = True,
17
+ print_on_connect: bool = False,
18
+ enforce_chaining: bool = True,
19
+ enforce_login: bool = True,
20
+ debug: bool = False,
21
+ ) -> bool:
22
22
  """
23
23
  Keep trying to connect to the database.
24
24
 
@@ -85,16 +85,16 @@ def retry_connect(
85
85
 
86
86
 
87
87
  def _wrap_retry_connect(
88
- connector_meta: Dict[str, Any],
89
- max_retries: int = 50,
90
- retry_wait: int = 3,
91
- workers: int = 1,
92
- print_on_connect: bool = False,
93
- warn: bool = True,
94
- enforce_chaining: bool = True,
95
- enforce_login: bool = True,
96
- debug: bool = False,
97
- ) -> bool:
88
+ connector_meta: Dict[str, Any],
89
+ max_retries: int = 50,
90
+ retry_wait: int = 3,
91
+ workers: int = 1,
92
+ print_on_connect: bool = False,
93
+ warn: bool = True,
94
+ enforce_chaining: bool = True,
95
+ enforce_login: bool = True,
96
+ debug: bool = False,
97
+ ) -> bool:
98
98
  """
99
99
  Keep trying to connect to the database.
100
100
 
@@ -144,8 +144,6 @@ def _wrap_retry_connect(
144
144
  import time
145
145
 
146
146
  connector = get_connector(**connector_meta)
147
- if connector.type not in instance_types:
148
- return None
149
147
 
150
148
  if not hasattr(connector, 'test_connection'):
151
149
  return True
@@ -157,7 +155,15 @@ def _wrap_retry_connect(
157
155
  dprint(f"Trying to connect to '{connector}'...")
158
156
  dprint(f"Attempt ({retries + 1} / {max_retries})")
159
157
 
160
- if connector.type == 'sql':
158
+ if connector.type not in ('sql', 'api'):
159
+ try:
160
+ connected = connector.test_connection()
161
+ except Exception as e:
162
+ if warn:
163
+ print(e)
164
+ connected = False
165
+
166
+ elif connector.type == 'sql':
161
167
 
162
168
  def _connect(_connector):
163
169
  ### Test queries like `SELECT 1`.
@@ -185,7 +191,7 @@ def _wrap_retry_connect(
185
191
  _warn(
186
192
  f"Meerschaum instance '{connector}' does not allow chaining " +
187
193
  "and cannot be used as the parent for this instance.",
188
- stack = False
194
+ stack=False,
189
195
  )
190
196
  return False
191
197