meerschaum 2.1.5__py3-none-any.whl → 2.1.6__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.
@@ -9,7 +9,7 @@ NOTE: `sync` required a SQL connection and is not intended for client use
9
9
  """
10
10
 
11
11
  from __future__ import annotations
12
- from datetime import timedelta
12
+ from datetime import timedelta, datetime, timezone
13
13
  import meerschaum as mrsm
14
14
  from meerschaum.utils.typing import SuccessTuple, Any, List, Optional, Tuple, Union
15
15
 
@@ -39,7 +39,7 @@ def sync(
39
39
 
40
40
  def _pipes_lap(
41
41
  workers: Optional[int] = None,
42
- debug: bool = None,
42
+ debug: Optional[bool] = None,
43
43
  unblock: bool = False,
44
44
  force: bool = False,
45
45
  min_seconds: int = 1,
@@ -52,7 +52,7 @@ def _pipes_lap(
52
52
  nopretty: bool = False,
53
53
  _progress: Optional['rich.progress.Progress'] = None,
54
54
  **kw: Any
55
- ) -> Tuple[List[meerschaum.Pipe], List[meerschaum.Pipe]]:
55
+ ) -> Tuple[List[mrsm.Pipe], List[mrsm.Pipe]]:
56
56
  """
57
57
  Do a lap of syncing pipes.
58
58
  """
@@ -402,11 +402,20 @@ def _wrap_pipe(
402
402
  Wrapper function for handling exceptions.
403
403
  """
404
404
  import time
405
+ import traceback
406
+ from datetime import datetime, timedelta, timezone
407
+ import meerschaum as mrsm
408
+ from meerschaum.utils.typing import is_success_tuple, SuccessTuple
405
409
  from meerschaum.connectors import get_connector_plugin
406
410
  from meerschaum.utils.venv import Venv
407
411
  from meerschaum.plugins import _pre_sync_hooks, _post_sync_hooks
408
412
  from meerschaum.utils.misc import filter_keywords
413
+ from meerschaum.utils.pool import get_pool
414
+ from meerschaum.utils.warnings import warn
415
+
416
+ pool = get_pool(workers=workers)
409
417
 
418
+ sync_timestamp = datetime.now(timezone.utc)
410
419
  sync_start = time.perf_counter()
411
420
  sync_kwargs = {k: v for k, v in kw.items() if k != 'blocking'}
