meerschaum 2.7.2__py3-none-any.whl → 2.7.3__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.
- meerschaum/_internal/arguments/_parse_arguments.py +2 -0
- meerschaum/_internal/arguments/_parser.py +17 -11
- meerschaum/actions/clear.py +1 -1
- meerschaum/actions/edit.py +1 -1
- meerschaum/actions/verify.py +18 -21
- meerschaum/config/_version.py +1 -1
- meerschaum/connectors/sql/_fetch.py +45 -26
- meerschaum/connectors/sql/_instance.py +4 -4
- meerschaum/connectors/sql/_pipes.py +135 -103
- meerschaum/core/Pipe/_attributes.py +1 -1
- meerschaum/core/Pipe/_dtypes.py +9 -9
- meerschaum/core/Pipe/_fetch.py +2 -3
- meerschaum/core/Pipe/_sync.py +11 -3
- meerschaum/core/Pipe/_verify.py +9 -5
- meerschaum/jobs/__init__.py +1 -1
- meerschaum/utils/dataframe.py +10 -2
- meerschaum/utils/dtypes/sql.py +1 -1
- meerschaum/utils/formatting/__init__.py +5 -25
- meerschaum/utils/formatting/_pipes.py +9 -6
- meerschaum/utils/sql.py +156 -87
- meerschaum/utils/venv/__init__.py +44 -6
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.3.dist-info}/METADATA +1 -1
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.3.dist-info}/RECORD +29 -29
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.3.dist-info}/LICENSE +0 -0
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.3.dist-info}/NOTICE +0 -0
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.3.dist-info}/WHEEL +0 -0
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.3.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.3.dist-info}/top_level.txt +0 -0
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.3.dist-info}/zip-safe +0 -0
@@ -240,6 +240,8 @@ def parse_synonyms(
|
|
240
240
|
args_dict['instance'] = args_dict['mrsm_instance']
|
241
241
|
if args_dict.get('skip_check_existing', None):
|
242
242
|
args_dict['check_existing'] = False
|
243
|
+
if args_dict.get('skip_enforce_dtypes', None):
|
244
|
+
args_dict['enforce_dtypes'] = False
|
243
245
|
if args_dict.get('venv', None) in ('None', '[None]'):
|
244
246
|
args_dict['venv'] = None
|
245
247
|
chunk_minutes = args_dict.get('chunk_minutes', None)
|
@@ -87,7 +87,7 @@ def parse_datetime(dt_str: str) -> Union[datetime, int, str]:
|
|
87
87
|
dt = round_time(dt, round_delta)
|
88
88
|
else:
|
89
89
|
dt = dateutil_parser.parse(dt_str)
|
90
|
-
except Exception
|
90
|
+
except Exception:
|
91
91
|
dt = None
|
92
92
|
if dt is None:
|
93
93
|
from meerschaum.utils.warnings import error
|
@@ -121,7 +121,7 @@ def parse_help(sysargs: Union[List[str], Dict[str, Any]]) -> None:
|
|
121
121
|
"""Parse the `--help` flag to determine which help message to print."""
|
122
122
|
from meerschaum._internal.arguments._parse_arguments import parse_arguments, parse_line
|
123
123
|
from meerschaum.actions import actions, get_subactions
|
124
|
-
import
|
124
|
+
import textwrap
|
125
125
|
from copy import deepcopy
|
126
126
|
if isinstance(sysargs, list):
|
127
127
|
args = parse_arguments(sysargs)
|
@@ -140,14 +140,14 @@ def parse_help(sysargs: Union[List[str], Dict[str, Any]]) -> None:
|
|
140
140
|
if len(args['action']) > 1:
|
141
141
|
try:
|
142
142
|
subaction = get_subactions(args['action'][0])[args['action'][1]]
|
143
|
-
except Exception
|
143
|
+
except Exception:
|
144
144
|
subaction = None
|
145
145
|
if subaction is not None:
|
146
146
|
return print(textwrap.dedent(subaction.__doc__))
|
147
147
|
|
148
148
|
try:
|
149
149
|
doc = actions[args['action'][0]].__doc__
|
150
|
-
except Exception
|
150
|
+
except Exception:
|
151
151
|
doc = None
|
152
152
|
if doc is None:
|
153
153
|
doc = "No help available for '" + f"{args['action'][0]}" + "'."
|
@@ -309,7 +309,7 @@ groups['sync'].add_argument(
|
|
309
309
|
)
|
310
310
|
groups['sync'].add_argument(
|
311
311
|
'--chunksize', type=int, help=(
|
312
|
-
"Specify the database chunksize. Defaults to
|
312
|
+
"Specify the database chunksize. Defaults to 100,000."
|
313
313
|
),
|
314
314
|
)
|
315
315
|
groups['sync'].add_argument(
|
@@ -336,19 +336,25 @@ groups['sync'].add_argument(
|
|
336
336
|
)
|
337
337
|
groups['sync'].add_argument(
|
338
338
|
'--bounded', '--bound', action="store_true",
|
339
|
-
help
|
339
|
+
help=(
|
340
340
|
"When verifying, do not sync outside "
|
341
|
-
|
341
|
+
"the existing oldest and newest datetime bounds."
|
342
342
|
)
|
343
343
|
)
|
344
344
|
groups['sync'].add_argument(
|
345
345
|
'--skip-check-existing', '--allow-duplicates', action='store_true',
|
346
|
-
help
|
347
|
-
"Skip checking for duplicate rows when syncing. "
|
348
|
-
"This
|
349
|
-
"For example, this setting is highly recommended for use with IoT devices."
|
346
|
+
help=(
|
347
|
+
"Skip checking for duplicate rows when syncing. "
|
348
|
+
"This improves performance when all rows to be synced are unique. "
|
350
349
|
)
|
351
350
|
)
|
351
|
+
groups['sync'].add_argument(
|
352
|
+
'--skip-enforce-dtypes', action='store_true',
|
353
|
+
help=(
|
354
|
+
"Skip enforcing incoming data to a pipe's dtypes. "
|
355
|
+
"This improves performance when all rows are expected to already be of the correct type."
|
356
|
+
),
|
357
|
+
)
|
352
358
|
groups['sync'].add_argument(
|
353
359
|
'--cache', action='store_true',
|
354
360
|
help = (
|
meerschaum/actions/clear.py
CHANGED
@@ -137,7 +137,7 @@ def _ask_with_rowcounts(
|
|
137
137
|
)
|
138
138
|
total_num_rows = sum([rc for p, rc in pipes_rowcounts.items()])
|
139
139
|
question = (
|
140
|
-
f"Are you sure you want to delete {total_num_rows} rows across {len(pipes)} pipe"
|
140
|
+
f"Are you sure you want to delete {total_num_rows:,} rows across {len(pipes)} pipe"
|
141
141
|
+ ('s' if len(pipes) != 1 else '')
|
142
142
|
+ " in the following range?\n"
|
143
143
|
)
|
meerschaum/actions/edit.py
CHANGED
meerschaum/actions/verify.py
CHANGED
@@ -10,9 +10,9 @@ from __future__ import annotations
|
|
10
10
|
from meerschaum.utils.typing import Union, Any, Sequence, SuccessTuple, Optional, Tuple, List
|
11
11
|
|
12
12
|
def verify(
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
action: Optional[List[str]] = None,
|
14
|
+
**kwargs: Any
|
15
|
+
) -> SuccessTuple:
|
16
16
|
"""
|
17
17
|
Verify the states of pipes, packages, and more.
|
18
18
|
"""
|
@@ -36,19 +36,17 @@ def _verify_pipes(**kwargs) -> SuccessTuple:
|
|
36
36
|
|
37
37
|
|
38
38
|
def _verify_packages(
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
debug: bool = False,
|
40
|
+
venv: Optional[str] = 'mrsm',
|
41
|
+
**kw
|
42
|
+
) -> SuccessTuple:
|
43
43
|
"""
|
44
44
|
Verify the versions of packages.
|
45
45
|
"""
|
46
46
|
from meerschaum.utils.packages import (
|
47
|
-
attempt_import,
|
47
|
+
attempt_import, all_packages, is_installed, venv_contains_package,
|
48
48
|
_monkey_patch_get_distribution, manually_import_module,
|
49
49
|
)
|
50
|
-
from meerschaum.utils.formatting import pprint
|
51
|
-
from meerschaum.utils.debug import dprint
|
52
50
|
|
53
51
|
venv_packages, base_packages, miss_packages = [], [], []
|
54
52
|
|
@@ -80,10 +78,10 @@ def _verify_packages(
|
|
80
78
|
|
81
79
|
|
82
80
|
def _verify_venvs(
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
81
|
+
action: Optional[List[str]],
|
82
|
+
debug: bool = False,
|
83
|
+
**kw
|
84
|
+
) -> SuccessTuple:
|
87
85
|
"""
|
88
86
|
Verify your virtual environments.
|
89
87
|
"""
|
@@ -94,15 +92,14 @@ def _verify_venvs(
|
|
94
92
|
|
95
93
|
|
96
94
|
def _verify_plugins(
|
97
|
-
|
98
|
-
|
99
|
-
|
95
|
+
action: Optional[List[str]] = None,
|
96
|
+
**kwargs: Any
|
97
|
+
) -> SuccessTuple:
|
100
98
|
"""
|
101
99
|
Verify that all of the available plugins are able to be imported as expected.
|
102
100
|
"""
|
103
|
-
from meerschaum.utils.formatting import print_options,
|
104
|
-
from meerschaum.plugins import
|
105
|
-
from meerschaum.config import get_config
|
101
|
+
from meerschaum.utils.formatting import print_options, print_tuple
|
102
|
+
from meerschaum.plugins import get_plugins_names, Plugin
|
106
103
|
from meerschaum.utils.misc import items_str
|
107
104
|
|
108
105
|
plugins_names_to_verify = action or get_plugins_names()
|
@@ -135,7 +132,7 @@ def _verify_plugins(
|
|
135
132
|
f"Successfully imported {len(plugins_names_to_verify)} plugins."
|
136
133
|
if success
|
137
134
|
else (
|
138
|
-
|
135
|
+
"Failed to import plugin"
|
139
136
|
+ ('s' if len(failed_to_import) != 1 else '')
|
140
137
|
+ f" {items_str(failed_to_import)}."
|
141
138
|
)
|
meerschaum/config/_version.py
CHANGED
@@ -9,6 +9,7 @@ Implement the Connector fetch() method
|
|
9
9
|
from __future__ import annotations
|
10
10
|
|
11
11
|
from datetime import datetime, timedelta
|
12
|
+
|
12
13
|
import meerschaum as mrsm
|
13
14
|
from meerschaum.utils.typing import Optional, Union, Callable, Any, List, Dict
|
14
15
|
|
@@ -144,37 +145,37 @@ def get_pipe_metadef(
|
|
144
145
|
-------
|
145
146
|
A pipe's meta definition fetch query string.
|
146
147
|
"""
|
147
|
-
from meerschaum.utils.
|
148
|
-
from meerschaum.utils.warnings import warn, error
|
148
|
+
from meerschaum.utils.warnings import warn
|
149
149
|
from meerschaum.utils.sql import sql_item_name, dateadd_str, build_where
|
150
|
+
from meerschaum.utils.dtypes.sql import get_db_type_from_pd_type
|
150
151
|
from meerschaum.utils.misc import is_int
|
151
152
|
from meerschaum.config import get_config
|
152
153
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
dt_name = sql_item_name(_dt, self.flavor, None) if _dt else None
|
154
|
+
dt_col = pipe.columns.get('datetime', None)
|
155
|
+
if not dt_col:
|
156
|
+
dt_col = pipe.guess_datetime()
|
157
|
+
dt_name = sql_item_name(dt_col, self.flavor, None) if dt_col else None
|
158
158
|
is_guess = True
|
159
159
|
else:
|
160
|
-
|
161
|
-
dt_name = sql_item_name(_dt, self.flavor, None)
|
160
|
+
dt_name = sql_item_name(dt_col, self.flavor, None)
|
162
161
|
is_guess = False
|
162
|
+
dt_typ = pipe.dtypes.get(dt_col, 'datetime') if dt_col else None
|
163
|
+
db_dt_typ = get_db_type_from_pd_type(dt_typ, self.flavor) if dt_typ else None
|
163
164
|
|
164
165
|
if begin not in (None, '') or end is not None:
|
165
166
|
if is_guess:
|
166
|
-
if
|
167
|
+
if dt_col is None:
|
167
168
|
warn(
|
168
169
|
f"Unable to determine a datetime column for {pipe}."
|
169
170
|
+ "\n Ignoring begin and end...",
|
170
|
-
stack
|
171
|
+
stack=False,
|
171
172
|
)
|
172
173
|
begin, end = '', None
|
173
174
|
else:
|
174
175
|
warn(
|
175
176
|
f"A datetime wasn't specified for {pipe}.\n"
|
176
|
-
+ f" Using column \"{
|
177
|
-
stack
|
177
|
+
+ f" Using column \"{dt_col}\" for datetime bounds...",
|
178
|
+
stack=False
|
178
179
|
)
|
179
180
|
|
180
181
|
apply_backtrack = begin == '' and check_existing
|
@@ -200,6 +201,7 @@ def get_pipe_metadef(
|
|
200
201
|
datepart='minute',
|
201
202
|
number=((-1 * btm) if apply_backtrack else 0),
|
202
203
|
begin=begin,
|
204
|
+
db_type=db_dt_typ,
|
203
205
|
)
|
204
206
|
if begin
|
205
207
|
else None
|
@@ -210,11 +212,13 @@ def get_pipe_metadef(
|
|
210
212
|
datepart='minute',
|
211
213
|
number=0,
|
212
214
|
begin=end,
|
215
|
+
db_type=db_dt_typ,
|
213
216
|
)
|
214
217
|
if end
|
215
218
|
else None
|
216
219
|
)
|
217
220
|
|
221
|
+
definition_name = sql_item_name('definition', self.flavor, None)
|
218
222
|
meta_def = (
|
219
223
|
_simple_fetch_query(pipe, self.flavor) if (
|
220
224
|
(not (pipe.columns or {}).get('id', None))
|
@@ -225,26 +229,26 @@ def get_pipe_metadef(
|
|
225
229
|
has_where = 'where' in meta_def.lower()[meta_def.lower().rfind('definition'):]
|
226
230
|
if dt_name and (begin_da or end_da):
|
227
231
|
definition_dt_name = (
|
228
|
-
dateadd_str(self.flavor, 'minute', 0, f"
|
232
|
+
dateadd_str(self.flavor, 'minute', 0, f"{definition_name}.{dt_name}", db_type=db_dt_typ)
|
229
233
|
if not is_int((begin_da or end_da))
|
230
|
-
else f"
|
234
|
+
else f"{definition_name}.{dt_name}"
|
231
235
|
)
|
232
236
|
meta_def += "\n" + ("AND" if has_where else "WHERE") + " "
|
233
237
|
has_where = True
|
234
238
|
if begin_da:
|
235
|
-
meta_def += f"{definition_dt_name}
|
239
|
+
meta_def += f"\n {definition_dt_name}\n >=\n {begin_da}\n"
|
236
240
|
if begin_da and end_da:
|
237
|
-
meta_def += "
|
241
|
+
meta_def += " AND"
|
238
242
|
if end_da:
|
239
|
-
meta_def += f"{definition_dt_name}
|
243
|
+
meta_def += f"\n {definition_dt_name}\n <\n {end_da}\n"
|
240
244
|
|
241
245
|
if params is not None:
|
242
246
|
params_where = build_where(params, self, with_where=False)
|
243
|
-
meta_def += "\n" + ("AND" if has_where else "WHERE") + "
|
247
|
+
meta_def += "\n " + ("AND" if has_where else "WHERE") + " "
|
244
248
|
has_where = True
|
245
249
|
meta_def += params_where
|
246
250
|
|
247
|
-
return meta_def
|
251
|
+
return meta_def.rstrip()
|
248
252
|
|
249
253
|
|
250
254
|
def get_pipe_query(pipe: mrsm.Pipe, warn: bool = True) -> Union[str, None]:
|
@@ -256,7 +260,11 @@ def get_pipe_query(pipe: mrsm.Pipe, warn: bool = True) -> Union[str, None]:
|
|
256
260
|
- query
|
257
261
|
- sql
|
258
262
|
"""
|
263
|
+
import re
|
264
|
+
import textwrap
|
259
265
|
from meerschaum.utils.warnings import warn as _warn
|
266
|
+
from meerschaum.utils.misc import parse_arguments_str
|
267
|
+
from meerschaum.utils.sql import sql_item_name
|
260
268
|
if pipe.parameters.get('fetch', {}).get('definition', None):
|
261
269
|
definition = pipe.parameters['fetch']['definition']
|
262
270
|
elif pipe.parameters.get('definition', None):
|
@@ -272,7 +280,23 @@ def get_pipe_query(pipe: mrsm.Pipe, warn: bool = True) -> Union[str, None]:
|
|
272
280
|
+ " Set the key `query` in `pipe.parameters` to a valid SQL query."
|
273
281
|
)
|
274
282
|
return None
|
275
|
-
|
283
|
+
|
284
|
+
def replace_pipe_match(pipe_match):
|
285
|
+
try:
|
286
|
+
args_str = pipe_match.group(1)
|
287
|
+
args, kwargs = parse_arguments_str(args_str)
|
288
|
+
pipe = mrsm.Pipe(*args, **kwargs)
|
289
|
+
except Exception as e:
|
290
|
+
if warn:
|
291
|
+
_warn(f"Failed to parse pipe from SQL definition:\n{e}")
|
292
|
+
raise e
|
293
|
+
|
294
|
+
target = pipe.target
|
295
|
+
schema = pipe.instance_connector.get_pipe_schema(pipe)
|
296
|
+
return sql_item_name(target, pipe.instance_connector.flavor, schema)
|
297
|
+
|
298
|
+
definition = re.sub(r'\{\{Pipe\((.*?)\)\}\}', replace_pipe_match, definition)
|
299
|
+
return textwrap.dedent(definition.lstrip().rstrip())
|
276
300
|
|
277
301
|
|
278
302
|
def set_pipe_query(pipe: mrsm.Pipe, query: str) -> None:
|
@@ -331,11 +355,7 @@ def _join_fetch_query(
|
|
331
355
|
pipe_instance_name = sql_item_name(
|
332
356
|
pipe.target, pipe.instance_connector.flavor, pipe.instance_connector.schema
|
333
357
|
)
|
334
|
-
# pipe_remote_name = sql_item_name(pipe.target, pipe.connector.flavor)
|
335
358
|
sync_times_table = pipe.target + "_sync_times"
|
336
|
-
sync_times_instance_name = sql_item_name(
|
337
|
-
sync_times_table, pipe.instance_connector.flavor, None
|
338
|
-
)
|
339
359
|
sync_times_remote_name = sql_item_name(
|
340
360
|
sync_times_table, pipe.connector.flavor, None
|
341
361
|
)
|
@@ -393,4 +413,3 @@ def _join_fetch_query(
|
|
393
413
|
WHERE definition.{dt_remote_name} > st.{dt_remote_name}
|
394
414
|
""" + (f" OR st.{id_remote_name} IS NULL" if new_ids else "")
|
395
415
|
return query
|
396
|
-
|
@@ -96,15 +96,15 @@ def _drop_temporary_tables(self, debug: bool = False) -> SuccessTuple:
|
|
96
96
|
sqlalchemy.select(temp_tables_table.c.table)
|
97
97
|
.where(temp_tables_table.c.ready_to_drop.is_not(None))
|
98
98
|
)
|
99
|
-
tables_to_drop =
|
99
|
+
tables_to_drop = {
|
100
100
|
table
|
101
101
|
for table, ready_to_drop in _in_memory_temp_tables.items()
|
102
102
|
if ready_to_drop
|
103
|
-
|
103
|
+
}
|
104
104
|
if not tables_to_drop:
|
105
105
|
df = self.read(query, silent=True, debug=debug)
|
106
106
|
tables_to_drop = (
|
107
|
-
|
107
|
+
set(df['table'])
|
108
108
|
if df is not None
|
109
109
|
else []
|
110
110
|
)
|
@@ -126,7 +126,7 @@ def _drop_temporary_tables(self, debug: bool = False) -> SuccessTuple:
|
|
126
126
|
sqlalchemy.delete(temp_tables_table)
|
127
127
|
.where(temp_tables_table.c.table.in_(dropped_tables))
|
128
128
|
)
|
129
|
-
|
129
|
+
_ = self.exec(delete_query, silent=True, debug=debug)
|
130
130
|
|
131
131
|
success = len(failed_tables) == 0
|
132
132
|
msg = (
|