meerschaum 2.5.0__py3-none-any.whl → 2.6.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 (45) hide show
  1. meerschaum/_internal/arguments/_parser.py +6 -1
  2. meerschaum/_internal/entry.py +16 -5
  3. meerschaum/actions/edit.py +6 -6
  4. meerschaum/actions/sql.py +12 -11
  5. meerschaum/api/dash/pages/login.py +17 -17
  6. meerschaum/api/dash/pipes.py +104 -13
  7. meerschaum/api/routes/_pipes.py +58 -40
  8. meerschaum/api/routes/_webterm.py +1 -0
  9. meerschaum/config/_edit.py +46 -19
  10. meerschaum/config/_read_config.py +20 -9
  11. meerschaum/config/_version.py +1 -1
  12. meerschaum/config/stack/__init__.py +1 -1
  13. meerschaum/config/static/__init__.py +1 -0
  14. meerschaum/connectors/api/_APIConnector.py +1 -0
  15. meerschaum/connectors/api/_pipes.py +39 -8
  16. meerschaum/connectors/sql/_SQLConnector.py +4 -3
  17. meerschaum/connectors/sql/_pipes.py +511 -118
  18. meerschaum/connectors/sql/_sql.py +55 -15
  19. meerschaum/connectors/valkey/_ValkeyConnector.py +3 -2
  20. meerschaum/connectors/valkey/_pipes.py +11 -5
  21. meerschaum/core/Pipe/__init__.py +27 -9
  22. meerschaum/core/Pipe/_attributes.py +181 -18
  23. meerschaum/core/Pipe/_clear.py +10 -8
  24. meerschaum/core/Pipe/_copy.py +2 -0
  25. meerschaum/core/Pipe/_data.py +65 -17
  26. meerschaum/core/Pipe/_deduplicate.py +30 -28
  27. meerschaum/core/Pipe/_dtypes.py +4 -4
  28. meerschaum/core/Pipe/_fetch.py +12 -10
  29. meerschaum/core/Pipe/_sync.py +28 -11
  30. meerschaum/core/Pipe/_verify.py +52 -49
  31. meerschaum/utils/dataframe.py +64 -34
  32. meerschaum/utils/dtypes/__init__.py +25 -6
  33. meerschaum/utils/dtypes/sql.py +76 -33
  34. meerschaum/utils/misc.py +57 -24
  35. meerschaum/utils/packages/_packages.py +2 -1
  36. meerschaum/utils/schedule.py +7 -5
  37. meerschaum/utils/sql.py +697 -44
  38. {meerschaum-2.5.0.dist-info → meerschaum-2.6.0.dist-info}/METADATA +5 -3
  39. {meerschaum-2.5.0.dist-info → meerschaum-2.6.0.dist-info}/RECORD +45 -45
  40. {meerschaum-2.5.0.dist-info → meerschaum-2.6.0.dist-info}/WHEEL +1 -1
  41. {meerschaum-2.5.0.dist-info → meerschaum-2.6.0.dist-info}/LICENSE +0 -0
  42. {meerschaum-2.5.0.dist-info → meerschaum-2.6.0.dist-info}/NOTICE +0 -0
  43. {meerschaum-2.5.0.dist-info → meerschaum-2.6.0.dist-info}/entry_points.txt +0 -0
  44. {meerschaum-2.5.0.dist-info → meerschaum-2.6.0.dist-info}/top_level.txt +0 -0
  45. {meerschaum-2.5.0.dist-info → meerschaum-2.6.0.dist-info}/zip-safe +0 -0
@@ -6,22 +6,26 @@ Import the config yaml file
6
6
  """
7
7
 
8
8
  from __future__ import annotations
9
+ import pathlib
10
+
9
11
  from meerschaum.utils.typing import Optional, Dict, Any, List, Tuple, Union
10
12
  from meerschaum.config import get_config
11
13
 
14
+
12
15
  def read_config(
13
- directory: Optional[str] = None,
16
+ directory: Union[pathlib.Path, str, None] = None,
14
17
  keys: Optional[List[str]] = None,
15
- write_missing : bool = True,
16
- substitute : bool = True,
17
- with_filenames : bool = False,
18
+ write_missing: bool = True,
19
+ substitute: bool = True,
20
+ with_filenames: bool = False,
21
+ raise_parsing_errors: bool = False,
18
22
  ) -> Union[Dict[str, Any], Tuple[Dict[str, Any], List[str]]]:
19
23
  """
