meerschaum 3.0.0rc2__py3-none-any.whl → 3.0.0rc4__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/shell/Shell.py +5 -4
- meerschaum/actions/bootstrap.py +1 -1
- meerschaum/actions/edit.py +6 -3
- meerschaum/actions/start.py +1 -1
- meerschaum/api/_events.py +5 -0
- meerschaum/api/dash/callbacks/__init__.py +1 -0
- meerschaum/api/dash/callbacks/dashboard.py +93 -115
- meerschaum/api/dash/callbacks/jobs.py +11 -5
- meerschaum/api/dash/callbacks/pipes.py +194 -14
- meerschaum/api/dash/callbacks/settings/__init__.py +0 -1
- meerschaum/api/dash/callbacks/{settings/tokens.py → tokens.py} +3 -2
- meerschaum/api/dash/components.py +6 -7
- meerschaum/api/dash/jobs.py +1 -1
- meerschaum/api/dash/keys.py +17 -1
- meerschaum/api/dash/pages/__init__.py +2 -1
- meerschaum/api/dash/pages/{job.py → jobs.py} +10 -7
- meerschaum/api/dash/pages/pipes.py +16 -5
- meerschaum/api/dash/pages/settings/__init__.py +0 -1
- meerschaum/api/dash/pages/{settings/tokens.py → tokens.py} +6 -8
- meerschaum/api/dash/pipes.py +219 -3
- meerschaum/api/dash/tokens.py +27 -30
- meerschaum/config/_default.py +5 -4
- meerschaum/config/_paths.py +1 -0
- meerschaum/config/_version.py +1 -1
- meerschaum/connectors/instance/_tokens.py +6 -2
- meerschaum/connectors/sql/_SQLConnector.py +14 -0
- meerschaum/connectors/sql/_pipes.py +63 -23
- meerschaum/connectors/sql/tables/__init__.py +254 -122
- meerschaum/core/Pipe/__init__.py +17 -1
- meerschaum/core/Pipe/_attributes.py +5 -2
- meerschaum/core/Token/_Token.py +1 -1
- meerschaum/plugins/bootstrap.py +508 -3
- meerschaum/utils/_get_pipes.py +31 -5
- meerschaum/utils/dataframe.py +8 -2
- meerschaum/utils/dtypes/__init__.py +2 -3
- meerschaum/utils/dtypes/sql.py +11 -11
- meerschaum/utils/formatting/_pprint.py +1 -0
- meerschaum/utils/pipes.py +6 -2
- meerschaum/utils/sql.py +1 -1
- {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/METADATA +1 -1
- {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/RECORD +47 -47
- {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/WHEEL +0 -0
- {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/entry_points.txt +0 -0
- {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/licenses/LICENSE +0 -0
- {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/licenses/NOTICE +0 -0
- {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/top_level.txt +0 -0
- {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/zip-safe +0 -0
@@ -7,19 +7,25 @@ Define SQLAlchemy tables
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
+
|
11
|
+
import pickle
|
12
|
+
import threading
|
13
|
+
import meerschaum as mrsm
|
10
14
|
from meerschaum.utils.typing import Optional, Dict, Union, InstanceConnector, List
|
11
|
-
from meerschaum.utils.warnings import error, warn
|
15
|
+
from meerschaum.utils.warnings import error, warn, dprint
|
12
16
|
|
13
17
|
### store a tables dict for each connector
|
14
18
|
connector_tables = {}
|
19
|
+
_tables_locks = {}
|
15
20
|
|
16
21
|
_sequence_flavors = {'duckdb', 'oracle'}
|
17
22
|
_skip_index_names_flavors = {'mssql',}
|
18
23
|
|
19
24
|
def get_tables(
|
20
25
|
mrsm_instance: Optional[Union[str, InstanceConnector]] = None,
|
21
|
-
create: bool =
|
22
|
-
|
26
|
+
create: Optional[bool] = None,
|
27
|
+
refresh: bool = False,
|
28
|
+
debug: bool = False,
|
23
29
|
) -> Union[Dict[str, 'sqlalchemy.Table'], bool]:
|
24
30
|
"""
|
25
31
|
Create tables on the database and return the `sqlalchemy` tables.
|
@@ -29,10 +35,13 @@ def get_tables(
|
|
29
35
|
mrsm_instance: Optional[Union[str, InstanceConnector]], default None
|
30
36
|
The connector on which the tables reside.
|
31
37
|
|
32
|
-
create: bool, default
|
38
|
+
create: Optional[bool], default None
|
33
39
|
If `True`, create the tables if they don't exist.
|
34
40
|
|
35
|
-
|
41
|
+
refresh: bool, default False
|
42
|
+
If `True`, invalidate and rebuild any cache.
|
43
|
+
|
44
|
+
debug: bool, default False
|
36
45
|
Verbosity Toggle.
|
37
46
|
|
38
47
|
Returns
|
@@ -42,7 +51,6 @@ def get_tables(
|
|
42
51
|
|
43
52
|
"""
|
44
53
|
from meerschaum.utils.debug import dprint
|
45
|
-
from meerschaum.utils.formatting import pprint
|
46
54
|
from meerschaum.connectors.parse import parse_instance_keys
|
47
55
|
from meerschaum.utils.packages import attempt_import
|
48
56
|
from meerschaum.utils.sql import json_flavors
|
@@ -54,7 +62,7 @@ def get_tables(
|
|
54
62
|
lazy=False,
|
55
63
|
)
|
56
64
|
if not sqlalchemy:
|
57
|
-
error(
|
65
|
+
error("Failed to import sqlalchemy. Is sqlalchemy installed?")
|
58
66
|
|
59
67
|
if mrsm_instance is None:
|
60
68
|
conn = get_connector(debug=debug)
|
@@ -63,149 +71,209 @@ def get_tables(
|
|
63
71
|
else: ### NOTE: mrsm_instance MUST BE a SQL Connector for this to work!
|
64
72
|
conn = mrsm_instance
|
65
73
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
74
|
+
cache_expired = refresh or (
|
75
|
+
(
|
76
|
+
_check_create_cache(conn, debug=debug)
|
77
|
+
if conn.flavor != 'sqlite'
|
78
|
+
else True
|
79
|
+
)
|
80
|
+
if conn.type == 'sql'
|
81
|
+
else False
|
82
|
+
)
|
83
|
+
create = create or cache_expired
|
72
84
|
|
73
85
|
### Skip if the connector is not a SQL connector.
|
74
86
|
if getattr(conn, 'type', None) != 'sql':
|
75
87
|
return {}
|
76
88
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
89
|
+
conn_key = str(conn)
|
90
|
+
|
91
|
+
if refresh:
|
92
|
+
_ = connector_tables.pop(conn_key, None)
|
93
|
+
|
94
|
+
if conn_key in connector_tables:
|
95
|
+
return connector_tables[conn_key]
|
96
|
+
|
97
|
+
fasteners = attempt_import('fasteners')
|
98
|
+
pickle_path = conn.get_metadata_cache_path(kind='pkl')
|
99
|
+
lock_path = pickle_path.with_suffix('.lock')
|
100
|
+
lock = fasteners.InterProcessLock(lock_path)
|
101
|
+
|
102
|
+
with lock:
|
103
|
+
if not cache_expired and pickle_path.exists():
|
104
|
+
try:
|
105
|
+
with open(pickle_path, 'rb') as f:
|
106
|
+
metadata = pickle.load(f)
|
107
|
+
metadata.bind = conn.engine
|
108
|
+
tables = {tbl.name.replace('mrsm_', ''): tbl for tbl in metadata.tables.values()}
|
109
|
+
connector_tables[conn_key] = tables
|
110
|
+
return tables
|
111
|
+
except Exception as e:
|
112
|
+
warn(f"Failed to load metadata from cache, rebuilding: {e}")
|
113
|
+
|
114
|
+
if conn_key not in _tables_locks:
|
115
|
+
_tables_locks[conn_key] = threading.Lock()
|
116
|
+
|
117
|
+
with _tables_locks[conn_key]:
|
118
|
+
if conn_key not in connector_tables:
|
119
|
+
if debug:
|
120
|
+
dprint(f"Building in-memory instance tables for '{conn}'.")
|
121
|
+
|
122
|
+
id_type = sqlalchemy.Integer
|
123
|
+
if conn.flavor in json_flavors:
|
124
|
+
from sqlalchemy.dialects.postgresql import JSONB
|
125
|
+
params_type = JSONB
|
126
|
+
else:
|
127
|
+
params_type = sqlalchemy.types.Text
|
128
|
+
id_names = ('user_id', 'plugin_id', 'pipe_id')
|
129
|
+
sequences = {
|
130
|
+
k: sqlalchemy.Sequence(k + '_seq')
|
131
|
+
for k in id_names
|
132
|
+
}
|
133
|
+
id_col_args = { k: [k, id_type] for k in id_names }
|
134
|
+
id_col_kw = { k: {'primary_key': True} for k in id_names }
|
135
|
+
index_names = conn.flavor not in _skip_index_names_flavors
|
136
|
+
|
137
|
+
if conn.flavor in _sequence_flavors:
|
138
|
+
for k, args in id_col_args.items():
|
139
|
+
args.append(sequences[k])
|
140
|
+
for k, kw in id_col_kw.items():
|
141
|
+
kw.update({'server_default': sequences[k].next_value()})
|
142
|
+
|
143
|
+
_tables = {
|
144
|
+
'users': sqlalchemy.Table(
|
145
|
+
'mrsm_users',
|
146
|
+
conn.metadata,
|
147
|
+
sqlalchemy.Column(
|
148
|
+
*id_col_args['user_id'],
|
149
|
+
**id_col_kw['user_id'],
|
150
|
+
),
|
151
|
+
sqlalchemy.Column(
|
152
|
+
'username',
|
153
|
+
sqlalchemy.String(256),
|
154
|
+
index = index_names,
|
155
|
+
nullable = False,
|
156
|
+
),
|
157
|
+
sqlalchemy.Column('password_hash', sqlalchemy.String(1024)),
|
158
|
+
sqlalchemy.Column('email', sqlalchemy.String(256)),
|
159
|
+
sqlalchemy.Column('user_type', sqlalchemy.String(256)),
|
160
|
+
sqlalchemy.Column('attributes', params_type),
|
161
|
+
extend_existing = True,
|
108
162
|
),
|
109
|
-
sqlalchemy.
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
163
|
+
'plugins': sqlalchemy.Table(
|
164
|
+
*([
|
165
|
+
'mrsm_plugins',
|
166
|
+
conn.metadata,
|
167
|
+
sqlalchemy.Column(
|
168
|
+
*id_col_args['plugin_id'],
|
169
|
+
**id_col_kw['plugin_id'],
|
170
|
+
),
|
171
|
+
sqlalchemy.Column(
|
172
|
+
'plugin_name', sqlalchemy.String(256), index=index_names, nullable=False,
|
173
|
+
),
|
174
|
+
sqlalchemy.Column('user_id', sqlalchemy.Integer, nullable=False),
|
175
|
+
sqlalchemy.Column('version', sqlalchemy.String(256)),
|
176
|
+
sqlalchemy.Column('attributes', params_type),
|
177
|
+
] + ([
|
178
|
+
sqlalchemy.ForeignKeyConstraint(['user_id'], ['mrsm_users.user_id']),
|
179
|
+
] if conn.flavor != 'duckdb' else [])),
|
180
|
+
extend_existing = True,
|
114
181
|
),
|
115
|
-
|
116
|
-
|
117
|
-
sqlalchemy.Column('user_type', sqlalchemy.String(256)),
|
118
|
-
sqlalchemy.Column('attributes', params_type),
|
119
|
-
extend_existing = True,
|
120
|
-
),
|
121
|
-
'plugins': sqlalchemy.Table(
|
122
|
-
*([
|
123
|
-
'mrsm_plugins',
|
182
|
+
'temp_tables': sqlalchemy.Table(
|
183
|
+
'mrsm_temp_tables',
|
124
184
|
conn.metadata,
|
125
185
|
sqlalchemy.Column(
|
126
|
-
|
127
|
-
|
186
|
+
'date_created',
|
187
|
+
sqlalchemy.DateTime,
|
188
|
+
index = True,
|
189
|
+
nullable = False,
|
128
190
|
),
|
129
191
|
sqlalchemy.Column(
|
130
|
-
'
|
192
|
+
'table',
|
193
|
+
sqlalchemy.String(256),
|
194
|
+
index = index_names,
|
195
|
+
nullable = False,
|
131
196
|
),
|
132
|
-
sqlalchemy.Column(
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
197
|
+
sqlalchemy.Column(
|
198
|
+
'ready_to_drop',
|
199
|
+
sqlalchemy.DateTime,
|
200
|
+
index = False,
|
201
|
+
nullable = True,
|
202
|
+
),
|
203
|
+
extend_existing = True,
|
204
|
+
),
|
205
|
+
}
|
206
|
+
|
207
|
+
pipes_parameters_col = sqlalchemy.Column("parameters", params_type)
|
208
|
+
pipes_table_args = [
|
209
|
+
"mrsm_pipes",
|
142
210
|
conn.metadata,
|
143
211
|
sqlalchemy.Column(
|
144
|
-
'
|
145
|
-
|
146
|
-
|
212
|
+
*id_col_args['pipe_id'],
|
213
|
+
**id_col_kw['pipe_id'],
|
214
|
+
),
|
215
|
+
sqlalchemy.Column(
|
216
|
+
"connector_keys",
|
217
|
+
sqlalchemy.String(256),
|
218
|
+
index = index_names,
|
147
219
|
nullable = False,
|
148
220
|
),
|
149
221
|
sqlalchemy.Column(
|
150
|
-
|
222
|
+
"metric_key",
|
151
223
|
sqlalchemy.String(256),
|
152
224
|
index = index_names,
|
153
225
|
nullable = False,
|
154
226
|
),
|
155
227
|
sqlalchemy.Column(
|
156
|
-
|
157
|
-
sqlalchemy.
|
158
|
-
index =
|
228
|
+
"location_key",
|
229
|
+
sqlalchemy.String(256),
|
230
|
+
index = index_names,
|
159
231
|
nullable = True,
|
160
232
|
),
|
233
|
+
pipes_parameters_col,
|
234
|
+
]
|
235
|
+
if conn.flavor in json_flavors:
|
236
|
+
pipes_table_args.append(
|
237
|
+
sqlalchemy.Index(
|
238
|
+
'ix_mrsm_pipes_parameters_tags',
|
239
|
+
pipes_parameters_col['tags'],
|
240
|
+
postgresql_using='gin'
|
241
|
+
)
|
242
|
+
)
|
243
|
+
_tables['pipes'] = sqlalchemy.Table(
|
244
|
+
*pipes_table_args,
|
161
245
|
extend_existing = True,
|
162
|
-
),
|
163
|
-
}
|
164
|
-
|
165
|
-
_tables['pipes'] = sqlalchemy.Table(
|
166
|
-
"mrsm_pipes",
|
167
|
-
conn.metadata,
|
168
|
-
sqlalchemy.Column(
|
169
|
-
*id_col_args['pipe_id'],
|
170
|
-
**id_col_kw['pipe_id'],
|
171
|
-
),
|
172
|
-
sqlalchemy.Column(
|
173
|
-
"connector_keys",
|
174
|
-
sqlalchemy.String(256),
|
175
|
-
index = index_names,
|
176
|
-
nullable = False,
|
177
|
-
),
|
178
|
-
sqlalchemy.Column(
|
179
|
-
"metric_key",
|
180
|
-
sqlalchemy.String(256),
|
181
|
-
index = index_names,
|
182
|
-
nullable = False,
|
183
|
-
),
|
184
|
-
sqlalchemy.Column(
|
185
|
-
"location_key",
|
186
|
-
sqlalchemy.String(256),
|
187
|
-
index = index_names,
|
188
|
-
nullable = True,
|
189
|
-
),
|
190
|
-
sqlalchemy.Column("parameters", params_type),
|
191
|
-
extend_existing = True,
|
192
|
-
)
|
193
|
-
|
194
|
-
### store the table dict for reuse (per connector)
|
195
|
-
connector_tables[conn] = _tables
|
196
|
-
if create:
|
197
|
-
create_schemas(
|
198
|
-
conn,
|
199
|
-
schemas = [conn.internal_schema],
|
200
|
-
debug = debug,
|
201
246
|
)
|
202
|
-
create_tables(conn, tables=_tables)
|
203
247
|
|
204
|
-
|
248
|
+
### store the table dict for reuse (per connector)
|
249
|
+
connector_tables[conn_key] = _tables
|
250
|
+
|
251
|
+
if debug:
|
252
|
+
dprint(f"Built in-memory tables for '{conn}'.")
|
253
|
+
|
254
|
+
if create:
|
255
|
+
if debug:
|
256
|
+
dprint(f"Creating tables for connector '{conn}'.")
|
257
|
+
|
258
|
+
create_schemas(
|
259
|
+
conn,
|
260
|
+
schemas = [conn.internal_schema],
|
261
|
+
debug = debug,
|
262
|
+
)
|
263
|
+
create_tables(conn, tables=_tables)
|
264
|
+
|
265
|
+
_write_create_cache(mrsm.get_connector(str(mrsm_instance)), debug=debug)
|
266
|
+
|
267
|
+
if conn.flavor != 'sqlite':
|
268
|
+
with open(pickle_path, 'wb') as f:
|
269
|
+
pickle.dump(conn.metadata, f)
|
270
|
+
|
271
|
+
connector_tables[conn_key] = _tables
|
272
|
+
return connector_tables[conn_key]
|
205
273
|
|
206
274
|
|
207
275
|
def create_tables(
|
208
|
-
conn:
|
276
|
+
conn: mrsm.connectors.SQLConnector,
|
209
277
|
tables: Optional[Dict[str, 'sqlalchemy.Table']] = None,
|
210
278
|
) -> bool:
|
211
279
|
"""
|
@@ -224,14 +292,13 @@ def create_tables(
|
|
224
292
|
|
225
293
|
|
226
294
|
def create_schemas(
|
227
|
-
conn:
|
295
|
+
conn: mrsm.connectors.SQLConnector,
|
228
296
|
schemas: List[str],
|
229
297
|
debug: bool = False,
|
230
298
|
) -> bool:
|
231
299
|
"""
|
232
300
|
Create the internal Meerschaum schema on the database.
|
233
301
|
"""
|
234
|
-
from meerschaum._internal.static import STATIC_CONFIG
|
235
302
|
from meerschaum.utils.packages import attempt_import
|
236
303
|
from meerschaum.utils.sql import sql_item_name, NO_SCHEMA_FLAVORS, SKIP_IF_EXISTS_FLAVORS
|
237
304
|
if conn.flavor in NO_SCHEMA_FLAVORS:
|
@@ -257,3 +324,68 @@ def create_schemas(
|
|
257
324
|
except Exception as e:
|
258
325
|
warn(f"Failed to create internal schema '{schema}':\n{e}")
|
259
326
|
return all(successes.values())
|
327
|
+
|
328
|
+
|
329
|
+
def _check_create_cache(connector: mrsm.connectors.SQLConnector, debug: bool = False) -> bool:
|
330
|
+
"""
|
331
|
+
Return `True` if the metadata cache is missing or expired.
|
332
|
+
"""
|
333
|
+
import json
|
334
|
+
from datetime import datetime, timedelta
|
335
|
+
from meerschaum.utils.dtypes import get_current_timestamp
|
336
|
+
|
337
|
+
if connector.type != 'sql':
|
338
|
+
return False
|
339
|
+
|
340
|
+
path = connector.get_metadata_cache_path()
|
341
|
+
if not path.exists():
|
342
|
+
if debug:
|
343
|
+
dprint(f"Metadata cache doesn't exist for '{connector}'.")
|
344
|
+
return True
|
345
|
+
|
346
|
+
try:
|
347
|
+
with open(path, 'r', encoding='utf-8') as f:
|
348
|
+
metadata = json.load(f)
|
349
|
+
except Exception:
|
350
|
+
return True
|
351
|
+
|
352
|
+
created_str = metadata.get('created', None)
|
353
|
+
if not created_str:
|
354
|
+
return True
|
355
|
+
|
356
|
+
now = get_current_timestamp()
|
357
|
+
created = datetime.fromisoformat(created_str)
|
358
|
+
|
359
|
+
delta = now - created
|
360
|
+
threshold_minutes = (
|
361
|
+
mrsm.get_config('system', 'connectors', 'sql', 'instance', 'create_metadata_cache_minutes')
|
362
|
+
)
|
363
|
+
threshold_delta = timedelta(minutes=threshold_minutes)
|
364
|
+
if delta >= threshold_delta:
|
365
|
+
if debug:
|
366
|
+
dprint(f"Metadata cache expired for '{connector}'.")
|
367
|
+
return True
|
368
|
+
|
369
|
+
if debug:
|
370
|
+
dprint(f"Using cached metadata for '{connector}'.")
|
371
|
+
|
372
|
+
return False
|
373
|
+
|
374
|
+
|
375
|
+
def _write_create_cache(connector: mrsm.connectors.SQLConnector, debug: bool = False):
|
376
|
+
"""
|
377
|
+
Write the current timestamp to the cache file.
|
378
|
+
"""
|
379
|
+
if connector.type != 'sql':
|
380
|
+
return
|
381
|
+
|
382
|
+
import json
|
383
|
+
from meerschaum.utils.dtypes import get_current_timestamp, json_serialize_value
|
384
|
+
|
385
|
+
if debug:
|
386
|
+
dprint(f"Writing metadata cache for '{connector}'.")
|
387
|
+
|
388
|
+
path = connector.get_metadata_cache_path()
|
389
|
+
now = get_current_timestamp()
|
390
|
+
with open(path, 'w+', encoding='utf-8') as f:
|
391
|
+
json.dump({'created': now}, f, default=json_serialize_value)
|
meerschaum/core/Pipe/__init__.py
CHANGED
@@ -562,7 +562,7 @@ class Pipe:
|
|
562
562
|
'connector_keys': self.connector_keys,
|
563
563
|
'metric_key': self.metric_key,
|
564
564
|
'location_key': self.location_key,
|
565
|
-
'parameters': self.parameters,
|
565
|
+
'parameters': self._attributes.get('parameters', None),
|
566
566
|
'instance_keys': self.instance_keys,
|
567
567
|
}
|
568
568
|
|
@@ -598,3 +598,19 @@ class Pipe:
|
|
598
598
|
if aliased_key is not None:
|
599
599
|
key = aliased_key
|
600
600
|
return getattr(self, key, None)
|
601
|
+
|
602
|
+
def __copy__(self):
|
603
|
+
"""
|
604
|
+
Return a shallow copy of the current pipe.
|
605
|
+
"""
|
606
|
+
return mrsm.Pipe(
|
607
|
+
self.connector_keys, self.metric_key, self.location_key,
|
608
|
+
instance=self.instance_keys,
|
609
|
+
parameters=self._attributes.get('parameters', None),
|
610
|
+
)
|
611
|
+
|
612
|
+
def __deepcopy__(self, memo):
|
613
|
+
"""
|
614
|
+
Return a deep copy of the current pipe.
|
615
|
+
"""
|
616
|
+
return self.__copy__()
|
@@ -286,7 +286,6 @@ def get_dtypes(
|
|
286
286
|
"""
|
287
287
|
If defined, return the `dtypes` dictionary defined in `meerschaum.Pipe.parameters`.
|
288
288
|
|
289
|
-
|
290
289
|
Parameters
|
291
290
|
----------
|
292
291
|
infer: bool, default True
|
@@ -310,7 +309,11 @@ def get_dtypes(
|
|
310
309
|
dprint(f"Configured dtypes for {self}:")
|
311
310
|
mrsm.pprint(configured_dtypes)
|
312
311
|
|
313
|
-
remote_dtypes =
|
312
|
+
remote_dtypes = (
|
313
|
+
self.infer_dtypes(persist=False, refresh=refresh, debug=debug)
|
314
|
+
if infer
|
315
|
+
else {}
|
316
|
+
)
|
314
317
|
patched_dtypes = apply_patch_to_config((remote_dtypes or {}), (configured_dtypes or {}))
|
315
318
|
|
316
319
|
dt_col = parameters.get('columns', {}).get('datetime', None)
|
meerschaum/core/Token/_Token.py
CHANGED
@@ -120,7 +120,7 @@ class Token:
|
|
120
120
|
Register the new token to the configured instance.
|
121
121
|
"""
|
122
122
|
if self.user is None:
|
123
|
-
|
123
|
+
return False, "Cannot register a token without a user."
|
124
124
|
|
125
125
|
return self.instance_connector.register_token(self, debug=debug)
|
126
126
|
|