412
421
  sync_kwargs.update({
@@ -415,8 +424,9 @@ def _wrap_pipe(
415
424
  'debug': debug,
416
425
  'min_seconds': min_seconds,
417
426
  'workers': workers,
418
- 'bounded': 'bounded',
427
+ 'bounded': bounded,
419
428
  'chunk_interval': chunk_interval,
429
+ 'sync_timestamp': sync_timestamp,
420
430
  })
421
431
  if not verify and not deduplicate:
422
432
  sync_method = pipe.sync
@@ -427,12 +437,32 @@ def _wrap_pipe(
427
437
  sync_kwargs['deduplicate'] = deduplicate
428
438
  sync_kwargs['sync_method'] = sync_method
429
439
 
430
- for module_name, pre_sync_hooks in _pre_sync_hooks.items():
431
- plugin_name = module_name.split('.')[-1] if module_name.startswith('plugins.') else None
440
+ def call_sync_hook(plugin_name: str, sync_hook) -> SuccessTuple:
432
441
  plugin = mrsm.Plugin(plugin_name) if plugin_name else None
433
- with Venv(plugin):
434
- for pre_sync_hook in pre_sync_hooks:
435
- _ = pre_sync_hook(pipe, **filter_keywords(pre_sync_hook, **sync_kwargs))
442
+ with mrsm.Venv(plugin):
443
+ try:
444
+ sync_hook_result = sync_hook(pipe, **filter_keywords(sync_hook, **sync_kwargs))
445
+ if is_success_tuple(sync_hook_result):
446
+ return sync_hook_result
447
+ except Exception as e:
448
+ msg = (
449
+ f"Failed to execute sync hook '{sync_hook.__name__}' "
450
+ + f"from plugin '{plugin}':\n{traceback.format_exc()}"
451
+ )
452
+ warn(msg, stack=False)
453
+ return False, msg
454
+ return True, "Success"
455
+
456
+ hook_results = []
457
+ def apply_hooks(is_pre_sync: bool):
458
+ _sync_hooks = (_pre_sync_hooks if is_pre_sync else _post_sync_hooks)
459
+ for module_name, sync_hooks in _sync_hooks.items():
460
+ plugin_name = module_name.split('.')[-1] if module_name.startswith('plugins.') else None
461
+ for sync_hook in sync_hooks:
462
+ hook_result = pool.apply_async(call_sync_hook, (plugin_name, sync_hook))
463
+ hook_results.append(hook_result)
464
+
465
+ apply_hooks(True)
436
466
 
437
467
  try:
438
468
  with Venv(get_connector_plugin(pipe.connector), debug=debug):
@@ -444,18 +474,16 @@ def _wrap_pipe(
444
474
  return_tuple = (False, f"Failed to sync {pipe} with exception:" + "\n" + str(e))
445
475
 
446
476
  duration = time.perf_counter() - sync_start
447
- sync_kwargs['duration'] = duration
448
- for module_name, post_sync_hooks in _post_sync_hooks.items():
449
- plugin_name = module_name.split('.')[-1] if module_name.startswith('plugins.') else None
450
- plugin = mrsm.Plugin(plugin_name) if plugin_name else None
451
- with Venv(plugin):
452
- for post_sync_hook in post_sync_hooks:
453
- _ = post_sync_hook(
454
- pipe,
455
- return_tuple,
456
- **filter_keywords(post_sync_hook, **sync_kwargs)
457
- )
458
-
477
+ sync_kwargs.update({
478
+ 'success_tuple': return_tuple,
479
+ 'sync_duration': duration,
480
+ 'sync_complete_timestamp': datetime.now(timezone.utc),
481
+ })
482
+ apply_hooks(False)
483
+ for hook_result in hook_results:
484
+ hook_success, hook_msg = hook_result.get()
485
+ mrsm.pprint((hook_success, hook_msg))
486
+
459
487
  return return_tuple
460
488
 
461
489
 
@@ -2,4 +2,4 @@
2
2
  Specify the Meerschaum release version.
3
3
  """
4
4
 
5
- __version__ = "2.1.5"
5
+ __version__ = "2.1.6"
@@ -385,7 +385,13 @@ def get_create_index_queries(
385
385
  -------
386
386
  A dictionary of column names mapping to lists of queries.
387
387
  """
388
- from meerschaum.utils.sql import sql_item_name, get_distinct_col_count, update_queries
388
+ from meerschaum.utils.sql import (
389
+ sql_item_name,
390
+ get_distinct_col_count,
391
+ update_queries,
392
+ get_null_replacement,
393
+ COALESCE_UNIQUE_INDEX_FLAVORS,
394
+ )
389
395
  from meerschaum.config import get_config
390
396
  index_queries = {}
391
397
 
@@ -497,15 +503,37 @@ def get_create_index_queries(
497
503
  if ix and ix in existing_cols_types
498
504
  ]
499
505
  )
506
+ coalesce_indices_cols_str = ', '.join(
507
+ [
508
+ (
509
+ "COALESCE("
510
+ + sql_item_name(ix, self.flavor)
511
+ + ", "
512
+ + get_null_replacement(existing_cols_types[ix], self.flavor)
513
+ + ") "
514
+ ) if ix_key != 'datetime' else (sql_item_name(ix, self.flavor))
515
+ for ix_key, ix in pipe.columns.items()
516
+ if ix and ix in existing_cols_types
517
+ ]
518
+ )
519
+ unique_index_name = sql_item_name(pipe.target + '_unique_index', self.flavor)
500
520
  constraint_name = sql_item_name(pipe.target + '_constraint', self.flavor)
501
- constraint_query = (
521
+ add_constraint_query = (
502
522
  f"ALTER TABLE {_pipe_name} ADD CONSTRAINT {constraint_name} UNIQUE ({indices_cols_str})"
503
- if self.flavor != 'sqlite'
504
- else f"CREATE UNIQUE INDEX {constraint_name} ON {_pipe_name} ({indices_cols_str})"
505
523
  )
524
+ unique_index_cols_str = (
525
+ indices_cols_str
526
+ if self.flavor not in COALESCE_UNIQUE_INDEX_FLAVORS
527
+ else coalesce_indices_cols_str
528
+ )
529
+ create_unique_index_query = (
530
+ f"CREATE UNIQUE INDEX {unique_index_name} ON {_pipe_name} ({unique_index_cols_str})"
531
+ )
532
+ constraint_queries = [create_unique_index_query]
533
+ if self.flavor != 'sqlite':
534
+ constraint_queries.append(add_constraint_query)
506
535
  if upsert and indices_cols_str:
507
- index_queries[constraint_name] = [constraint_query]
508
-
536
+ index_queries[unique_index_name] = constraint_queries
509
537
  return index_queries
510
538
 
511
539
 
@@ -1074,7 +1102,7 @@ def get_pipe_attributes(
1074
1102
  def sync_pipe(
1075
1103
  self,
1076
1104
  pipe: mrsm.Pipe,
1077
- df: Union[pandas.DataFrame, str, Dict[Any, Any], None] = None,
1105
+ df: Union[pd.DataFrame, str, Dict[Any, Any], None] = None,
1078
1106
  begin: Optional[datetime] = None,
1079
1107
  end: Optional[datetime] = None,
1080
1108
  chunksize: Optional[int] = -1,
@@ -1286,7 +1314,11 @@ def sync_pipe(
1286
1314
  temp_pipe = Pipe(
1287
1315
  pipe.connector_keys.replace(':', '_') + '_', pipe.metric_key, pipe.location_key,
1288
1316
  instance = pipe.instance_keys,
1289
- columns = pipe.columns,
1317
+ columns = {
1318
+ ix_key: ix
1319
+ for ix_key, ix in pipe.columns.items()
1320
+ if ix and ix in update_df.columns
1321
+ },
1290
1322
  dtypes = pipe.dtypes,
1291
1323
  target = temp_target,
1292
1324
  temporary = True,
@@ -214,22 +214,6 @@ def create_tables(
214
214
  from meerschaum.utils.sql import get_rename_table_queries, table_exists
215
215
  _tables = tables if tables is not None else get_tables(conn)
216
216
 
217
- rename_queries = []
218
- for table_key, table in _tables.items():
219
- if table_exists(
220
- table_key,
221
- conn,
222
- schema = conn.instance_schema,
223
- ):
224
- rename_queries.extend(get_rename_table_queries(
225
- table_key,
226
- table.name,
227
- schema = conn.instance_schema,
228
- flavor = conn.flavor,
229
- ))
230
- if rename_queries:
231
- conn.exec_queries(rename_queries)
232
-
233
217
  try:
234
218
  conn.metadata.create_all(bind=conn.engine)
235
219
  except Exception as e:
@@ -8,7 +8,7 @@ Retrieve Pipes' data from instances.
8
8
 
9
9
  from __future__ import annotations
10
10
  from datetime import datetime, timedelta
11
- from meerschaum.utils.typing import Optional, Dict, Any, Union, Generator, List, Tuple
11
+ from meerschaum.utils.typing import Optional, Dict, Any, Union, Generator, List, Tuple, Iterator
12
12
  from meerschaum.config import get_config
13
13
 
14
14
  def get_data(
@@ -247,7 +247,7 @@ def _get_data_as_iterator(
247
247
  fresh: bool = False,
248
248
  debug: bool = False,
249
249
  **kw: Any
250
- ) -> Generator['pd.DataFrame']:
250
+ ) -> Iterator['pd.DataFrame']:
251
251
  """
252
252
  Return a pipe's data as a generator.
253
253
  """
@@ -267,16 +267,17 @@ def _get_data_as_iterator(
267
267
 
268
268
  _ = kw.pop('as_chunks', None)
269
269
  _ = kw.pop('as_iterator', None)
270
+ dt_col = self.columns.get('datetime', None)
270
271
  min_dt = (
271
272
  begin
272
273
  if begin is not None
273
274
  else self.get_sync_time(round_down=False, newest=False, params=params, debug=debug)
274
- )
275
+ ) if dt_col else None
275
276
  max_dt = (
276
277
  end
277
278
  if end is not None
278
279
  else self.get_sync_time(round_down=False, newest=True, params=params, debug=debug)
279
- )
280
+ ) if dt_col else None
280
281
 
281
282
  ### We want to search just past the maximum value.
282
283
  if end is None:
meerschaum/utils/sql.py CHANGED
@@ -38,6 +38,7 @@ version_queries = {
38
38
  'oracle': "SELECT version from PRODUCT_COMPONENT_VERSION WHERE rownum = 1",
39
39
  }
40
40
  SKIP_IF_EXISTS_FLAVORS = {'mssql', 'oracle'}
41
+ COALESCE_UNIQUE_INDEX_FLAVORS = {'timescaledb', 'postgresql', 'citus'}
41
42
  update_queries = {
42
43
  'default': """
43
44
  UPDATE {target_table_name} AS f
@@ -53,25 +54,25 @@ update_queries = {
53
54
  INSERT INTO {target_table_name} ({patch_cols_str})
54
55
  SELECT {patch_cols_str}
55
56
  FROM {patch_table_name}
56
- ON CONFLICT ({join_cols_str}) DO UPDATE {sets_subquery_none_excluded}
57
+ ON CONFLICT ({join_cols_str}) DO {update_or_nothing} {sets_subquery_none_excluded}
57
58
  """,
58
59
  'postgresql-upsert': """
59
60
  INSERT INTO {target_table_name} ({patch_cols_str})
60
61
  SELECT {patch_cols_str}
61
62
  FROM {patch_table_name}
62
- ON CONFLICT ({join_cols_str}) DO UPDATE {sets_subquery_none_excluded}
63
+ ON CONFLICT ({join_cols_str}) DO {update_or_nothing} {sets_subquery_none_excluded}
63
64
  """,
64
65
  'citus-upsert': """
65
66
  INSERT INTO {target_table_name} ({patch_cols_str})
66
67
  SELECT {patch_cols_str}
67
68
  FROM {patch_table_name}
68
- ON CONFLICT ({join_cols_str}) DO UPDATE {sets_subquery_none_excluded}
69
+ ON CONFLICT ({join_cols_str}) DO {update_or_nothing} {sets_subquery_none_excluded}
69
70
  """,
70
71
  'cockroachdb-upsert': """
71
72
  INSERT INTO {target_table_name} ({patch_cols_str})
72
73
  SELECT {patch_cols_str}
73
74
  FROM {patch_table_name}
74
- ON CONFLICT ({join_cols_str}) DO UPDATE {sets_subquery_none_excluded}
75
+ ON CONFLICT ({join_cols_str}) DO {update_or_nothing} {sets_subquery_none_excluded}
75
76
  """,
76
77
  'mysql': """
77
78
  UPDATE {target_table_name} AS f
@@ -122,7 +123,7 @@ update_queries = {
122
123
  SELECT {patch_cols_str}
123
124
  FROM {patch_table_name}
124
125
  WHERE true
125
- ON CONFLICT ({join_cols_str}) DO UPDATE {sets_subquery_none_excluded}
126
+ ON CONFLICT ({join_cols_str}) DO {update_or_nothing} {sets_subquery_none_excluded}
126
127
  """,
127
128
  'sqlite_delete_insert': [
128
129
  """
@@ -1084,7 +1085,7 @@ def get_update_queries(
1084
1085
  for col in patch_table_columns
1085
1086
  ]
1086
1087
  )
1087
- join_cols_str = ','.join(
1088
+ join_cols_str = ', '.join(
1088
1089
  [
1089
1090
  sql_item_name(col, flavor)
1090
1091
  for col in join_cols
@@ -1109,10 +1110,27 @@ def get_update_queries(
1109
1110
  if debug:
1110
1111
  dprint(f"value_cols: {value_cols}")
1111
1112
 
1112
- if not value_cols or not join_cols_types:
1113
+ if not join_cols_types:
1114
+ return []
1115
+ if not value_cols and not upsert:
1113
1116
  return []
1114
1117
 
1118
+ coalesce_join_cols_str = ', '.join(
1119
+ [
1120
+ 'COALESCE('
1121
+ + sql_item_name(c_name, flavor)
1122
+ + ', '
1123
+ + get_null_replacement(c_type, flavor)
1124
+ + ')'
1125
+ for c_name, c_type in join_cols_types
1126
+ ]
1127
+ )
1128
+
1129
+ update_or_nothing = ('UPDATE' if value_cols else 'NOTHING')
1130
+
1115
1131
  def sets_subquery(l_prefix: str, r_prefix: str):
1132
+ if not value_cols:
1133
+ return ''
1116
1134
  return 'SET ' + ',\n'.join([
1117
1135
  (
1118
1136
  l_prefix + sql_item_name(c_name, flavor, None)
@@ -1169,6 +1187,8 @@ def get_update_queries(
1169
1187
  patch_cols_str = patch_cols_str,
1170
1188
  date_bounds_subquery = date_bounds_subquery,
1171
1189
  join_cols_str = join_cols_str,
1190
+ coalesce_join_cols_str = coalesce_join_cols_str,
1191
+ update_or_nothing = update_or_nothing,
1172
1192
  )
1173
1193
  for base_query in base_queries
1174
1194
  ]
@@ -87,3 +87,14 @@ PipesDict = Dict[
87
87
  ]
88
88
  ]
89
89
  WebState = Dict[str, str]
90
+
91
+ def is_success_tuple(x: Any) -> bool:
92
+ """
93
+ Determine whether an object is a `SuccessTuple`.
94
+ """
95
+ return (
96
+ isinstance(x, tuple)
97
+ and len(x) == 2
98
+ and isinstance(x[0], bool)
99
+ and isinstance(x[1], str)
100
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: meerschaum
3
- Version: 2.1.5
3
+ Version: 2.1.6
4
4
  Summary: Sync Time-Series Pipes with Meerschaum
5
5
  Home-page: https://meerschaum.io
6
6
  Author: Bennett Meares
@@ -43,7 +43,7 @@ meerschaum/actions/sql.py,sha256=wYofwk1vGO96U2ncigGEfMtYMZeprz2FR1PRRZhkAPI,431
43
43
  meerschaum/actions/stack.py,sha256=WMRMebyYwZGNlbnj6Ja09qvCSDNteFJOTa8_joHlnVo,5886
44
44
  meerschaum/actions/start.py,sha256=mNFWqxc_o9moavvDQWE4YoZF6b-SW2nKyw5MtwIj-90,18384
45
45
  meerschaum/actions/stop.py,sha256=KTBadAmJ6SbReqlltkwfqZW6EryB4kZXupl0ZyInI0Q,4311
46
- meerschaum/actions/sync.py,sha256=oMRZzT7q6eUs-7UrXcTpcem59EBwftu_6ug8XCen6dk,16235
46
+ meerschaum/actions/sync.py,sha256=Pzj0p53Aa4ZjP3SnlUyB6OeNvVUoJ0iCfWffMIIsd0k,17266
47
47
  meerschaum/actions/tag.py,sha256=SJf5qFW0ccLXjqlTdkK_0MCcrCMdg6xhYrhKdco0hdA,3053
48
48
  meerschaum/actions/uninstall.py,sha256=2fUd5ZK45VGGCI8V4NLmSnavdKjOv7cGM22x2WlTStw,6068
49
49
  meerschaum/actions/upgrade.py,sha256=VQKyjCGioEF2FYbQmldHh21imDqApNl0xal0rhxzrJk,6302
@@ -134,7 +134,7 @@ meerschaum/config/_preprocess.py,sha256=-AEA8m_--KivZwTQ1sWN6LTn5sio_fUr2XZ51BO6
134
134
  meerschaum/config/_read_config.py,sha256=WFZKIXZMDe_ca0ES7ivgM_mnwShvFxLdoeisT_X5-h0,14720
135
135
  meerschaum/config/_shell.py,sha256=k6PH0BEr2imhgURLYlR5p6s5gXfYpWoyZSV29U-SsXk,3589
136
136
  meerschaum/config/_sync.py,sha256=Q-sz5YcjL3CJS2Dyw4rVRQsz9th9GWa9o5F9D0Jrmn8,4120
137
- meerschaum/config/_version.py,sha256=5u15PU7pHH1p6K_hknjy0-rs4zQUg8VbND291EX5N4I,71
137
+ meerschaum/config/_version.py,sha256=4oiHJ97xK6U_82-kd6gX-Wu6OlnPt6kBWdvU0LDvhtc,71
138
138
  meerschaum/config/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
139
139
  meerschaum/config/stack/__init__.py,sha256=4a_up1oxkitwgIylWWk0vA4XkGhEpWazUaENOPEdYQI,9034
140
140
  meerschaum/config/stack/grafana/__init__.py,sha256=wzuoch_AK49lcn7lH2qTSJ_PPbSagF4lcweeipz_XiE,2010
@@ -165,20 +165,20 @@ meerschaum/connectors/sql/_cli.py,sha256=XaWjWZzGIfhMiYoXAs2FrwHUGNyZpxIzH4g4xug
165
165
  meerschaum/connectors/sql/_create_engine.py,sha256=PrHS5xCvqBMdCl0-AsoEw_9Dt2WrH3Wim5qKeTiLyp4,10382
166
166
  meerschaum/connectors/sql/_fetch.py,sha256=BLcZBGeE8JV6utnCgvq1TX_y6dTjX5KAvB4xm4YKxiQ,13210
167
167
  meerschaum/connectors/sql/_instance.py,sha256=jAGq_qjz2WyBrjtnI7FyGRLOs2l3o630vonPM5Pp4Mg,6447
168
- meerschaum/connectors/sql/_pipes.py,sha256=L6ldoFLhhE0ap1Yf2aETzRIBby5TbkIWUb2_-B3_4-k,99687
168
+ meerschaum/connectors/sql/_pipes.py,sha256=5XsaEfFRqMejwvRBRaWrAX2laplJMDRxA82-DqiKSGc,100773
169
169
  meerschaum/connectors/sql/_plugins.py,sha256=hS0cuJQxwd6jUfY136AQ33dGQw_MigP_OFC84KdSMhA,8323
170
170
  meerschaum/connectors/sql/_sql.py,sha256=jNdIcwQC2ZMNKT9W6ugavQPtimUpoTr8cBt05z_vHIo,34262
171
171
  meerschaum/connectors/sql/_uri.py,sha256=0BrhQtqQdzg9mR04gWBZINs_BbPFtSlTECXT_TCUwik,3460
172
172
  meerschaum/connectors/sql/_users.py,sha256=JkD6lKYJO8JVnpVySMqPM20NWUr-XzD_JO-lLMcAD_c,10100
173
173
  meerschaum/connectors/sql/tools.py,sha256=jz8huOaRCwGlYdtGfAqAh7SoK8uydYBrasKQba9FT38,187
174
- meerschaum/connectors/sql/tables/__init__.py,sha256=a4eFvbvGBoL4ZaTNzl6RV1Rj90LTeHFcPPT-j51pzFo,9471
174
+ meerschaum/connectors/sql/tables/__init__.py,sha256=e2dALTtThqbrq0soMNQ9QwgccyfTAjOrFkEClstLp3A,9001
175
175
  meerschaum/connectors/sql/tables/types.py,sha256=Jc_MTHIBM-KHpQt__Lckp39CeOo7tGOiAk5faDx-znY,1573
176
176
  meerschaum/core/__init__.py,sha256=tjASW10n9uLV6bYhcwP4rggh-ESXSJzgxpSBbVsuISs,251
177
177
  meerschaum/core/Pipe/__init__.py,sha256=1QOHqyUX2uJnfihVoGQV30BLm7JZZX2qjbsYIpCNFGI,16230
178
178
  meerschaum/core/Pipe/_attributes.py,sha256=XbSHfDsomaNymzf7-__UhbHqu6mlTTx20xprsw_L04I,13202
179
179
  meerschaum/core/Pipe/_bootstrap.py,sha256=sTbHUX8V0Kfn6vEErXzsVslSjQNfQ5MxXxxuRYslr4w,7613
180
180
  meerschaum/core/Pipe/_clear.py,sha256=hQVPztHiadzLB0c4_yFg6EETnf9MtFdJDCpO41Giuco,2261
181
- meerschaum/core/Pipe/_data.py,sha256=K4sZAPwBB8kb9mr5NqgQcCfgX1u-iYZ06uEPSJx5BqE,20783
181
+ meerschaum/core/Pipe/_data.py,sha256=uafKY7GGD5uGQ__-YcKlWOnRatAp1ExSbvz06LWPTsA,20880
182
182
  meerschaum/core/Pipe/_deduplicate.py,sha256=hXeNhz8p6Zgz2Y-A2W5AZPkVFUgsLqNvTQKKL0JHJ0A,10267
183
183
  meerschaum/core/Pipe/_delete.py,sha256=1geNp9BgrocXP1gt76dMbnlJWKYFMuSNqPFA4K4-hXE,2118
184
184
  meerschaum/core/Pipe/_drop.py,sha256=uf3MvMkCw9tVfJ2fuo8LqZ4vvMNa3xC3YoFGEuc-hH8,1052
@@ -205,9 +205,9 @@ meerschaum/utils/pool.py,sha256=vkE42af4fjrTEJTxf6Ek3xGucm1MtEkpsSEiaVzNKHs,2655
205
205
  meerschaum/utils/process.py,sha256=tbEutHAg_Kn5UetOI-fduRjsafGOYX5tkLvpzqosgvc,7098
206
206
  meerschaum/utils/prompt.py,sha256=0mBFbgi_l9rCou9UnC_6qKTHkqyl1Z_jSRzfmc0xRXM,16490
207
207
  meerschaum/utils/schedule.py,sha256=lYra4f7QpGlmV4vAhO1UvA5TWQSPdLqw7eG7ekKZtwg,1951
208
- meerschaum/utils/sql.py,sha256=mWGZO-JXmwfELSRyT7w3L6A-_HJ-k9aPwIgnMGj9Bqs,45982
208
+ meerschaum/utils/sql.py,sha256=4sCNEpgUd6uFz6ySs4nnUMVaOT0YAvPM1ZlQYJTSF-0,46656
209
209
  meerschaum/utils/threading.py,sha256=fAXk7-FnbFvdU1FQ4vHKk5NeGbbTpTw7y9dRnlVayNI,2472
210
- meerschaum/utils/typing.py,sha256=mCWZ7QN5Oub5QtWtdLp3gL_PPbpbdRhI2DJJkv_dpTA,2535
210
+ meerschaum/utils/typing.py,sha256=-g_LN1HzBdYZml7iZNSoB4EbpV27D0S0pM_PhuDSuzI,2784
211
211
  meerschaum/utils/warnings.py,sha256=0b5O2DBbhEAGnu6RAB1hlHSVmwL_hcR3EiMkExXmBJ0,6535
212
212
  meerschaum/utils/yaml.py,sha256=vbCrFjdapKsZ9wRRaI9Ih8dVUwZ-KHpSzfGhRcpDBgQ,3162
213
213
  meerschaum/utils/daemon/Daemon.py,sha256=_dxHUM4SEIvTin_k0xMIFjdXTDj97ZE1Do4A_AXcAHA,31961
@@ -226,11 +226,11 @@ meerschaum/utils/packages/_packages.py,sha256=gEWZHxFbYV6FZfM2uV1JOzS4eBl5OVoBZf
226
226
  meerschaum/utils/packages/lazy_loader.py,sha256=VHnph3VozH29R4JnSSBfwtA5WKZYZQFT_GeQSShCnuc,2540
227
227
  meerschaum/utils/venv/_Venv.py,sha256=sBnlmxHdAh2bx8btfVoD79-H9-cYsv5lP02IIXkyECs,3553
228
228
  meerschaum/utils/venv/__init__.py,sha256=sj-n8scWH2NPDJGAxfpqzsYqVUt2jMEr-7Uq9G7YUNQ,23183
229
- meerschaum-2.1.5.dist-info/LICENSE,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
230
- meerschaum-2.1.5.dist-info/METADATA,sha256=ig4PzucKdxot5IvSY8VeKrh54OVd7ZM8grPLZixLgiw,23976
231
- meerschaum-2.1.5.dist-info/NOTICE,sha256=OTA9Fcthjf5BRvWDDIcBC_xfLpeDV-RPZh3M-HQBRtQ,114
232
- meerschaum-2.1.5.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
233
- meerschaum-2.1.5.dist-info/entry_points.txt,sha256=5YBVzibw-0rNA_1VjB16z5GABsOGf-CDhW4yqH8C7Gc,88
234
- meerschaum-2.1.5.dist-info/top_level.txt,sha256=bNoSiDj0El6buocix-FRoAtJOeq1qOF5rRm2u9i7Q6A,11
235
- meerschaum-2.1.5.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
236
- meerschaum-2.1.5.dist-info/RECORD,,
229
+ meerschaum-2.1.6.dist-info/LICENSE,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
230
+ meerschaum-2.1.6.dist-info/METADATA,sha256=3D9pRJcEwjj7Z5FSkaBa2DTnoW0uzxi1xQ-ZzIHQ6II,23976
231
+ meerschaum-2.1.6.dist-info/NOTICE,sha256=OTA9Fcthjf5BRvWDDIcBC_xfLpeDV-RPZh3M-HQBRtQ,114
232
+ meerschaum-2.1.6.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
233
+ meerschaum-2.1.6.dist-info/entry_points.txt,sha256=5YBVzibw-0rNA_1VjB16z5GABsOGf-CDhW4yqH8C7Gc,88
234
+ meerschaum-2.1.6.dist-info/top_level.txt,sha256=bNoSiDj0El6buocix-FRoAtJOeq1qOF5rRm2u9i7Q6A,11
235
+ meerschaum-2.1.6.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
236
+ meerschaum-2.1.6.dist-info/RECORD,,