meerschaum 2.7.5__py3-none-any.whl → 2.7.6__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. meerschaum/_internal/shell/Shell.py +4 -6
  2. meerschaum/_internal/shell/ShellCompleter.py +6 -5
  3. meerschaum/actions/clear.py +6 -3
  4. meerschaum/actions/copy.py +33 -27
  5. meerschaum/actions/sync.py +22 -18
  6. meerschaum/api/dash/pipes.py +2 -3
  7. meerschaum/config/_default.py +5 -0
  8. meerschaum/config/_version.py +1 -1
  9. meerschaum/connectors/api/_misc.py +3 -2
  10. meerschaum/connectors/api/_pipes.py +8 -9
  11. meerschaum/connectors/sql/_SQLConnector.py +1 -0
  12. meerschaum/connectors/sql/_pipes.py +37 -10
  13. meerschaum/connectors/sql/_sql.py +9 -1
  14. meerschaum/jobs/_Job.py +1 -0
  15. meerschaum/plugins/__init__.py +7 -3
  16. meerschaum/utils/daemon/Daemon.py +5 -1
  17. meerschaum/utils/daemon/__init__.py +2 -2
  18. meerschaum/utils/misc.py +7 -6
  19. meerschaum/utils/packages/__init__.py +31 -27
  20. meerschaum/utils/packages/_packages.py +1 -1
  21. meerschaum/utils/prompt.py +54 -36
  22. meerschaum/utils/venv/__init__.py +12 -3
  23. {meerschaum-2.7.5.dist-info → meerschaum-2.7.6.dist-info}/METADATA +4 -4
  24. {meerschaum-2.7.5.dist-info → meerschaum-2.7.6.dist-info}/RECORD +30 -30
  25. {meerschaum-2.7.5.dist-info → meerschaum-2.7.6.dist-info}/WHEEL +1 -1
  26. {meerschaum-2.7.5.dist-info → meerschaum-2.7.6.dist-info}/LICENSE +0 -0
  27. {meerschaum-2.7.5.dist-info → meerschaum-2.7.6.dist-info}/NOTICE +0 -0
  28. {meerschaum-2.7.5.dist-info → meerschaum-2.7.6.dist-info}/entry_points.txt +0 -0
  29. {meerschaum-2.7.5.dist-info → meerschaum-2.7.6.dist-info}/top_level.txt +0 -0
  30. {meerschaum-2.7.5.dist-info → meerschaum-2.7.6.dist-info}/zip-safe +0 -0
@@ -742,8 +742,7 @@ class Shell(cmd.Cmd):
742
742
  """
743
743
  from meerschaum import get_connector
744
744
  from meerschaum.connectors.parse import parse_instance_keys
745
- from meerschaum.utils.warnings import warn, info
746
- from meerschaum.utils.misc import remove_ansi
745
+ from meerschaum.utils.warnings import info
747
746
 
748
747
  if action is None:
749
748
  action = []
@@ -829,7 +828,7 @@ class Shell(cmd.Cmd):
829
828
  """
830
829
  from meerschaum import get_connector
831
830
  from meerschaum.connectors.parse import parse_repo_keys
832
- from meerschaum.utils.warnings import warn, info
831
+ from meerschaum.utils.warnings import info
833
832
 
834
833
  if action is None:
835
834
  action = []
@@ -878,7 +877,6 @@ class Shell(cmd.Cmd):
878
877
 
879
878
  Note that executors are API instances.
880
879
  """
881
- from meerschaum import get_connector
882
880
  from meerschaum.connectors.parse import parse_executor_keys
883
881
  from meerschaum.utils.warnings import warn, info
884
882
  from meerschaum.jobs import get_executor_keys_from_context
@@ -894,7 +892,7 @@ class Shell(cmd.Cmd):
894
892
  executor_keys = get_executor_keys_from_context()
895
893
 
896
894
  if executor_keys == 'systemd' and get_executor_keys_from_context() != 'systemd':
897
- warn(f"Cannot execute via `systemd`, falling back to `local`...", stack=False)
895
+ warn("Cannot execute via `systemd`, falling back to `local`...", stack=False)
898
896
  executor_keys = 'local'
899
897
 
900
898
  conn = parse_executor_keys(executor_keys, debug=debug)
@@ -935,7 +933,7 @@ class Shell(cmd.Cmd):
935
933
  if args['action'][0] not in shell_attrs['_actions']:
936
934
  try:
937
935
  print(textwrap.dedent(getattr(self, f"do_{args['action'][0]}").__doc__))
938
- except Exception as e:
936
+ except Exception:
939
937
  print(f"No help on '{args['action'][0]}'.")
940
938
  return ""
941
939
  parse_help(args)
@@ -7,13 +7,15 @@ Implement the prompt_toolkit Completer base class.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
- from prompt_toolkit.completion import Completer, Completion
11
- from meerschaum.utils.typing import Optional
12
- from meerschaum.actions import get_shell, get_completer, get_main_action_name, get_action
10
+ from meerschaum.actions import get_shell, get_main_action_name, get_action
13
11
  from meerschaum._internal.arguments import parse_line
14
12
 
15
13
  from meerschaum.utils.packages import attempt_import, ensure_readline
16
- prompt_toolkit = attempt_import('prompt_toolkit', lazy=False, install=True)
14
+
15
+ prompt_toolkit_completion = attempt_import('prompt_toolkit.completion', lazy=False, install=True)
16
+ Completer = prompt_toolkit_completion.Completer
17
+ Completion = prompt_toolkit_completion.Completion
18
+
17
19
 
18
20
  class ShellCompleter(Completer):
19
21
  """
@@ -30,7 +32,6 @@ class ShellCompleter(Completer):
30
32
  yielded = []
31
33
  ensure_readline()
32
34
  parts = document.text.split('-')
33
- ends_with_space = parts[0].endswith(' ')
34
35
  last_action_line = parts[0].split('+')[-1]
35
36
  part_0_subbed_spaces = last_action_line.replace(' ', '_')
36
37
  parsed_text = (part_0_subbed_spaces + '-'.join(parts[1:]))
@@ -130,12 +130,15 @@ def _ask_with_rowcounts(
130
130
  )
131
131
 
132
132
 
133
- pipes_rowcounts = {p: p.get_rowcount(begin=begin, end=end, debug=debug) for p in pipes}
133
+ pipes_rowcounts = {
134
+ pipe: pipe.get_rowcount(begin=begin, end=end, debug=debug)
135
+ for pipe in pipes
136
+ }
134
137
  print_options(
135
- [str(p) + f'\n{rc}\n' for p, rc in pipes_rowcounts.items()],
138
+ [str(pipe) + f'\n{rowcount:,}\n' for pipe, rowcount in pipes_rowcounts.items()],
136
139
  header='Number of Rows to be Deleted'
137
140
  )