20
24
  Read the configuration directory.
21
25
 
22
26
  Parameters
23
27
  ----------
24
- directory: Optional[str], default None
28
+ directory: Union[pathlib.Path, str, None], default None
25
29
  The directory with configuration files (.json and .yaml).
26
30
 
27
31
  keys: Optional[List[str]], default None
@@ -36,7 +40,10 @@ def read_config(
36
40
 
37
41
  with_filename: bool, default False
38
42
  If `True`, return a tuple of the configuration dictionary with a list of read filenames.
39
-
43
+
44
+ raise_parsing_errors: bool, default False
45
+ If `True`, re-raise parsing exceptions.
46
+
40
47
  Examples
41
48
  --------
42
49
  >>> read_config(keys=['meerschaum'], with_filename=True)
@@ -63,9 +70,9 @@ def read_config(
63
70
 
64
71
  default_filetype = STATIC_CONFIG['config']['default_filetype']
65
72
  filetype_loaders = {
66
- 'yml' : yaml.load,
67
- 'yaml' : yaml.load,
68
- 'json' : json.load,
73
+ 'yml': yaml.load,
74
+ 'yaml': yaml.load,
75
+ 'json': json.load,
69
76
  }
70
77
 
71
78
  ### Construct filekeys (files to parse).
@@ -167,6 +174,8 @@ def read_config(
167
174
  _config_key = filetype_loaders[_type](f)
168
175
  except Exception as e:
169
176
  print(f"Error processing file: {filepath}")
177
+ if raise_parsing_errors:
178
+ raise e
170
179
  import traceback
171
180
  traceback.print_exc()
172
181
  _config_key = {}
@@ -184,6 +193,8 @@ def read_config(
184
193
  config[symlinks_key][key] = _single_key_config[symlinks_key][key]
185
194
  break
186
195
  except Exception as e:
196
+ if raise_parsing_errors:
197
+ raise e
187
198
  print(f"Unable to parse {filename}!")
188
199
  import traceback
189
200
  traceback.print_exc()
@@ -2,4 +2,4 @@
2
2
  Specify the Meerschaum release version.
3
3
  """
4
4
 
5
- __version__ = "2.5.0"
5
+ __version__ = "2.6.0"
@@ -39,7 +39,7 @@ valkey_password = 'MRSM{meerschaum:connectors:valkey:main:password}'
39
39
 
40
40
  env_dict = {
41
41
  'COMPOSE_PROJECT_NAME': 'mrsm',
42
- 'TIMESCALEDB_VERSION': 'latest-pg16-oss',
42
+ 'TIMESCALEDB_VERSION': 'latest-pg16',
43
43
  'POSTGRES_USER': db_user,
44
44
  'POSTGRES_PASSWORD': db_pass,
45
45
  'POSTGRES_DB': db_base,
@@ -148,6 +148,7 @@ STATIC_CONFIG: Dict[str, Any] = {
148
148
  'min_ratio_columns_changed_for_full_astype': 0.5,
149
149
  },
150
150
  'exists_timeout_seconds': 5.0,
151
+ 'static_schema_cache_seconds': 60.0,
151
152
  },
152
153
  'jobs': {
153
154
  'check_restart_seconds': 1.0,
@@ -58,6 +58,7 @@ class APIConnector(Connector):
58
58
  drop_pipe,
59
59
  clear_pipe,
60
60
  get_pipe_columns_types,
61
+ get_pipe_columns_indices,
61
62
  )
62
63
  from ._fetch import fetch
63
64
  from ._plugins import (
@@ -669,11 +669,11 @@ def clear_pipe(
669
669
  kw.pop('force', None)
670
670
  return self.do_action_legacy(
671
671
  ['clear', 'pipes'],
672
- connector_keys = pipe.connector_keys,
673
- metric_keys = pipe.metric_key,
674
- location_keys = pipe.location_key,
675
- force = True,
676
- debug = debug,
672
+ connector_keys=pipe.connector_keys,
673
+ metric_keys=pipe.metric_key,
674
+ location_keys=pipe.location_key,
675
+ force=True,
676
+ debug=debug,
677
677
  **kw
678
678
  )
679
679
 
@@ -690,7 +690,7 @@ def get_pipe_columns_types(
690
690
  ----------
691
691
  pipe: meerschaum.Pipe
692
692
  The pipe whose columns to be queried.
693
-
693
+
694
694
  Returns
695
695
  -------
696
696
  A dictionary mapping column names to their database types.
@@ -707,11 +707,42 @@ def get_pipe_columns_types(
707
707
  r_url = pipe_r_url(pipe) + '/columns/types'
708
708
  response = self.get(
709
709
  r_url,
710
- debug = debug
710
+ debug=debug
711
+ )
712
+ j = response.json()
713
+ if isinstance(j, dict) and 'detail' in j and len(j.keys()) == 1:
714
+ warn(j['detail'])
715
+ return None
716
+ if not isinstance(j, dict):
717
+ warn(response.text)
718
+ return None
719
+ return j
720
+
721
+
722
+ def get_pipe_columns_indices(
723
+ self,
724
+ pipe: mrsm.Pipe,
725
+ debug: bool = False,
726
+ ) -> Union[Dict[str, str], None]:
727
+ """
728
+ Fetch the index information for a pipe.
729
+
730
+ Parameters
731
+ ----------
732
+ pipe: mrsm.Pipe
733
+ The pipe whose columns to be queried.
734
+
735
+ Returns
736
+ -------
737
+ A dictionary mapping column names to a list of associated index information.
738
+ """
739
+ r_url = pipe_r_url(pipe) + '/columns/indices'
740
+ response = self.get(
741
+ r_url,
742
+ debug=debug
711
743
  )
712
744
  j = response.json()
713
745
  if isinstance(j, dict) and 'detail' in j and len(j.keys()) == 1:
714
- from meerschaum.utils.warnings import warn
715
746
  warn(j['detail'])
716
747
  return None
717
748
  if not isinstance(j, dict):
@@ -67,6 +67,8 @@ class SQLConnector(Connector):
67
67
  get_pipe_columns_types,
68
68
  get_to_sql_dtype,
69
69
  get_pipe_schema,
70
+ create_pipe_table_from_df,
71
+ get_pipe_columns_indices,
70
72
  )
71
73
  from ._plugins import (
72
74
  register_plugin,
@@ -141,9 +143,9 @@ class SQLConnector(Connector):
141
143
  if uri.startswith('postgres') and not uri.startswith('postgresql'):
142
144
  uri = uri.replace('postgres', 'postgresql', 1)
143
145
  if uri.startswith('postgresql') and not uri.startswith('postgresql+'):
144
- uri = uri.replace('postgresql://', 'postgresql+psycopg', 1)
146
+ uri = uri.replace('postgresql://', 'postgresql+psycopg://', 1)
145
147
  if uri.startswith('timescaledb://'):
146
- uri = uri.replace('timescaledb://', 'postgresql://', 1)
148
+ uri = uri.replace('timescaledb://', 'postgresql+psycopg://', 1)
147
149
  flavor = 'timescaledb'
148
150
  kw['uri'] = uri
149
151
  from_uri_params = self.from_uri(kw['uri'], as_dict=True)
@@ -155,7 +157,6 @@ class SQLConnector(Connector):
155
157
  if flavor:
156
158
  kw['flavor'] = flavor
157
159
 
158
-
159
160
  ### set __dict__ in base class
160
161
  super().__init__(
161
162
  'sql',