138
- total_num_rows = sum([rc for p, rc in pipes_rowcounts.items()])
141
+ total_num_rows = sum([rowcount for rowcount in pipes_rowcounts.values()])
139
142
  question = (
140
143
  f"Are you sure you want to delete {total_num_rows:,} rows across {len(pipes)} pipe"
141
144
  + ('s' if len(pipes) != 1 else '')
@@ -7,7 +7,7 @@ Functions for copying elements.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
- from meerschaum.utils.typing import Union, Any, Sequence, SuccessTuple, Optional, Tuple, List
10
+ from meerschaum.utils.typing import Any, SuccessTuple, Optional, List
11
11
 
12
12
  def copy(
13
13
  action: Optional[List[str]] = None,
@@ -69,44 +69,53 @@ def _copy_pipes(
69
69
  Copy pipes' attributes and make new pipes.
70
70
  """
71
71
  from meerschaum import get_pipes, Pipe
72
- from meerschaum.utils.prompt import prompt, yes_no
72
+ from meerschaum.utils.prompt import prompt, yes_no, get_connectors_completer
73
73
  from meerschaum.utils.warnings import warn
74
74
  from meerschaum.utils.formatting import print_tuple
75
75
  from meerschaum.utils.formatting._shell import clear_screen
76
76
  pipes = get_pipes(as_list=True, **kw)
77
77
  successes = 0
78
- for p in pipes:
79
- ck = prompt(f"Connector keys for copy of {p}:", default=p.connector_keys)
80
- mk = prompt(f"Metric key for copy of {p}:", default=p.metric_key)
81
- lk = prompt(f"Location key for copy of {p} ('None' to omit):", default=str(p.location_key))
78
+ for pipe in pipes:
79
+ ck = prompt(
80
+ f"Connector keys for copy of {pipe}:",
81
+ default=pipe.connector_keys,
82
+ completer=get_connectors_completer(),
83
+ )
84
+ mk = prompt(f"Metric key for copy of {pipe}:", default=pipe.metric_key)
85
+ lk = prompt(
86
+ f"Location key for copy of {pipe} ('None' to omit):",
87
+ default=str(pipe.location_key),
88
+ )
82
89
  if lk in ('', 'None', '[None]'):
83
90
  lk = None
84
- _new_pipe = Pipe(
85
- ck, mk, lk,
86
- parameters=p.parameters.copy(),
87
- )
91
+
88
92
  instance_keys = prompt(
89
- f"Meerschaum instance to store the new {_new_pipe}:",
90
- default=p.instance_keys
93
+ f"Meerschaum instance for copy of {pipe}:",
94
+ default=pipe.instance_keys
91
95
  )
92
- _new_pipe.instance_keys = instance_keys
93
- if _new_pipe.get_id(debug=debug) is not None:
94
- warn(f"New {_new_pipe} already exists. Skipping...", stack=False)
96
+ new_pipe = Pipe(
97
+ ck, mk, lk,
98
+ instance=instance_keys,
99
+ parameters=pipe.parameters.copy(),
100
+ )
101
+
102
+ if new_pipe.get_id(debug=debug) is not None:
103
+ warn(f"{new_pipe} already exists. Skipping...", stack=False)
95
104
  continue
96
- _register_success_tuple = _new_pipe.register(debug=debug)
105
+ _register_success_tuple = new_pipe.register(debug=debug)
97
106
  if not _register_success_tuple[0]:
98
- warn(f"Failed to register new {_new_pipe}.", stack=False)
107
+ warn(f"Failed to register new {new_pipe}.", stack=False)
99
108
  continue
100
109
 
101
110
  clear_screen(debug=debug)
102
111
  successes += 1
103
112
  print_tuple(
104
- (True, f"Successfully copied attributes of {p} " + f" into {_new_pipe}.")
113
+ (True, f"Successfully copied attributes of {pipe} " + f" into {new_pipe}.")
105
114
  )
106
115
  if (
107
116
  force or yes_no(
108
117
  (
109
- f"Do you want to copy data from {p} into {_new_pipe}?\n\n"
118
+ f"Do you want to copy data from {pipe} into {new_pipe}?\n\n"
110
119
  + "If you specified `--begin`, `--end` or `--params`, data will be filtered."
111
120
  ),
112
121
  noask=noask,
@@ -114,8 +123,8 @@ def _copy_pipes(
114
123
  default='n',
115
124
  )
116
125
  ):
117
- _new_pipe.sync(
118
- p.get_data(
126
+ new_pipe.sync(
127
+ pipe.get_data(
119
128
  debug=debug,
120
129
  as_iterator=True,
121
130
  **kw
@@ -142,17 +151,14 @@ def _copy_connectors(
142
151
  ) -> SuccessTuple:
143
152
  """
144
153
  Create a new connector from an existing one.
145
-
146
154
  """
147
- import os, pathlib
148
155
  from meerschaum.utils.prompt import yes_no, prompt
149
156
  from meerschaum.connectors.parse import parse_connector_keys
150
157
  from meerschaum.config import _config, get_config
151
- from meerschaum.config._edit import write_config
152
- from meerschaum.utils.warnings import info, warn
158
+ from meerschaum.utils.warnings import info
153
159
  from meerschaum.utils.formatting import pprint
154
160
  from meerschaum.actions import get_action
155
- cf = _config()
161
+ _ = _config()
156
162
  if action is None:
157
163
  action = []
158
164
  if connector_keys is None:
@@ -170,7 +176,7 @@ def _copy_connectors(
170
176
 
171
177
  try:
172
178
  conn = parse_connector_keys(ck)
173
- except Exception as e:
179
+ except Exception:
174
180
  return False, f"Unable to parse connector '{ck}'."
175
181
 
176
182
  if len(_keys) == 2:
@@ -275,12 +275,14 @@ def _sync_pipes(
275
275
  import time
276
276
  import os
277
277
  import contextlib
278
+ from datetime import timedelta
278
279
 
279
280
  from meerschaum.utils.warnings import warn, info
280
281
  from meerschaum.utils.formatting._shell import progress
281
282
  from meerschaum.utils.formatting._shell import clear_screen
282
283
  from meerschaum.utils.formatting import print_pipes_results
283
284
  from meerschaum.config.static import STATIC_CONFIG
285
+ from meerschaum.utils.misc import interval_str
284
286
 
285
287
  noninteractive_val = os.environ.get(STATIC_CONFIG['environment']['noninteractive'], None)
286
288
  noninteractive = str(noninteractive_val).lower() in ('1', 'true', 'yes')
@@ -321,7 +323,7 @@ def _sync_pipes(
321
323
  for pipe, (_success, _msg) in results_dict.items()
322
324
  if not _success
323
325
  ]
324
- except Exception as e:
326
+ except Exception:
325
327
  import traceback
326
328
  traceback.print_exc()
327
329
  warn(
@@ -351,9 +353,9 @@ def _sync_pipes(
351
353
  success_msg = (
352
354
  "Successfully spawned threads for pipes:"
353
355
  if unblock
354
- else f"Successfully synced pipes:"
356
+ else "Successfully synced pipes:"
355
357
  )
356
- fail_msg = f"Failed to sync pipes:"
358
+ fail_msg = "Failed to sync pipes:"
357
359
  if results_dict:
358
360
  print_pipes_results(
359
361
  results_dict,
@@ -362,8 +364,10 @@ def _sync_pipes(
362
364
  nopretty = nopretty,
363
365
  )
364
366
 
367
+ lap_duration_text = interval_str(timedelta(seconds=(lap_end - lap_begin)))
368
+
365
369
  msg = (
366
- f"It took {round(lap_end - lap_begin, 2)} seconds to sync " +
370
+ f"It took {lap_duration_text} to sync " +
367
371
  f"{len(success_pipes) + len(failure_pipes)} pipe" +
368
372
  ("s" if (len(success_pipes) + len(failure_pipes)) != 1 else "") + "\n" +
369
373
  f" ({len(success_pipes)} succeeded, {len(failure_pipes)} failed)."
@@ -385,26 +389,26 @@ def _sync_pipes(
385
389
 
386
390
 
387
391
  def _wrap_pipe(
388
- pipe,
389
- unblock: bool = False,
390
- force: bool = False,
391
- debug: bool = False,
392
- min_seconds: int = 1,
393
- workers = None,
394
- verify: bool = False,
395
- deduplicate: bool = False,
396
- bounded: Optional[bool] = None,
397
- chunk_interval: Union[timedelta, int, None] = None,
398
- **kw
399
- ):
392
+ pipe,
393
+ unblock: bool = False,
394
+ force: bool = False,
395
+ debug: bool = False,
396
+ min_seconds: int = 1,
397
+ workers = None,
398
+ verify: bool = False,
399
+ deduplicate: bool = False,
400
+ bounded: Optional[bool] = None,
401
+ chunk_interval: Union[timedelta, int, None] = None,
402
+ **kw
403
+ ):
400
404
  """
401
405
  Wrapper function for handling exceptions.
402
406
  """
403
407
  import time
404
408
  import traceback
405
- from datetime import datetime, timedelta, timezone
409
+ from datetime import datetime, timezone
406
410
  import meerschaum as mrsm
407
- from meerschaum.utils.typing import is_success_tuple, SuccessTuple
411
+ from meerschaum.utils.typing import is_success_tuple
408
412
  from meerschaum.connectors import get_connector_plugin
409
413
  from meerschaum.utils.venv import Venv
410
414
  from meerschaum.plugins import _pre_sync_hooks, _post_sync_hooks
@@ -12,7 +12,6 @@ import shlex
12
12
  from textwrap import dedent
13
13
  from urllib.parse import urlencode
14
14
 
15
- from dash.dependencies import Input, Output, State
16
15
  from meerschaum.utils.typing import List, Optional, Dict, Any, Tuple, Union
17
16
  from meerschaum.utils.misc import string_to_dict
18
17
  from meerschaum.utils.packages import attempt_import, import_dcc, import_html, import_pandas
@@ -76,7 +75,7 @@ def keys_from_state(
76
75
  try:
77
76
  # params = string_to_dict(state['params-textarea.value'])
78
77
  params = string_to_dict(state['search-parameters-editor.value'])
79
- except Exception as e:
78
+ except Exception:
80
79
  params = None
81
80
  else:
82
81
  params = None
@@ -506,7 +505,7 @@ def accordion_items_from_pipe(
506
505
 
507
506
  stats_rows = []
508
507
  if rowcount is not None:
509
- stats_rows.append(html.Tr([html.Td("Row-count"), html.Td(f"{rowcount}")]))
508
+ stats_rows.append(html.Tr([html.Td("Row Count"), html.Td(f"{rowcount:,}")]))
510
509
  if interval is not None:
511
510
  stats_rows.append(
512
511
  html.Tr([html.Td("Timespan"), html.Td(humanfriendly.format_timespan(interval))])
@@ -76,6 +76,11 @@ default_system_config = {
76
76
  },
77
77
  'instance': {
78
78
  'stale_temporary_tables_minutes': 1440,
79
+ 'temporary_target': {
80
+ 'prefix': '_',
81
+ 'transaction_id_length': 4,
82
+ 'separator': '_',
83
+ },
79
84
  },
80
85
  'chunksize': 100_000,
81
86
  'poolclass': 'sqlalchemy.pool.QueuePool',
@@ -2,4 +2,4 @@
2
2
  Specify the Meerschaum release version.
3
3
  """
4
4
 
5
- __version__ = "2.7.5"
5
+ __version__ = "2.7.6"
@@ -20,12 +20,13 @@ def get_mrsm_version(self, **kw) -> Optional[str]:
20
20
  use_token=False,
21
21
  **kw
22
22
  ).json()
23
- except Exception as e:
23
+ except Exception:
24
24
  return None
25
25
  if isinstance(j, dict) and 'detail' in j:
26
26
  return None
27
27
  return j
28
28
 
29
+
29
30
  def get_chaining_status(self, **kw) -> Optional[bool]:
30
31
  """
31
32
  Fetch the chaining status of the API instance.
@@ -39,7 +40,7 @@ def get_chaining_status(self, **kw) -> Optional[bool]:
39
40
  )
40
41
  if not response:
41
42
  return None
42
- except Exception as e:
43
+ except Exception:
43
44
  return None
44
45
 
45
46
  return response.json()
@@ -9,8 +9,7 @@ Register or fetch Pipes from the API
9
9
  from __future__ import annotations
10
10
  import time
11
11
  import json
12
- from io import StringIO
13
- from datetime import datetime
12
+ from datetime import datetime, timedelta
14
13
 
15
14
  import meerschaum as mrsm
16
15
  from meerschaum.utils.debug import dprint
@@ -178,11 +177,11 @@ def sync_pipe(
178
177
  """Sync a DataFrame into a Pipe."""
179
178
  from decimal import Decimal
180
179
  from meerschaum.utils.debug import dprint
181
- from meerschaum.utils.misc import json_serialize_datetime, items_str
180
+ from meerschaum.utils.misc import json_serialize_datetime, items_str, interval_str
182
181
  from meerschaum.config import get_config
183
182
  from meerschaum.utils.packages import attempt_import
184
- from meerschaum.utils.dataframe import get_numeric_cols, to_json, get_bytes_cols
185
- begin = time.time()
183
+ from meerschaum.utils.dataframe import get_numeric_cols, to_json
184
+ begin = time.perf_counter()
186
185
  more_itertools = attempt_import('more_itertools')
187
186
  if df is None:
188
187
  msg = f"DataFrame is `None`. Cannot sync {pipe}."
@@ -304,9 +303,10 @@ def sync_pipe(
304
303
  num_success_chunks += 1
305
304
 
306
305
  success_tuple = True, (
307
- f"It took {round(time.time() - begin, 2)} seconds to sync {rowcount} row"
306
+ f"It took {interval_str(timedelta(seconds=(time.perf_counter() - begin)))} "
307
+ + "to sync {rowcount:,} row"
308
308
  + ('s' if rowcount != 1 else '')
309
- + f" across {num_success_chunks} chunk" + ('s' if num_success_chunks != 1 else '') +
309
+ + f" across {num_success_chunks:,} chunk" + ('s' if num_success_chunks != 1 else '') +
310
310
  f" to {pipe}."
311
311
  )
312
312
  return success_tuple
@@ -549,10 +549,9 @@ def create_metadata(
549
549
  if debug:
550
550
  dprint("Create metadata response: {response.text}")
551
551
  try:
552
- metadata_response = json.loads(response.text)
552
+ _ = json.loads(response.text)
553
553
  except Exception as e:
554
554
  warn(f"Failed to create metadata on {self}:\n{e}")
555
- metadata_response = False
556
555
  return False
557
556
 
558
557
 
@@ -69,6 +69,7 @@ class SQLConnector(Connector):
69
69
  get_pipe_schema,
70
70
  create_pipe_table_from_df,
71
71
  get_pipe_columns_indices,
72
+ get_temporary_target,
72
73
  )
73
74
  from ._plugins import (
74
75
  register_plugin,
@@ -1505,7 +1505,6 @@ def sync_pipe(
1505
1505
  UPDATE_QUERIES,
1506
1506
  get_reset_autoincrement_queries,
1507
1507
  )
1508
- from meerschaum.utils.misc import generate_password
1509
1508
  from meerschaum.utils.dtypes import are_dtypes_equal
1510
1509
  from meerschaum.utils.dtypes.sql import get_db_type_from_pd_type
1511
1510
  from meerschaum import Pipe
@@ -1720,9 +1719,7 @@ def sync_pipe(
1720
1719
  warn(f"Could not reset auto-incrementing primary key for {pipe}.", stack=False)
1721
1720
 
1722
1721
  if update_df is not None and len(update_df) > 0:
1723
- transact_id = generate_password(3)
1724
- temp_prefix = '##' if self.flavor != 'oracle' else '_'
1725
- temp_target = temp_prefix + transact_id + '_' + pipe.target
1722
+ temp_target = self.get_temporary_target(pipe.target, label='update')
1726
1723
  self._log_temporary_tables_creation(temp_target, create=(not pipe.temporary), debug=debug)
1727
1724
  temp_pipe = Pipe(
1728
1725
  pipe.connector_keys.replace(':', '_') + '_', pipe.metric_key, pipe.location_key,
@@ -1743,7 +1740,7 @@ def sync_pipe(
1743
1740
  static=True,
1744
1741
  autoincrement=False,
1745
1742
  parameters={
1746
- 'schema': (self.internal_schema if self.flavor != 'mssql' else None),
1743
+ 'schema': self.internal_schema,
1747
1744
  'hypertable': False,
1748
1745
  },
1749
1746
  )
@@ -1910,15 +1907,18 @@ def sync_pipe_inplace(
1910
1907
  )
1911
1908
  from meerschaum.utils.misc import generate_password
1912
1909
 
1913
- transact_id = generate_password(3)
1914
- def get_temp_table_name(label: str) -> str:
1915
- temp_prefix = '##' if self.flavor != 'oracle' else '_'
1916
- return temp_prefix + transact_id + '_' + label + '_' + pipe.target
1910
+ transaction_id_length = (
1911
+ mrsm.get_config(
1912
+ 'system', 'connectors', 'sql', 'instance', 'temporary_target', 'transaction_id_length'
1913
+ )
1914
+ )
1915
+ transact_id = generate_password(transaction_id_length)
1917
1916
 
1918
1917
  internal_schema = self.internal_schema
1918
+ target = pipe.target
1919
1919
  temp_table_roots = ['backtrack', 'new', 'delta', 'joined', 'unseen', 'update']
1920
1920
  temp_tables = {
1921
- table_root: get_temp_table_name(table_root)
1921
+ table_root: self.get_temporary_target(target, transact_id=transact_id, label=table_root)
1922
1922
  for table_root in temp_table_roots
1923
1923
  }
1924
1924
  temp_table_names = {
@@ -3626,3 +3626,30 @@ def get_pipe_schema(self, pipe: mrsm.Pipe) -> Union[str, None]:
3626
3626
  A schema string or `None` if nothing is configured.
3627
3627
  """
3628
3628
  return pipe.parameters.get('schema', self.schema)
3629
+
3630
+
3631
+ @staticmethod
3632
+ def get_temporary_target(
3633
+ target: str,
3634
+ transact_id: Optional[str, None] = None,
3635
+ label: Optional[str] = None,
3636
+ separator: Optional[str] = None,
3637
+ ) -> str:
3638
+ """
3639
+ Return a unique(ish) temporary target for a pipe.
3640
+ """
3641
+ from meerschaum.utils.misc import generate_password
3642
+ temp_target_cf = (
3643
+ mrsm.get_config('system', 'connectors', 'sql', 'instance', 'temporary_target') or {}
3644
+ )
3645
+ transaction_id_len = temp_target_cf.get('transaction_id_length', 3)
3646
+ transact_id = transact_id or generate_password(transaction_id_len)
3647
+ temp_prefix = temp_target_cf.get('prefix', '_')
3648
+ separator = separator or temp_target_cf.get('separator', '_')
3649
+ return (
3650
+ temp_prefix
3651
+ + target
3652
+ + separator
3653
+ + transact_id
3654
+ + ((separator + label) if label else '')
3655
+ )
@@ -778,6 +778,7 @@ def to_sql(
778
778
  import time
779
779
  import json
780
780
  from decimal import Decimal
781
+ from datetime import timedelta
781
782
  from meerschaum.utils.warnings import error, warn
782
783
  import warnings
783
784
  import functools
@@ -816,6 +817,7 @@ def to_sql(
816
817
  PD_TO_SQLALCHEMY_DTYPES_FLAVORS,
817
818
  get_db_type_from_pd_type,
818
819
  )
820
+ from meerschaum.utils.misc import interval_str
819
821
  from meerschaum.connectors.sql._create_engine import flavor_configs
820
822
  from meerschaum.utils.packages import attempt_import, import_pandas
821
823
  sqlalchemy = attempt_import('sqlalchemy', debug=debug)
@@ -998,7 +1000,13 @@ def to_sql(
998
1000
 
999
1001
  end = time.perf_counter()
1000
1002
  if success:
1001
- msg = f"It took {round(end - start, 2)} seconds to sync {len(df)} rows to {name}."
1003
+ num_rows = len(df)
1004
+ msg = (
1005
+ f"It took {interval_str(timedelta(seconds=(end - start)))} "
1006
+ + f"to sync {num_rows:,} row"
1007
+ + ('s' if num_rows != 1 else '')
1008
+ + f" to {name}."
1009
+ )
1002
1010
  stats['start'] = start
1003
1011
  stats['end'] = end
1004
1012
  stats['duration'] = end - start
meerschaum/jobs/_Job.py CHANGED
@@ -313,6 +313,7 @@ class Job:
313
313
  if not cleanup_success:
314
314
  return cleanup_success, cleanup_msg
315
315
 
316
+ _ = self.daemon._properties.pop('result', None)
316
317
  return cleanup_success, f"Deleted {self}."
317
318
 
318
319
  def is_running(self) -> bool:
@@ -126,8 +126,8 @@ def pre_sync_hook(
126
126
 
127
127
 
128
128
  def post_sync_hook(
129
- function: Callable[[Any], Any],
130
- ) -> Callable[[Any], Any]:
129
+ function: Callable[[Any], Any],
130
+ ) -> Callable[[Any], Any]:
131
131
  """
132
132
  Register a function as a sync hook to be executed upon completion of a sync.
133
133
 
@@ -143,10 +143,14 @@ def post_sync_hook(
143
143
  Examples
144
144
  --------
145
145
  >>> from meerschaum.plugins import post_sync_hook
146
+ >>> from meerschaum.utils.misc import interval_str
147
+ >>> from datetime import timedelta
146
148
  >>>
147
149
  >>> @post_sync_hook
148
150
  ... def log_sync(pipe, success_tuple, duration=None, **kwargs):
149
- ... print(f"It took {round(duration, 2)} seconds to sync {pipe}.")
151
+ ... duration_delta = timedelta(seconds=duration)
152
+ ... duration_text = interval_str(duration_delta)
153
+ ... print(f"It took {duration_text} to sync {pipe}.")
150
154
  >>>
151
155
  """
152
156
  with _locks['_post_sync_hooks']:
@@ -1017,7 +1017,8 @@ class Daemon:
1017
1017
 
1018
1018
  def read_pickle(self) -> Daemon:
1019
1019
  """Read a Daemon's pickle file and return the `Daemon`."""
1020
- import pickle, traceback
1020
+ import pickle
1021
+ import traceback
1021
1022
  if not self.pickle_path.exists():
1022
1023
  error(f"Pickle file does not exist for daemon '{self.daemon_id}'.")
1023
1024
 
@@ -1053,6 +1054,9 @@ class Daemon:
1053
1054
  if self._properties is None:
1054
1055
  self._properties = {}
1055
1056
 
1057
+ if self._properties.get('result', None) is None:
1058
+ _ = self._properties.pop('result', None)
1059
+
1056
1060
  if _file_properties is not None:
1057
1061
  self._properties = apply_patch_to_config(
1058
1062
  _file_properties,
@@ -37,7 +37,7 @@ def daemon_entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
37
37
  filtered_sysargs = [arg for arg in sysargs if arg not in ('-d', '--daemon')]
38
38
  try:
39
39
  label = shlex.join(filtered_sysargs) if sysargs else None
40
- except Exception as e:
40
+ except Exception:
41
41
  label = ' '.join(filtered_sysargs) if sysargs else None
42
42
 
43
43
  name = _args.get('name', None)
@@ -45,7 +45,7 @@ def daemon_entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
45
45
  if name:
46
46
  try:
47
47
  daemon = Daemon(daemon_id=name)
48
- except Exception as e:
48
+ except Exception:
49
49
  daemon = None
50
50
 
51
51
  if daemon is not None:
meerschaum/utils/misc.py CHANGED
@@ -90,20 +90,21 @@ def add_method_to_class(
90
90
 
91
91
 
92
92
  def generate_password(length: int = 12) -> str:
93
- """Generate a secure password of given length.
93
+ """
94
+ Generate a secure password of given length.
94
95
 
95
96
  Parameters
96
97
  ----------
97
- length : int, default 12
98
+ length: int, default 12
98
99
  The length of the password.
99
100
 
100
101
  Returns
101
102
  -------
102
103
  A random password string.
103
-
104
104
  """
105
- import secrets, string
106
- return ''.join((secrets.choice(string.ascii_letters) for i in range(length)))
105
+ import secrets
106
+ import string
107
+ return ''.join((secrets.choice(string.ascii_letters + string.digits) for i in range(length)))
107
108
 
108
109
  def is_int(s : str) -> bool:
109
110
  """
@@ -121,7 +122,7 @@ def is_int(s : str) -> bool:
121
122
  """
122
123
  try:
123
124
  float(s)
124
- except Exception as e:
125
+ except Exception:
125
126
  return False
126
127
 
127
128
  return float(s).is_integer()
@@ -337,14 +337,14 @@ def get_install_no_version(install_name: str) -> str:
337
337
 
338
338
  import_versions = {}
339
339
  def determine_version(
340
- path: pathlib.Path,
341
- import_name: Optional[str] = None,
342
- venv: Optional[str] = 'mrsm',
343
- search_for_metadata: bool = True,
344
- split: bool = True,
345
- warn: bool = False,
346
- debug: bool = False,
347
- ) -> Union[str, None]:
340
+ path: pathlib.Path,
341
+ import_name: Optional[str] = None,
342
+ venv: Optional[str] = 'mrsm',
343
+ search_for_metadata: bool = True,
344
+ split: bool = True,
345
+ warn: bool = False,
346
+ debug: bool = False,
347
+ ) -> Union[str, None]:
348
348
  """
349
349
  Determine a module's `__version__` string from its filepath.
350
350
 
@@ -381,11 +381,8 @@ def determine_version(
381
381
  with _locks['import_versions']:
382
382
  if venv not in import_versions:
383
383
  import_versions[venv] = {}
384
- import importlib.metadata
385
- import re, os
384
+ import os
386
385
  old_cwd = os.getcwd()
387
- if debug:
388
- from meerschaum.utils.debug import dprint
389
386
  from meerschaum.utils.warnings import warn as warn_function
390
387
  if import_name is None:
391
388
  import_name = path.parent.stem if path.stem == '__init__' else path.stem
@@ -395,7 +392,10 @@ def determine_version(
395
392
  _version = None
396
393
  module_parent_dir = (
397
394
  path.parent.parent if path.stem == '__init__' else path.parent
398
- ) if path is not None else venv_target_path(venv, debug=debug)
395
+ ) if path is not None else venv_target_path(venv, allow_nonexistent=True, debug=debug)
396
+
397
+ if not module_parent_dir.exists():
398
+ return None
399
399
 
400
400
  installed_dir_name = _import_to_dir_name(import_name)
401
401
  clean_installed_dir_name = installed_dir_name.lower().replace('-', '_')
@@ -403,7 +403,11 @@ def determine_version(
403
403
  ### First, check if a dist-info directory exists.
404
404
  _found_versions = []
405
405
  if search_for_metadata:
406
- for filename in os.listdir(module_parent_dir):
406
+ try:
407
+ filenames = os.listdir(module_parent_dir)
408
+ except FileNotFoundError:
409
+ filenames = []
410
+ for filename in filenames:
407
411
  if not filename.endswith('.dist-info'):
408
412
  continue
409
413
  filename_lower = filename.lower()
@@ -430,7 +434,7 @@ def determine_version(
430
434
  try:
431
435
  os.chdir(module_parent_dir)
432
436
  _version = importlib_metadata.metadata(import_name)['Version']
433
- except Exception as e:
437
+ except Exception:
434
438
  _version = None
435
439
  finally:
436
440
  os.chdir(old_cwd)
@@ -698,7 +702,7 @@ def need_update(
698
702
  (not semver.Version.parse(version).match(required_version))
699
703
  if required_version else False
700
704
  )
701
- except AttributeError as e:
705
+ except AttributeError:
702
706
  pip_install(_import_to_install_name('semver'), venv='mrsm', debug=debug)
703
707
  semver = manually_import_module('semver', venv='mrsm', debug=debug)
704
708
  return (
@@ -724,10 +728,10 @@ def need_update(
724
728
 
725
729
 
726
730
  def get_pip(
727
- venv: Optional[str] = 'mrsm',
728
- color: bool = True,
729
- debug: bool = False,
730
- ) -> bool:
731
+ venv: Optional[str] = 'mrsm',
732
+ color: bool = True,
733
+ debug: bool = False,
734
+ ) -> bool:
731
735
  """
732
736
  Download and run the get-pip.py script.
733
737
 
@@ -747,7 +751,8 @@ def get_pip(
747
751
  A bool indicating success.
748
752
 
749
753
  """
750
- import sys, subprocess
754
+ import sys
755
+ import subprocess
751
756
  from meerschaum.utils.misc import wget
752
757
  from meerschaum.config._paths import CACHE_RESOURCES_PATH
753
758
  from meerschaum.config.static import STATIC_CONFIG
@@ -755,7 +760,7 @@ def get_pip(
755
760
  dest = CACHE_RESOURCES_PATH / 'get-pip.py'
756
761
  try:
757
762
  wget(url, dest, color=False, debug=debug)
758
- except Exception as e:
763
+ except Exception:
759
764
  print(f"Failed to fetch pip from '{url}'. Please install pip and restart Meerschaum.")
760
765
  sys.exit(1)
761
766
  if venv is not None:
@@ -776,6 +781,7 @@ def pip_install(
776
781
  _uninstall: bool = False,
777
782
  _from_completely_uninstall: bool = False,
778
783
  _install_uv_pip: bool = True,
784
+ _use_uv_pip: bool = True,
779
785
  color: bool = True,
780
786
  silent: bool = False,
781
787
  debug: bool = False,
@@ -835,10 +841,7 @@ def pip_install(
835
841
  from meerschaum.utils.warnings import warn
836
842
  if args is None:
837
843
  args = ['--upgrade'] if not _uninstall else []
838
- if color:
839
- ANSI, UNICODE = True, True
840
- else:
841
- ANSI, UNICODE = False, False
844
+ ANSI = True if color else False
842
845
  if check_wheel:
843
846
  have_wheel = venv_contains_package('wheel', venv=venv, debug=debug)
844
847
 
@@ -877,7 +880,8 @@ def pip_install(
877
880
  )
878
881
 
879
882
  use_uv_pip = (
880
- venv_contains_package('uv', venv=None, debug=debug)
883
+ _use_uv_pip
884
+ and venv_contains_package('uv', venv=None, debug=debug)
881
885
  and uv_bin is not None
882
886
  and venv is not None
883
887
  and is_uv_enabled()
@@ -136,7 +136,7 @@ packages['sql'] = {
136
136
  'numpy' : 'numpy>=1.18.5',
137
137
  'pandas' : 'pandas[parquet]>=2.0.1',
138
138
  'pyarrow' : 'pyarrow>=16.1.0',
139
- 'dask' : 'dask[complete]>=2024.5.1',
139
+ 'dask' : 'dask[complete]>=2024.12.1',
140
140
  'partd' : 'partd>=1.4.2',
141
141
  'pytz' : 'pytz',
142
142
  'joblib' : 'joblib>=0.17.0',
@@ -7,7 +7,9 @@ Functions for interacting with the user.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
+
10
11
  import os
12
+ import meerschaum as mrsm
11
13
  from meerschaum.utils.typing import Any, Union, Optional, Tuple, List
12
14
 
13
15
 
@@ -63,9 +65,8 @@ def prompt(
63
65
 
64
66
  """
65
67
  from meerschaum.utils.packages import attempt_import
66
- from meerschaum.utils.formatting import colored, ANSI, CHARSET, highlight_pipes, fill_ansi
68
+ from meerschaum.utils.formatting import ANSI, CHARSET, highlight_pipes, fill_ansi
67
69
  from meerschaum.config import get_config
68
- from meerschaum.config.static import _static_config
69
70
  from meerschaum.utils.misc import filter_keywords
70
71
  from meerschaum.utils.daemon import running_in_daemon
71
72
  noask = check_noask(noask)
@@ -175,8 +176,6 @@ def yes_no(
175
176
  ```
176
177
  """
177
178
  from meerschaum.utils.warnings import error, warn
178
- from meerschaum.utils.formatting import ANSI, UNICODE
179
- from meerschaum.utils.packages import attempt_import
180
179
 
181
180
  default = options[0] if yes else default
182
181
  noask = yes or check_noask(noask)
@@ -195,7 +194,7 @@ def yes_no(
195
194
  success = False
196
195
 
197
196
  if not success:
198
- error(f"Error getting response. Aborting...", stack=False)
197
+ error("Error getting response. Aborting...", stack=False)
199
198
  if answer == "":
200
199
  answer = default
201
200
 
@@ -205,19 +204,20 @@ def yes_no(
205
204
 
206
205
  return answer.lower() == options[0].lower()
207
206
 
207
+
208
208
  def choose(
209
- question: str,
210
- choices: List[Union[str, Tuple[str, str]]],
211
- default: Union[str, List[str], None] = None,
212
- numeric: bool = True,
213
- multiple: bool = False,
214
- as_indices: bool = False,
215
- delimiter: str = ',',
216
- icon: bool = True,
217
- warn: bool = True,
218
- noask: bool = False,
219
- **kw
220
- ) -> Union[str, Tuple[str], None]:
209
+ question: str,
210
+ choices: List[Union[str, Tuple[str, str]]],
211
+ default: Union[str, List[str], None] = None,
212
+ numeric: bool = True,
213
+ multiple: bool = False,
214
+ as_indices: bool = False,
215
+ delimiter: str = ',',
216
+ icon: bool = True,
217
+ warn: bool = True,
218
+ noask: bool = False,
219
+ **kw
220
+ ) -> Union[str, Tuple[str], None]:
221
221
  """
222
222
  Present a list of options and return the user's choice.
223
223
 
@@ -418,8 +418,8 @@ def choose(
418
418
  valid = (len(answers) > 1 or not (len(answers) == 1 and answers[0] is None))
419
419
  for a in answers:
420
420
  if (
421
- not a in {_original for _new, _original in altered_choices.items()}
422
- and not a in _choices
421
+ a not in {_original for _new, _original in altered_choices.items()}
422
+ and a not in _choices
423
423
  and a != default
424
424
  and not noask
425
425
  ):
@@ -428,21 +428,22 @@ def choose(
428
428
  if valid:
429
429
  break
430
430
  if warn:
431
- _warn(f"Please pick a valid choice.", stack=False)
431
+ _warn("Please pick a valid choice.", stack=False)
432
432
 
433
433
  if not multiple:
434
434
  if not numeric:
435
435
  return answer
436
436
  try:
437
437
  _answer = choices[int(answer) - 1]
438
- if as_indices and isinstance(choice, tuple):
438
+ if as_indices and isinstance(_answer, tuple):
439
439
  return _answer[0]
440
440
  return _answer
441
- except Exception as e:
441
+ except Exception:
442
442
  _warn(f"Could not cast answer '{answer}' to an integer.", stacklevel=3)
443
443
 
444
444
  if not numeric:
445
445
  return answers
446
+
446
447
  _answers = []
447
448
  for a in answers:
448
449
  try:
@@ -451,17 +452,17 @@ def choose(
451
452
  if isinstance(_answer_to_return, tuple) and as_indices:
452
453
  _answer_to_return = _answer_to_return[0]
453
454
  _answers.append(_answer_to_return)
454
- except Exception as e:
455
+ except Exception:
455
456
  _warn(f"Could not cast answer '{a}' to an integer.", stacklevel=3)
456
457
  return _answers
457
458
 
458
459
 
459
460
  def get_password(
460
- username: Optional[str] = None,
461
- minimum_length: Optional[int] = None,
462
- confirm: bool = True,
463
- **kw: Any
464
- ) -> str:
461
+ username: Optional[str] = None,
462
+ minimum_length: Optional[int] = None,
463
+ confirm: bool = True,
464
+ **kw: Any
465
+ ) -> str:
465
466
  """
466
467
  Prompt the user for a password.
467
468
 
@@ -493,15 +494,15 @@ def get_password(
493
494
  from meerschaum.utils.warnings import warn
494
495
  while True:
495
496
  password = prompt(
496
- f"Password" + (f" for user '{username}':" if username is not None else ":"),
497
- is_password = True,
497
+ "Password" + (f" for user '{username}':" if username is not None else ":"),
498
+ is_password=True,
498
499
  **kw
499
500
  )
500
501
  if minimum_length is not None and len(password) < minimum_length:
501
502
  warn(
502
503
  "Password is too short. " +
503
504
  f"Please enter a password that is at least {minimum_length} characters.",
504
- stack = False
505
+ stack=False
505
506
  )
506
507
  continue
507
508
 
@@ -509,12 +510,12 @@ def get_password(
509
510
  return password
510
511
 
511
512
  _password = prompt(
512
- f"Confirm password" + (f" for user '{username}':" if username is not None else ":"),
513
- is_password = True,
513
+ "Confirm password" + (f" for user '{username}':" if username is not None else ":"),
514
+ is_password=True,
514
515
  **kw
515
516
  )
516
517
  if password != _password:
517
- warn(f"Passwords do not match! Please try again.", stack=False)
518
+ warn("Passwords do not match! Please try again.", stack=False)
518
519
  continue
519
520
  else:
520
521
  return password
@@ -550,13 +551,13 @@ def get_email(username: Optional[str] = None, allow_omit: bool = True, **kw: Any
550
551
  from meerschaum.utils.misc import is_valid_email
551
552
  while True:
552
553
  email = prompt(
553
- f"Email" + (f" for user '{username}'" if username is not None else "") +
554
+ "Email" + (f" for user '{username}'" if username is not None else "") +
554
555
  (" (empty to omit):" if allow_omit else ": "),
555
556
  **kw
556
557
  )
557
558
  if (allow_omit and email == '') or is_valid_email(email):
558
559
  return email
559
- warn(f"Invalid email! Please try again.", stack=False)
560
+ warn("Invalid email! Please try again.", stack=False)
560
561
 
561
562
 
562
563
  def check_noask(noask: bool = False) -> bool:
@@ -571,3 +572,20 @@ def check_noask(noask: bool = False) -> bool:
571
572
  os.environ.get(NOASK, 'false').lower()
572
573
  in ('1', 'true')
573
574
  )
575
+
576
+
577
+ def get_connectors_completer(*types: str):
578
+ """
579
+ Return a prompt-toolkit Completer object to pass into `prompt()`.
580
+ """
581
+ from meerschaum.utils.misc import get_connector_labels
582
+ prompt_toolkit_completion = mrsm.attempt_import('prompt_toolkit.completion', lazy=False)
583
+ Completer = prompt_toolkit_completion.Completer
584
+ Completion = prompt_toolkit_completion.Completion
585
+
586
+ class ConnectorCompleter(Completer):
587
+ def get_completions(self, document, complete_event):
588
+ for label in get_connector_labels(*types):
589
+ yield Completion(label, start_position=(-1 * len(document.text)))
590
+
591
+ return ConnectorCompleter()
@@ -410,7 +410,7 @@ def init_venv(
410
410
  pass
411
411
 
412
412
  def wait_for_lock():
413
- max_lock_seconds = 1.0
413
+ max_lock_seconds = 2.0
414
414
  step_sleep_seconds = 0.1
415
415
  init_venv_check_start = time.perf_counter()
416
416
  while ((time.perf_counter() - init_venv_check_start) < max_lock_seconds):
@@ -450,13 +450,22 @@ def init_venv(
450
450
  temp_vtp = VENVS_CACHE_RESOURCES_PATH / str(venv)
451
451
  rename_vtp = vtp.exists() and not temp_vtp.exists()
452
452
 
453
+ wait_for_lock()
454
+ update_lock(True)
455
+
453
456
  if rename_vtp:
454
457
  if debug:
455
458
  print(f"Moving '{vtp}' to '{temp_vtp}'...")
456
459
  shutil.move(vtp, temp_vtp)
457
460
 
458
- wait_for_lock()
459
- update_lock(True)
461
+ if venv_path.exists():
462
+ if debug:
463
+ print(f"Removing '{venv_path}'...")
464
+ try:
465
+ shutil.rmtree(venv_path)
466
+ except Exception as e:
467
+ if debug:
468
+ print(f"Failed to remove '{venv_path}' ({e}). Continuing...")
460
469
 
461
470
  if uv is not None:
462
471
  _venv_success = run_python_package(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: meerschaum
3
- Version: 2.7.5
3
+ Version: 2.7.6
4
4
  Summary: Sync Time-Series Pipes with Meerschaum
5
5
  Home-page: https://meerschaum.io
6
6
  Author: Bennett Meares
@@ -127,7 +127,7 @@ Provides-Extra: sql
127
127
  Requires-Dist: numpy>=1.18.5; extra == "sql"
128
128
  Requires-Dist: pandas[parquet]>=2.0.1; extra == "sql"
129
129
  Requires-Dist: pyarrow>=16.1.0; extra == "sql"
130
- Requires-Dist: dask[complete]>=2024.5.1; extra == "sql"
130
+ Requires-Dist: dask[complete]>=2024.12.1; extra == "sql"
131
131
  Requires-Dist: partd>=1.4.2; extra == "sql"
132
132
  Requires-Dist: pytz; extra == "sql"
133
133
  Requires-Dist: joblib>=0.17.0; extra == "sql"
@@ -187,7 +187,7 @@ Requires-Dist: valkey>=6.0.0; extra == "api"
187
187
  Requires-Dist: numpy>=1.18.5; extra == "api"
188
188
  Requires-Dist: pandas[parquet]>=2.0.1; extra == "api"
189
189
  Requires-Dist: pyarrow>=16.1.0; extra == "api"
190
- Requires-Dist: dask[complete]>=2024.5.1; extra == "api"
190
+ Requires-Dist: dask[complete]>=2024.12.1; extra == "api"
191
191
  Requires-Dist: partd>=1.4.2; extra == "api"
192
192
  Requires-Dist: pytz; extra == "api"
193
193
  Requires-Dist: joblib>=0.17.0; extra == "api"
@@ -292,7 +292,7 @@ Requires-Dist: pycparser>=2.21.0; extra == "full"
292
292
  Requires-Dist: numpy>=1.18.5; extra == "full"
293
293
  Requires-Dist: pandas[parquet]>=2.0.1; extra == "full"
294
294
  Requires-Dist: pyarrow>=16.1.0; extra == "full"
295
- Requires-Dist: dask[complete]>=2024.5.1; extra == "full"
295
+ Requires-Dist: dask[complete]>=2024.12.1; extra == "full"
296
296
  Requires-Dist: partd>=1.4.2; extra == "full"
297
297
  Requires-Dist: pytz; extra == "full"
298
298
  Requires-Dist: joblib>=0.17.0; extra == "full"
@@ -12,8 +12,8 @@ meerschaum/_internal/gui/app/__init__.py,sha256=rKUa8hHk6Fai-PDF61tQcpT1myxKcfmv
12
12
  meerschaum/_internal/gui/app/_windows.py,sha256=-VHdjTzA3V596fVqnbmTxemONSp_80-sTNJ0CTB8FwU,2632
13
13
  meerschaum/_internal/gui/app/actions.py,sha256=rx37qXf3uoa7Ou0n1cISqNFZNL0nr4wO7vSUmWO8f2E,935
14
14
  meerschaum/_internal/gui/app/pipes.py,sha256=4nAQ0rrHb_2bNgDF0Ru2YlbPaCDDzAl5beOGU4Af-4A,1596
15
- meerschaum/_internal/shell/Shell.py,sha256=-dw1k9NbG0VGX0Sve1c8gQ1_XsMYcmYl0VwSO98ERVk,40099
16
- meerschaum/_internal/shell/ShellCompleter.py,sha256=uWo-SYBXDGEeKExsjVWi-u7yfnc5XWWCy4Nl4eSO8j4,3340
15
+ meerschaum/_internal/shell/Shell.py,sha256=R6xW-D9gVuxJxQzf4Bf6E9V8exE40aCdrDJ_snUpoxA,39982
16
+ meerschaum/_internal/shell/ShellCompleter.py,sha256=Ex6mPv83RUNdC3ufRJCcaoOmQ8q8z6tCHDVzXQmWIpY,3293
17
17
  meerschaum/_internal/shell/ValidAutoSuggest.py,sha256=bARjOWMidz0dvMelLUe6yRPto5l3gcEHYHqFDjoh22I,1280
18
18
  meerschaum/_internal/shell/__init__.py,sha256=vXQoQPEVlYiUYai1b5AwQAlTnja6A2cSABnqXhzlS7I,281
19
19
  meerschaum/_internal/shell/updates.py,sha256=FmKu1NsIE7AI1zq8zNeKneZzORv6BeURQeX0lRR81Ag,5040
@@ -25,8 +25,8 @@ meerschaum/actions/__init__.py,sha256=MHPs8aRBhbZQXnqd_6tVtisTrNCgPAPgnNcXYbn0zP
25
25
  meerschaum/actions/api.py,sha256=41r3fBh3vAPyNaOrvbh2oh6WUJTR2I-zaOEZN60A66E,12538
26
26
  meerschaum/actions/attach.py,sha256=UV19d9W_2WYcrf7BRz7k3mriDoX1V4rA4AKvbLdor0o,3106
27
27
  meerschaum/actions/bootstrap.py,sha256=08o3PchrJ_Rv8IP30ZBH1Ovk-b8qFBGPedCjF7jRzSo,18084
28
- meerschaum/actions/clear.py,sha256=iTSdJpFIGLirFgBrOFb2GH1ShI2LZ1NIGLeGYOboZYQ,4916
29
- meerschaum/actions/copy.py,sha256=NHoC9cHJGgoox8L8B0afbu8lAxEh_MKa_pNeVunZsl0,6824
28
+ meerschaum/actions/clear.py,sha256=v_xHn7-Pu7iwFNJ07q9eJt2hqPV7OwNZHUYa9dvixs4,4976
29
+ meerschaum/actions/copy.py,sha256=z_51zEQCKDXnAGfICIGKS3klZ2OTPdiZPJACvpuheDY,6861
30
30
  meerschaum/actions/deduplicate.py,sha256=puYyxeFYEUy1Sd2IOcZB2e6MrNxAZl2bTLmNzFDkCiw,1167
31
31
  meerschaum/actions/delete.py,sha256=H5oP0nE7qIWnFvkuFhZQZQYBVC0IbUevpaQ_2YQKXRA,18559
32
32
  meerschaum/actions/drop.py,sha256=Hd5h4rrWd7qL2rTqglsTonUsEoH7qQlsfqNFSHGeqr0,2453
@@ -46,7 +46,7 @@ meerschaum/actions/sql.py,sha256=zG-KydYR654RHaF-O4Id3ACCDWeogk2B1R-OFLwFbG0,451
46
46
  meerschaum/actions/stack.py,sha256=ZwrCTGJ0x3jjZkRieWcvqasQHYCqNtB1HYvTX-r3Z3g,5996
47
47
  meerschaum/actions/start.py,sha256=NtdVzeB00PQBnDSUSu8ypHmMrZT8_Idmw5BfVZ--Zic,21296
48
48
  meerschaum/actions/stop.py,sha256=5fdUw70YN-yuUWrC-NhA88cxr9FZ5NbssbQ8xXO8nFU,4632
49
- meerschaum/actions/sync.py,sha256=QGhf0ZyrNaplPL6TkwHO9VQLEu_Gemmid93vdaovXoo,17153
49
+ meerschaum/actions/sync.py,sha256=br87b8uqpv7GW18f_O7Zg7QioPh0t377J082yfmuSak,17223
50
50
  meerschaum/actions/tag.py,sha256=SJf5qFW0ccLXjqlTdkK_0MCcrCMdg6xhYrhKdco0hdA,3053
51
51
  meerschaum/actions/uninstall.py,sha256=tBXhdXggSieGEQe4EPGxpgMK0MZTJCweNvAJ9-59El0,5776
52
52
  meerschaum/actions/upgrade.py,sha256=AjuC93Te-I_GWwIfuNkFJ2q1zVHDQ2Oco34S4JgK2iA,6485
@@ -62,7 +62,7 @@ meerschaum/api/dash/connectors.py,sha256=-Wd40ieYJI2nOASXi4V1C4bvLekjnN_tj6zp7Hg
62
62
  meerschaum/api/dash/graphs.py,sha256=wJUDWzcLN8-C3xko6rj0F2v7Rt8YDkSXoVkkXJjYGIk,2046
63
63
  meerschaum/api/dash/jobs.py,sha256=mj9STE6AaQY4fwkjD1JcYRG0iW3VEcP04bO1SlKgiXw,7681
64
64
  meerschaum/api/dash/keys.py,sha256=hzEVeN60SAfVTVSO5lajGaykxRIKGhj9Ph00HRJnNoE,12598
65
- meerschaum/api/dash/pipes.py,sha256=39Ler1YIxaDmbZu9zKuJclA-j9psbrPRwZfBnh4KuxA,26264
65
+ meerschaum/api/dash/pipes.py,sha256=Zm2UKovwz6K8Mt6dTCY2LgDyUyFhEZ5D8nWw4ecPUXI,26210
66
66
  meerschaum/api/dash/plugins.py,sha256=KdfG04f6SsUpBg-nm7MUJegFGuElOj-GAkxDX98hi60,3768
67
67
  meerschaum/api/dash/sessions.py,sha256=-y5p4MYKh1eFzppkBfMsd6T7-rJs1nYS2-4fbVRAeRA,5029
68
68
  meerschaum/api/dash/sync.py,sha256=9lt7IRdG-fe9gf_ZO_viPiGlerX7ic6r_VFocv3I51A,504
@@ -132,7 +132,7 @@ meerschaum/api/routes/_webterm.py,sha256=MenDvWXnZ8CWEmryB46pKohMf0PN6o1xJGZ3LFj
132
132
  meerschaum/api/tables/__init__.py,sha256=e2aNC0CdlWICTUMx1i9RauF8Pm426J0RZJbsJWv4SWo,482
133
133
  meerschaum/config/__init__.py,sha256=5ZBq71P9t3nb74r5CGvMfNuauPscfegBX-nkaAUi5C4,11541
134
134
  meerschaum/config/_dash.py,sha256=BJHl4xMrQB-YHUEU7ldEW8q_nOPoIRSOqLrfGElc6Dw,187
135
- meerschaum/config/_default.py,sha256=IDRo8nLWija_cawiqeS6cPwZ9deDF9179m_rwGntNLA,5831
135
+ meerschaum/config/_default.py,sha256=6SC7MOkU_2oJ7RtFXQCz9w1Qqg2_8w5UdOaR_HL3lzI,6009
136
136
  meerschaum/config/_edit.py,sha256=M9yX_SDD24gV5kWITZpy7p9AWTizJsIAGWAs3WZx-Ws,9087
137
137
  meerschaum/config/_environment.py,sha256=Vv4DLDfc2vKLbCLsMvkQDj77K4kEvHKEBmUBo-wCrgo,4419
138
138
  meerschaum/config/_formatting.py,sha256=OMuqS1EWOsj_34wSs2tOqGIWci3bTMIZ5l-uelZgsIM,6672
@@ -143,7 +143,7 @@ meerschaum/config/_preprocess.py,sha256=-AEA8m_--KivZwTQ1sWN6LTn5sio_fUr2XZ51BO6
143
143
  meerschaum/config/_read_config.py,sha256=RLC3HHi_1ndj7ITVDKLD9_uULY3caGRwSz3ATYE-ixA,15014
144
144
  meerschaum/config/_shell.py,sha256=46_m49Txc5q1rGfCgO49ca48BODx45DQJi8D0zz1R18,4245
145
145
  meerschaum/config/_sync.py,sha256=jHcWRkxd82_BgX8Xo8agsWvf7BSbv3qHLWmYl6ehp_0,4242
146
- meerschaum/config/_version.py,sha256=FtGr91JvNFrz0tCWU-8xhZY04Aon0uXjcSuAPXv1SUI,71
146
+ meerschaum/config/_version.py,sha256=EePnAdxzJgKO-MgeMY2aPKqoD0YcmJBjbRii3glP9Q4,71
147
147
  meerschaum/config/paths.py,sha256=JjibeGN3YAdSNceRwsd42aNmeUrIgM6ndzC8qZAmNI0,621
148
148
  meerschaum/config/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
149
  meerschaum/config/stack/__init__.py,sha256=2UukC0Lmk-aVL1o1qXzumqmuIrw3vu9fD7iCuz4XD4I,10544
@@ -162,23 +162,23 @@ meerschaum/connectors/api/_actions.py,sha256=gd3F8i5BvN8XRvMcPvPVR8sc1DeLzgoBHdD
162
162
  meerschaum/connectors/api/_fetch.py,sha256=Khq9AFr1nk8Dsmcedb77aWhAuHw0JGgVeahDG95Q5MQ,2072
163
163
  meerschaum/connectors/api/_jobs.py,sha256=N5lpHFGG10jlVgaJeWAOTuLBQw3AdgjXsEPpp1YwZQE,11270
164
164
  meerschaum/connectors/api/_login.py,sha256=5GsD-B214vr5EYfM3XrTUs1sTFApxZA-9dNxq8oNSyg,2050
165
- meerschaum/connectors/api/_misc.py,sha256=OZRZBYOokKIEjmQaR8jUYgu6ZRn9VzXBChzR8CfDv_w,1092
166
- meerschaum/connectors/api/_pipes.py,sha256=dGs5rS7qoX4-qw-KTw-_a9b9EtLmLCC-ZKm03ZGts6Q,21263
165
+ meerschaum/connectors/api/_misc.py,sha256=XK0LLexNUEKZjAAqoJ-9oOgwLlMdwxSOvcpqO5NuOas,1083
166
+ meerschaum/connectors/api/_pipes.py,sha256=hk6Qj3tgog8naxl0Y2l6TfJsG4AZmel3bFIaLxuy0XY,21248
167
167
  meerschaum/connectors/api/_plugins.py,sha256=z04tPjfZZWwa7T60mogZH3X3wDmeLdnoN5Oh8m_YsU8,5217
168
168
  meerschaum/connectors/api/_request.py,sha256=Wc4Y70t0VxEj3_ch5fAeeoSAeFMuRnyNLOV-aUFInjY,6996
169
169
  meerschaum/connectors/api/_uri.py,sha256=HWxqGx4R1cHZ3ywy9Ro9ePbFxxusw4RLaC3hpGt9Z6I,1469
170
170
  meerschaum/connectors/api/_users.py,sha256=kzb7ENgXwQ19OJYKOuuWzx2rwVuUZCly9dTnyvVuT2Q,5275
171
171
  meerschaum/connectors/plugin/PluginConnector.py,sha256=aQ1QaB7MordCFimZqoGLb0R12PfDUN_nWks2J5mzeAs,2084
172
172
  meerschaum/connectors/plugin/__init__.py,sha256=pwF7TGY4WNz2_HaVdmK4rPQ9ZwTOEuPHgzOqsGcoXJw,198
173
- meerschaum/connectors/sql/_SQLConnector.py,sha256=g9SFK30CZp7CTJI-SdpOanL1NQUBFQeUng7FSGacJA4,11985
173
+ meerschaum/connectors/sql/_SQLConnector.py,sha256=uyGoCshgL-u6j3VbCDiBJn8LkVuveLeE62y8MWxSo24,12015
174
174
  meerschaum/connectors/sql/__init__.py,sha256=3cqYiDkVasn7zWdtOTAZbT4bo95AuvGOmDD2TkaAxtw,205
175
175
  meerschaum/connectors/sql/_cli.py,sha256=VqAHkdXC0HVXuHaZik2q-cTVmIsuS4DWMcPMJPP_g-Q,4514
176
176
  meerschaum/connectors/sql/_create_engine.py,sha256=RzJz4Qc43P4JS6tkgVvAhbdjEejIepWbxymIfVZ44Nk,10555
177
177
  meerschaum/connectors/sql/_fetch.py,sha256=GOU1JnPOBgaI3dDr0JdAmfTMPLIMM0EFHrsqDgDIO74,14070
178
178
  meerschaum/connectors/sql/_instance.py,sha256=mmZnodccuCqmZN-UnznnFZ7JodxtT47kwjDDaDKgwUg,6274
179
- meerschaum/connectors/sql/_pipes.py,sha256=n0tHoVnBmno08qqO5qaFuSlfIW96_VVm8T1k5ZRdPQw,121592
179
+ meerschaum/connectors/sql/_pipes.py,sha256=M0VQqkwd9sSyyttyKxonjoGi61guVc-oa1KiuWS7sd8,122315
180
180
  meerschaum/connectors/sql/_plugins.py,sha256=wbxcNxqTtjfDsxPvdVGTllasYf6NHHzODaQ72hEUSBQ,8135
181
- meerschaum/connectors/sql/_sql.py,sha256=Q4MKuUlqrgXuYCbpCtoQlvqOvASDQ7BkkLLSYPLh_JE,41052
181
+ meerschaum/connectors/sql/_sql.py,sha256=brYLHJFt6BYlFYUhK--4okkll7UTkRR_PnvjjIJvXNY,41289
182
182
  meerschaum/connectors/sql/_uri.py,sha256=0BrhQtqQdzg9mR04gWBZINs_BbPFtSlTECXT_TCUwik,3460
183
183
  meerschaum/connectors/sql/_users.py,sha256=FJjYeJGhr-TDHziNc6p_5mupGRtGjezKPIYgHFEVSnY,9956
184
184
  meerschaum/connectors/sql/tools.py,sha256=jz8huOaRCwGlYdtGfAqAh7SoK8uydYBrasKQba9FT38,187
@@ -211,33 +211,33 @@ meerschaum/core/Plugin/__init__.py,sha256=UXg64EvJPgI1PCxkY_KM02-ZmBm4FZpLPIQR_u
211
211
  meerschaum/core/User/_User.py,sha256=qbI0GIkr3G0PI4d9S49uatbJQ2kH_-z5-GoVJ0fuEtA,6624
212
212
  meerschaum/core/User/__init__.py,sha256=9qNy-Gobui4x6GiaE8U7-WOggsdniOM3_wegLN3SVKs,988
213
213
  meerschaum/jobs/_Executor.py,sha256=qM62BhFTM4tyJ7p90KOM0y3qyeRY9k3ZV_aTDJMHnO8,1682
214
- meerschaum/jobs/_Job.py,sha256=wRsmrQ1bm898BxXELbHTltKYBj0bK0GmegE8zeL0FG8,32161
214
+ meerschaum/jobs/_Job.py,sha256=m_OzHG1zdV3jBS1CS6idT-sc5XBx-sMz4CJZbWKeKqI,32217
215
215
  meerschaum/jobs/__init__.py,sha256=YjwB6t8HCT593ckrOlImgk0kLX-1NgAYzNXVwS-uvyY,12173
216
216
  meerschaum/jobs/systemd.py,sha256=Rq-tsDPslG17ZhpKMrVJ5r8Z0IPr6DEc9APObfIoXCg,24614
217
217
  meerschaum/plugins/_Plugin.py,sha256=bIo4HX8TTWIcwIHROwMt4VK6OoEUhY_3Qc8q-2dp-ZA,33895
218
- meerschaum/plugins/__init__.py,sha256=6krcqaMKyzuVqesXMqEL0XEy2SJQ4xfNt2-oI_fJ6v0,26278
218
+ meerschaum/plugins/__init__.py,sha256=Kl7Dz0CwUUxyjRC5RWnYo6WMLsOvdX2eQ38Rh3BjdzY,26465
219
219
  meerschaum/plugins/bootstrap.py,sha256=VwjpZAuYdqPJW0YoVgAoM_taHkdQHqP902-8T7OWWCI,11339
220
220
  meerschaum/utils/__init__.py,sha256=QrK1K9hIbPCRCM5k2nZGFqGnrqhA0Eh-iSmCU7FG6Cs,612
221
221
  meerschaum/utils/_get_pipes.py,sha256=tu4xKPoDn79Dz2kWM13cXTP4DSCkn-3G9M8KiLftopw,11073
222
222
  meerschaum/utils/dataframe.py,sha256=fM8_DxnMTMhXDUqWIVXR-bOOwzBGO-cRcjarOIN3jdQ,47990
223
223
  meerschaum/utils/debug.py,sha256=GyIzJmunkoPnOcZNYVQdT4Sgd-aOb5MI2VbIgATOjIQ,3695
224
224
  meerschaum/utils/interactive.py,sha256=t-6jWozXSqL7lYGDHuwiOjTgr-UKhdcg61q_eR5mikI,3196
225
- meerschaum/utils/misc.py,sha256=RW_WmNtAieP828OtJhr4dHKTQI2nxc4kTwn-Q5N3YBw,47055
225
+ meerschaum/utils/misc.py,sha256=Ut__DxYXuu-WtF9Mg2Z1CrnQMBmhPuqGsjOgiZMhAww,47079
226
226
  meerschaum/utils/networking.py,sha256=Sr_eYUGW8_UV9-k9LqRFf7xLtbUcsDucODyLCRsFRUc,1006
227
227
  meerschaum/utils/pool.py,sha256=vkE42af4fjrTEJTxf6Ek3xGucm1MtEkpsSEiaVzNKHs,2655
228
228
  meerschaum/utils/process.py,sha256=9O8PPPJjY9Q5W2f39I3B3lFU6TlSiRiI3bgrzdOOyOw,7843
229
- meerschaum/utils/prompt.py,sha256=SOpAvHcVFuk7-J4cqK_LkahWo6oJmLobeHg5fwM_9aY,18949
229
+ meerschaum/utils/prompt.py,sha256=qbS8l0DfD6eRB9_RRbfkKLPs3m-Hw2zXSeQCf0TDJgU,19370
230
230
  meerschaum/utils/schedule.py,sha256=bUsaCO9CGn2vJO5UvoISScHDDGIiMdCPHxpTFmu7vwE,11531
231
231
  meerschaum/utils/sql.py,sha256=JqOfWCHWAlm1fr7mtZMquoGCOnPyIlX5LDshcRFDgdo,77993
232
232
  meerschaum/utils/threading.py,sha256=awjbVL_QR6G-o_9Qk85utac9cSdqkiC8tQSdERCdrG8,2814
233
233
  meerschaum/utils/typing.py,sha256=U3MC347sh1umpa3Xr1k71eADyDmk4LB6TnVCpq8dVzI,2830
234
234
  meerschaum/utils/warnings.py,sha256=n-phr3BftNNgyPnvnXC_VMSjtCvjiCZ-ewmVfcROhkc,6611
235
235
  meerschaum/utils/yaml.py,sha256=PoC1du0pn2hLwTHwL-zuOf_EBWZSbCGOz-P-AZ4BWN0,3901
236
- meerschaum/utils/daemon/Daemon.py,sha256=zxU15r7XJCTU5r5IWdiH9GQEenUFSnV439f0Vq1EzgY,42760
236
+ meerschaum/utils/daemon/Daemon.py,sha256=jNhzpkcR-kXgIQKBqr--cFx6ZhAb0a0sdjnCOUkLEL0,42885
237
237
  meerschaum/utils/daemon/FileDescriptorInterceptor.py,sha256=MJKMO0Syf3d8yWUs6xXcQzg8Ptsuvh2aCRRoglOjusA,5257
238
238
  meerschaum/utils/daemon/RotatingFile.py,sha256=ePm_svjwyFDWh6V1k-bp1RHXCSWlyxDtlFu4SU4XvPU,24369
239
239
  meerschaum/utils/daemon/StdinFile.py,sha256=qdZ8E_RSOkURypwnS50mWeyWyRig1bAY9tKWMTVKajc,3307
240
- meerschaum/utils/daemon/__init__.py,sha256=o9jWb4lRTIyny4EPt7fPXFgV_vIf1mUofsTwoE1ZecA,8751
240
+ meerschaum/utils/daemon/__init__.py,sha256=ziRPyu_IM3l7Xd58y3Uvt0fZLoirJ9nuboFIxxult6c,8741
241
241
  meerschaum/utils/daemon/_names.py,sha256=d2ZwTxBoTAqXZkCfZ5LuX2XrkQmLNUq1OTlUqfoH5dA,4515
242
242
  meerschaum/utils/dtypes/__init__.py,sha256=c6DoYyCbWvMdRapBRKP5UJYLRUWtkTIlC_8HRzXFh2s,12166
243
243
  meerschaum/utils/dtypes/sql.py,sha256=Ew-ULDAJipzWpq_W-3fGGgTORhtoIqRZzZcS7k0L4B4,19582
@@ -246,16 +246,16 @@ meerschaum/utils/formatting/_jobs.py,sha256=izsqPJhTtUkXUUtWnbXtReYsUYwulXtci3pB
246
246
  meerschaum/utils/formatting/_pipes.py,sha256=OISJmmFiilaDbZxkiXck_g39MnnTfk_fJJyJ-YInvXA,19559
247
247
  meerschaum/utils/formatting/_pprint.py,sha256=tgrT3FyGyu5CWJYysqK3kX1xdZYorlbOk9fcU_vt9Qg,3096
248
248
  meerschaum/utils/formatting/_shell.py,sha256=XH7VFLteNv7NGtWhJl7FdIGt80sKeTiDoJokGSDAwBM,3761
249
- meerschaum/utils/packages/__init__.py,sha256=vg1C9dpj1MLOWgvNGrKkqLRe4Z9hUnNdQDOCvReCBh4,64392
250
- meerschaum/utils/packages/_packages.py,sha256=ykannoLv2Fm4iwZwiIlNAGZvt654cMJhjXr1VJPoEDo,8867
249
+ meerschaum/utils/packages/__init__.py,sha256=TdKaj2tmN4bFwzusOfMv24P5ET7Zv73vyoOf9GOIr5E,64427
250
+ meerschaum/utils/packages/_packages.py,sha256=_xODMSz1FAcx3XHrn9RXUhGJ1zg-QKsVu9zYZV2UJeY,8868
251
251
  meerschaum/utils/packages/lazy_loader.py,sha256=VHnph3VozH29R4JnSSBfwtA5WKZYZQFT_GeQSShCnuc,2540
252
252
  meerschaum/utils/venv/_Venv.py,sha256=gc1TCeAj-kTZbQFAT9xl1bi4HXFV5ApT0dPOJfxwr78,3748
253
- meerschaum/utils/venv/__init__.py,sha256=wqjp0ocIkp6nsHYLUObXIhfYY5CjX-JnS6psm783ga0,26755
254
- meerschaum-2.7.5.dist-info/LICENSE,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
255
- meerschaum-2.7.5.dist-info/METADATA,sha256=kQOkmZPuhuo-Ee1b_2JlzUnmfGYOZOBBUWs3pHZ_g1M,24224
256
- meerschaum-2.7.5.dist-info/NOTICE,sha256=OTA9Fcthjf5BRvWDDIcBC_xfLpeDV-RPZh3M-HQBRtQ,114
257
- meerschaum-2.7.5.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
258
- meerschaum-2.7.5.dist-info/entry_points.txt,sha256=5YBVzibw-0rNA_1VjB16z5GABsOGf-CDhW4yqH8C7Gc,88
259
- meerschaum-2.7.5.dist-info/top_level.txt,sha256=bNoSiDj0El6buocix-FRoAtJOeq1qOF5rRm2u9i7Q6A,11
260
- meerschaum-2.7.5.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
261
- meerschaum-2.7.5.dist-info/RECORD,,
253
+ meerschaum/utils/venv/__init__.py,sha256=vVU9vj7t-HTiRU--ReQZ9kRLesVqcHnSJDbmcfC-Dzg,27030
254
+ meerschaum-2.7.6.dist-info/LICENSE,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
255
+ meerschaum-2.7.6.dist-info/METADATA,sha256=fWChi6YW7sc_kNoXq7H3ryE-RdPH0fSR5UsFWQfMhps,24227
256
+ meerschaum-2.7.6.dist-info/NOTICE,sha256=OTA9Fcthjf5BRvWDDIcBC_xfLpeDV-RPZh3M-HQBRtQ,114
257
+ meerschaum-2.7.6.dist-info/WHEEL,sha256=A3WOREP4zgxI0fKrHUG8DC8013e3dK3n7a6HDbcEIwE,91
258
+ meerschaum-2.7.6.dist-info/entry_points.txt,sha256=5YBVzibw-0rNA_1VjB16z5GABsOGf-CDhW4yqH8C7Gc,88
259
+ meerschaum-2.7.6.dist-info/top_level.txt,sha256=bNoSiDj0El6buocix-FRoAtJOeq1qOF5rRm2u9i7Q6A,11
260
+ meerschaum-2.7.6.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
261
+ meerschaum-2.7.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.7.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5