meerschaum 2.2.0rc2__py3-none-any.whl → 2.2.0rc3__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/api/__init__.py +16 -11
- meerschaum/config/_jobs.py +1 -1
- meerschaum/config/_paths.py +1 -0
- meerschaum/config/_version.py +1 -1
- meerschaum/config/static/__init__.py +1 -0
- meerschaum/connectors/__init__.py +2 -0
- meerschaum/connectors/sql/SQLConnector.py +4 -2
- meerschaum/connectors/sql/_create_engine.py +4 -4
- meerschaum/connectors/sql/_instance.py +3 -1
- meerschaum/connectors/sql/_pipes.py +53 -38
- meerschaum/connectors/sql/_sql.py +7 -9
- meerschaum/core/User/_User.py +2 -0
- meerschaum/plugins/__init__.py +23 -1
- meerschaum/utils/daemon/Daemon.py +17 -2
- meerschaum/utils/daemon/FileDescriptorInterceptor.py +46 -8
- meerschaum/utils/daemon/RotatingFile.py +4 -0
- meerschaum/utils/daemon/__init__.py +2 -0
- meerschaum/utils/packages/__init__.py +10 -4
- meerschaum/utils/packages/_packages.py +7 -8
- meerschaum/utils/process.py +13 -10
- meerschaum/utils/schedule.py +15 -1
- {meerschaum-2.2.0rc2.dist-info → meerschaum-2.2.0rc3.dist-info}/METADATA +19 -21
- {meerschaum-2.2.0rc2.dist-info → meerschaum-2.2.0rc3.dist-info}/RECORD +29 -29
- {meerschaum-2.2.0rc2.dist-info → meerschaum-2.2.0rc3.dist-info}/LICENSE +0 -0
- {meerschaum-2.2.0rc2.dist-info → meerschaum-2.2.0rc3.dist-info}/NOTICE +0 -0
- {meerschaum-2.2.0rc2.dist-info → meerschaum-2.2.0rc3.dist-info}/WHEEL +0 -0
- {meerschaum-2.2.0rc2.dist-info → meerschaum-2.2.0rc3.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.2.0rc2.dist-info → meerschaum-2.2.0rc3.dist-info}/top_level.txt +0 -0
- {meerschaum-2.2.0rc2.dist-info → meerschaum-2.2.0rc3.dist-info}/zip-safe +0 -0
meerschaum/api/__init__.py
CHANGED
@@ -30,21 +30,26 @@ _locks = {'pipes': RLock(), 'connector': RLock(), 'uvicorn_config': RLock()}
|
|
30
30
|
CHECK_UPDATE = os.environ.get(STATIC_CONFIG['environment']['runtime'], None) != 'docker'
|
31
31
|
|
32
32
|
endpoints = STATIC_CONFIG['api']['endpoints']
|
33
|
-
|
33
|
+
|
34
|
+
(
|
35
|
+
fastapi,
|
36
|
+
aiofiles,
|
37
|
+
starlette_responses,
|
38
|
+
multipart,
|
39
|
+
packaging_version,
|
40
|
+
) = attempt_import(
|
41
|
+
'fastapi',
|
42
|
+
'aiofiles',
|
43
|
+
'starlette.responses',
|
44
|
+
'multipart',
|
45
|
+
'packaging.version',
|
46
|
+
lazy = False,
|
47
|
+
check_update = CHECK_UPDATE,
|
48
|
+
)
|
34
49
|
typing_extensions = attempt_import(
|
35
50
|
'typing_extensions', lazy=False, check_update=CHECK_UPDATE,
|
36
51
|
venv = None,
|
37
52
|
)
|
38
|
-
pydantic_dataclasses = attempt_import(
|
39
|
-
'pydantic.dataclasses', lazy=False, check_update=CHECK_UPDATE,
|
40
|
-
)
|
41
|
-
fastapi = attempt_import('fastapi', lazy=False, check_update=CHECK_UPDATE)
|
42
|
-
starlette_reponses = attempt_import(
|
43
|
-
'starlette.responses', warn=False, lazy=False,
|
44
|
-
check_update=CHECK_UPDATE,
|
45
|
-
)
|
46
|
-
python_multipart = attempt_import('multipart', lazy=False, check_update=CHECK_UPDATE)
|
47
|
-
packaging_version = attempt_import('packaging.version', check_update=CHECK_UPDATE)
|
48
53
|
from meerschaum.api._chain import check_allow_chaining, DISALLOW_CHAINING_MESSAGE
|
49
54
|
uvicorn_config_path = API_UVICORN_RESOURCES_PATH / SERVER_ID / 'config.json'
|
50
55
|
|
meerschaum/config/_jobs.py
CHANGED
meerschaum/config/_paths.py
CHANGED
@@ -129,6 +129,7 @@ paths = {
|
|
129
129
|
|
130
130
|
'PLUGINS_RESOURCES_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'plugins'),
|
131
131
|
'PLUGINS_INTERNAL_LOCK_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'plugins.lock'),
|
132
|
+
'PLUGINS_PACKAGES_INTERNAL_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'packaged_plugins'),
|
132
133
|
'PLUGINS_ARCHIVES_RESOURCES_PATH': ('{PLUGINS_RESOURCES_PATH}', '.archives'),
|
133
134
|
'PLUGINS_TEMP_RESOURCES_PATH' : ('{PLUGINS_RESOURCES_PATH}', '.tmp'),
|
134
135
|
'PLUGINS_INIT_PATH' : ('{PLUGINS_RESOURCES_PATH}', '__init__.py'),
|
meerschaum/config/_version.py
CHANGED
@@ -317,6 +317,8 @@ def load_plugin_connectors():
|
|
317
317
|
from meerschaum.plugins import get_plugins, import_plugins
|
318
318
|
to_import = []
|
319
319
|
for plugin in get_plugins():
|
320
|
+
if plugin is None:
|
321
|
+
continue
|
320
322
|
with open(plugin.__file__, encoding='utf-8') as f:
|
321
323
|
text = f.read()
|
322
324
|
if 'make_connector' in text:
|
@@ -128,8 +128,10 @@ class SQLConnector(Connector):
|
|
128
128
|
"""
|
129
129
|
if 'uri' in kw:
|
130
130
|
uri = kw['uri']
|
131
|
-
if uri.startswith('postgres
|
132
|
-
uri = uri.replace('postgres
|
131
|
+
if uri.startswith('postgres') and not uri.startswith('postgresql'):
|
132
|
+
uri = uri.replace('postgres', 'postgresql', 1)
|
133
|
+
if uri.startswith('postgresql') and not uri.startswith('postgresql+'):
|
134
|
+
uri = uri.replace('postgresql://', 'postgresql+psycopg', 1)
|
133
135
|
if uri.startswith('timescaledb://'):
|
134
136
|
uri = uri.replace('timescaledb://', 'postgresql://', 1)
|
135
137
|
flavor = 'timescaledb'
|
@@ -28,7 +28,7 @@ default_create_engine_args = {
|
|
28
28
|
}
|
29
29
|
flavor_configs = {
|
30
30
|
'timescaledb' : {
|
31
|
-
'engine' : 'postgresql',
|
31
|
+
'engine' : 'postgresql+psycopg',
|
32
32
|
'create_engine' : default_create_engine_args,
|
33
33
|
'omit_create_engine': {'method',},
|
34
34
|
'to_sql' : {},
|
@@ -38,7 +38,7 @@ flavor_configs = {
|
|
38
38
|
},
|
39
39
|
},
|
40
40
|
'postgresql' : {
|
41
|
-
'engine' : 'postgresql',
|
41
|
+
'engine' : 'postgresql+psycopg',
|
42
42
|
'create_engine' : default_create_engine_args,
|
43
43
|
'omit_create_engine': {'method',},
|
44
44
|
'to_sql' : {},
|
@@ -48,7 +48,7 @@ flavor_configs = {
|
|
48
48
|
},
|
49
49
|
},
|
50
50
|
'citus' : {
|
51
|
-
'engine' : 'postgresql',
|
51
|
+
'engine' : 'postgresql+psycopg',
|
52
52
|
'create_engine' : default_create_engine_args,
|
53
53
|
'omit_create_engine': {'method',},
|
54
54
|
'to_sql' : {},
|
@@ -242,7 +242,7 @@ def create_engine(
|
|
242
242
|
|
243
243
|
### Sometimes the timescaledb:// flavor can slip in.
|
244
244
|
if _uri and self.flavor in ('timescaledb',) and self.flavor in _uri:
|
245
|
-
engine_str = engine_str.replace(f'{self.flavor}
|
245
|
+
engine_str = engine_str.replace(f'{self.flavor}', 'postgresql', 1)
|
246
246
|
|
247
247
|
if debug:
|
248
248
|
dprint(
|
@@ -155,7 +155,9 @@ def _drop_old_temporary_tables(
|
|
155
155
|
temp_tables_table = get_tables(mrsm_instance=self, create=False, debug=debug)['temp_tables']
|
156
156
|
last_check = getattr(self, '_stale_temporary_tables_check_timestamp', 0)
|
157
157
|
now_ts = time.perf_counter()
|
158
|
-
if
|
158
|
+
if not last_check:
|
159
|
+
self._stale_temporary_tables_check_timestamp = 0
|
160
|
+
if refresh or (now_ts - last_check) < 60:
|
159
161
|
self._stale_temporary_tables_check_timestamp = now_ts
|
160
162
|
return self._drop_temporary_tables(debug=debug)
|
161
163
|
|
@@ -752,7 +752,7 @@ def get_pipe_data(
|
|
752
752
|
debug = debug,
|
753
753
|
**kw
|
754
754
|
)
|
755
|
-
|
755
|
+
|
756
756
|
if is_dask:
|
757
757
|
index_col = pipe.columns.get('datetime', None)
|
758
758
|
kw['index_col'] = index_col
|
@@ -1478,43 +1478,11 @@ def sync_pipe_inplace(
|
|
1478
1478
|
from meerschaum.utils.misc import generate_password
|
1479
1479
|
from meerschaum.utils.debug import dprint
|
1480
1480
|
|
1481
|
-
sqlalchemy, sqlalchemy_orm = mrsm.attempt_import('sqlalchemy', 'sqlalchemy.orm')
|
1482
|
-
metadef = self.get_pipe_metadef(
|
1483
|
-
pipe,
|
1484
|
-
params = params,
|
1485
|
-
begin = begin,
|
1486
|
-
end = end,
|
1487
|
-
check_existing = check_existing,
|
1488
|
-
debug = debug,
|
1489
|
-
)
|
1490
|
-
pipe_name = sql_item_name(pipe.target, self.flavor, self.get_pipe_schema(pipe))
|
1491
|
-
upsert = pipe.parameters.get('upsert', False) and f'{self.flavor}-upsert' in update_queries
|
1492
|
-
internal_schema = self.internal_schema
|
1493
|
-
database = getattr(self, 'database', self.parse_uri(self.URI).get('database', None))
|
1494
|
-
|
1495
|
-
if not pipe.exists(debug=debug):
|
1496
|
-
create_pipe_query = get_create_table_query(
|
1497
|
-
metadef,
|
1498
|
-
pipe.target,
|
1499
|
-
self.flavor,
|
1500
|
-
schema = self.get_pipe_schema(pipe),
|
1501
|
-
)
|
1502
|
-
result = self.exec(create_pipe_query, debug=debug)
|
1503
|
-
if result is None:
|
1504
|
-
return False, f"Could not insert new data into {pipe} from its SQL query definition."
|
1505
|
-
if not self.create_indices(pipe, debug=debug):
|
1506
|
-
warn(f"Failed to create indices for {pipe}. Continuing...")
|
1507
|
-
|
1508
|
-
rowcount = pipe.get_rowcount(debug=debug)
|
1509
|
-
return True, f"Inserted {rowcount}, updated 0 rows."
|
1510
|
-
|
1511
|
-
session = sqlalchemy_orm.Session(self.engine)
|
1512
|
-
connectable = session if self.flavor != 'duckdb' else self
|
1513
|
-
|
1514
1481
|
transact_id = generate_password(3)
|
1515
1482
|
def get_temp_table_name(label: str) -> str:
|
1516
1483
|
return '-' + transact_id + '_' + label + '_' + pipe.target
|
1517
1484
|
|
1485
|
+
internal_schema = self.internal_schema
|
1518
1486
|
temp_table_roots = ['backtrack', 'new', 'delta', 'joined', 'unseen', 'update']
|
1519
1487
|
temp_tables = {
|
1520
1488
|
table_root: get_temp_table_name(table_root)
|
@@ -1528,6 +1496,17 @@ def sync_pipe_inplace(
|
|
1528
1496
|
)
|
1529
1497
|
for table_root, table_name_raw in temp_tables.items()
|
1530
1498
|
}
|
1499
|
+
metadef = self.get_pipe_metadef(
|
1500
|
+
pipe,
|
1501
|
+
params = params,
|
1502
|
+
begin = begin,
|
1503
|
+
end = end,
|
1504
|
+
check_existing = check_existing,
|
1505
|
+
debug = debug,
|
1506
|
+
)
|
1507
|
+
pipe_name = sql_item_name(pipe.target, self.flavor, self.get_pipe_schema(pipe))
|
1508
|
+
upsert = pipe.parameters.get('upsert', False) and f'{self.flavor}-upsert' in update_queries
|
1509
|
+
database = getattr(self, 'database', self.parse_uri(self.URI).get('database', None))
|
1531
1510
|
|
1532
1511
|
def clean_up_temp_tables(ready_to_drop: bool = False):
|
1533
1512
|
log_success, log_msg = self._log_temporary_tables_creation(
|
@@ -1541,6 +1520,36 @@ def sync_pipe_inplace(
|
|
1541
1520
|
)
|
1542
1521
|
if not log_success:
|
1543
1522
|
warn(log_msg)
|
1523
|
+
drop_stale_success, drop_stale_msg = self._drop_old_temporary_tables(
|
1524
|
+
refresh = False,
|
1525
|
+
debug = debug,
|
1526
|
+
)
|
1527
|
+
if not drop_stale_success:
|
1528
|
+
warn(drop_stale_msg)
|
1529
|
+
return drop_stale_success, drop_stale_msg
|
1530
|
+
|
1531
|
+
sqlalchemy, sqlalchemy_orm = mrsm.attempt_import('sqlalchemy', 'sqlalchemy.orm')
|
1532
|
+
if not pipe.exists(debug=debug):
|
1533
|
+
create_pipe_query = get_create_table_query(
|
1534
|
+
metadef,
|
1535
|
+
pipe.target,
|
1536
|
+
self.flavor,
|
1537
|
+
schema = self.get_pipe_schema(pipe),
|
1538
|
+
)
|
1539
|
+
result = self.exec(create_pipe_query, debug=debug)
|
1540
|
+
if result is None:
|
1541
|
+
_ = clean_up_temp_tables()
|
1542
|
+
return False, f"Could not insert new data into {pipe} from its SQL query definition."
|
1543
|
+
|
1544
|
+
if not self.create_indices(pipe, debug=debug):
|
1545
|
+
warn(f"Failed to create indices for {pipe}. Continuing...")
|
1546
|
+
|
1547
|
+
rowcount = pipe.get_rowcount(debug=debug)
|
1548
|
+
_ = clean_up_temp_tables()
|
1549
|
+
return True, f"Inserted {rowcount}, updated 0 rows."
|
1550
|
+
|
1551
|
+
session = sqlalchemy_orm.Session(self.engine)
|
1552
|
+
connectable = session if self.flavor != 'duckdb' else self
|
1544
1553
|
|
1545
1554
|
create_new_query = get_create_table_query(
|
1546
1555
|
metadef,
|
@@ -1908,10 +1917,6 @@ def sync_pipe_inplace(
|
|
1908
1917
|
)
|
1909
1918
|
_ = clean_up_temp_tables(ready_to_drop=True)
|
1910
1919
|
|
1911
|
-
drop_stale_success, drop_stale_msg = self._drop_old_temporary_tables(refresh=False, debug=debug)
|
1912
|
-
if not drop_stale_success:
|
1913
|
-
warn(drop_stale_msg)
|
1914
|
-
|
1915
1920
|
return True, msg
|
1916
1921
|
|
1917
1922
|
|
@@ -2372,6 +2377,16 @@ def get_pipe_columns_types(
|
|
2372
2377
|
"""
|
2373
2378
|
if not pipe.exists(debug=debug):
|
2374
2379
|
return {}
|
2380
|
+
|
2381
|
+
if self.flavor == 'duckdb':
|
2382
|
+
from meerschaum.utils.sql import get_table_cols_types
|
2383
|
+
return get_table_cols_types(
|
2384
|
+
pipe.target,
|
2385
|
+
self,
|
2386
|
+
flavor = self.flavor,
|
2387
|
+
schema = self.schema,
|
2388
|
+
)
|
2389
|
+
|
2375
2390
|
table_columns = {}
|
2376
2391
|
try:
|
2377
2392
|
pipe_table = self.get_pipe_table(pipe, debug=debug)
|
@@ -943,17 +943,15 @@ def psql_insert_copy(
|
|
943
943
|
) for row in data_iter
|
944
944
|
)
|
945
945
|
|
946
|
+
table_name = sql_item_name(table.name, 'postgresql', table.schema)
|
947
|
+
columns = ', '.join(f'"{k}"' for k in keys)
|
948
|
+
sql = f"COPY {table_name} ({columns}) FROM STDIN WITH CSV NULL '\\N'"
|
949
|
+
|
946
950
|
dbapi_conn = conn.connection
|
947
951
|
with dbapi_conn.cursor() as cur:
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
s_buf.seek(0)
|
952
|
-
|
953
|
-
columns = ', '.join(f'"{k}"' for k in keys)
|
954
|
-
table_name = sql_item_name(table.name, 'postgresql', table.schema)
|
955
|
-
sql = f"COPY {table_name} ({columns}) FROM STDIN WITH CSV NULL '\\N'"
|
956
|
-
cur.copy_expert(sql=sql, file=s_buf)
|
952
|
+
with cur.copy(sql) as copy:
|
953
|
+
writer = csv.writer(copy)
|
954
|
+
writer.writerows(data_iter)
|
957
955
|
|
958
956
|
|
959
957
|
def format_sql_query_for_dask(query: str) -> 'sqlalchemy.sql.selectable.Select':
|
meerschaum/core/User/_User.py
CHANGED
@@ -86,6 +86,8 @@ def verify_password(
|
|
86
86
|
-------
|
87
87
|
A `bool` indicating whether `password` matches `password_hash`.
|
88
88
|
"""
|
89
|
+
if password is None or password_hash is None:
|
90
|
+
return False
|
89
91
|
hash_config = STATIC_CONFIG['users']['password_hash']
|
90
92
|
try:
|
91
93
|
digest, rounds_str, encoded_salt, encoded_checksum = password_hash.split('$')[1:]
|
meerschaum/plugins/__init__.py
CHANGED
@@ -247,6 +247,26 @@ def sync_plugins_symlinks(debug: bool = False, warn: bool = True) -> None:
|
|
247
247
|
_warn(f"Unable to create lockfile {PLUGINS_INTERNAL_LOCK_PATH}:\n{e}")
|
248
248
|
|
249
249
|
with _locks['internal_plugins']:
|
250
|
+
|
251
|
+
try:
|
252
|
+
from importlib.metadata import entry_points
|
253
|
+
except ImportError:
|
254
|
+
importlib_metadata = attempt_import('importlib_metadata', lazy=False)
|
255
|
+
entry_points = importlib_metadata.entry_points
|
256
|
+
|
257
|
+
### NOTE: Allow plugins to be installed via `pip`.
|
258
|
+
packaged_plugin_paths = []
|
259
|
+
discovered_packaged_plugins_eps = entry_points(group='meerschaum.plugins')
|
260
|
+
for ep in discovered_packaged_plugins_eps:
|
261
|
+
module_name = ep.name
|
262
|
+
for package_file_path in ep.dist.files:
|
263
|
+
if package_file_path.suffix != '.py':
|
264
|
+
continue
|
265
|
+
if str(package_file_path) == f'{module_name}.py':
|
266
|
+
packaged_plugin_paths.append(package_file_path.locate())
|
267
|
+
elif str(package_file_path) == f'{module_name}/__init__.py':
|
268
|
+
packaged_plugin_paths.append(package_file_path.locate().parent)
|
269
|
+
|
250
270
|
if is_symlink(PLUGINS_RESOURCES_PATH) or not PLUGINS_RESOURCES_PATH.exists():
|
251
271
|
try:
|
252
272
|
PLUGINS_RESOURCES_PATH.unlink()
|
@@ -255,7 +275,6 @@ def sync_plugins_symlinks(debug: bool = False, warn: bool = True) -> None:
|
|
255
275
|
|
256
276
|
PLUGINS_RESOURCES_PATH.mkdir(exist_ok=True)
|
257
277
|
|
258
|
-
|
259
278
|
existing_symlinked_paths = [
|
260
279
|
(PLUGINS_RESOURCES_PATH / item)
|
261
280
|
for item in os.listdir(PLUGINS_RESOURCES_PATH)
|
@@ -275,6 +294,7 @@ def sync_plugins_symlinks(debug: bool = False, warn: bool = True) -> None:
|
|
275
294
|
for plugins_path in PLUGINS_DIR_PATHS
|
276
295
|
]
|
277
296
|
))
|
297
|
+
plugins_to_be_symlinked.extend(packaged_plugin_paths)
|
278
298
|
|
279
299
|
### Check for duplicates.
|
280
300
|
seen_plugins = defaultdict(lambda: 0)
|
@@ -538,6 +558,8 @@ def get_plugins(*to_load, try_import: bool = True) -> Union[Tuple[Plugin], Plugi
|
|
538
558
|
]
|
539
559
|
plugins = tuple(plugin for plugin in _plugins if plugin.is_installed(try_import=try_import))
|
540
560
|
if len(to_load) == 1:
|
561
|
+
if len(plugins) == 0:
|
562
|
+
raise ValueError(f"Plugin '{to_load[0]}' is not installed.")
|
541
563
|
return plugins[0]
|
542
564
|
return plugins
|
543
565
|
|
@@ -19,6 +19,7 @@ from functools import partial
|
|
19
19
|
from datetime import datetime, timezone
|
20
20
|
from meerschaum.utils.typing import Optional, Dict, Any, SuccessTuple, Callable, List, Union
|
21
21
|
from meerschaum.config import get_config
|
22
|
+
from meerschaum.config.static import STATIC_CONFIG
|
22
23
|
from meerschaum.config._paths import DAEMON_RESOURCES_PATH, LOGS_RESOURCES_PATH
|
23
24
|
from meerschaum.config._patch import apply_patch_to_config
|
24
25
|
from meerschaum.utils.warnings import warn, error
|
@@ -170,9 +171,11 @@ class Daemon:
|
|
170
171
|
log_refresh_seconds,
|
171
172
|
partial(self.rotating_log.refresh_files, start_interception=True),
|
172
173
|
)
|
174
|
+
|
173
175
|
try:
|
174
176
|
os.environ['LINES'], os.environ['COLUMNS'] = str(int(lines)), str(int(columns))
|
175
177
|
with self._daemon_context:
|
178
|
+
os.environ[STATIC_CONFIG['environment']['daemon_id']] = self.daemon_id
|
176
179
|
self.rotating_log.refresh_files(start_interception=True)
|
177
180
|
try:
|
178
181
|
with open(self.pid_path, 'w+', encoding='utf-8') as f:
|
@@ -462,6 +465,9 @@ class Daemon:
|
|
462
465
|
Handle `SIGINT` within the Daemon context.
|
463
466
|
This method is injected into the `DaemonContext`.
|
464
467
|
"""
|
468
|
+
# from meerschaum.utils.daemon.FileDescriptorInterceptor import STOP_READING_FD_EVENT
|
469
|
+
# STOP_READING_FD_EVENT.set()
|
470
|
+
self.rotating_log.stop_log_fd_interception(unused_only=False)
|
465
471
|
timer = self.__dict__.get('_log_refresh_timer', None)
|
466
472
|
if timer is not None:
|
467
473
|
timer.cancel()
|
@@ -471,7 +477,16 @@ class Daemon:
|
|
471
477
|
daemon_context.close()
|
472
478
|
|
473
479
|
_close_pools()
|
474
|
-
|
480
|
+
import threading
|
481
|
+
for thread in threading.enumerate():
|
482
|
+
if thread.name == 'MainThread':
|
483
|
+
continue
|
484
|
+
try:
|
485
|
+
if thread.is_alive():
|
486
|
+
stack = traceback.format_stack(sys._current_frames()[thread.ident])
|
487
|
+
thread.join()
|
488
|
+
except Exception as e:
|
489
|
+
warn(traceback.format_exc())
|
475
490
|
raise KeyboardInterrupt()
|
476
491
|
|
477
492
|
|
@@ -489,7 +504,7 @@ class Daemon:
|
|
489
504
|
daemon_context.close()
|
490
505
|
|
491
506
|
_close_pools()
|
492
|
-
raise SystemExit(
|
507
|
+
raise SystemExit(0)
|
493
508
|
|
494
509
|
|
495
510
|
def _send_signal(
|
@@ -7,12 +7,15 @@ Intercept OS-level file descriptors.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
import os
|
10
|
+
import select
|
10
11
|
import traceback
|
12
|
+
from threading import Event
|
11
13
|
from datetime import datetime
|
12
14
|
from meerschaum.utils.typing import Callable
|
13
15
|
from meerschaum.utils.warnings import warn
|
14
16
|
|
15
17
|
FD_CLOSED: int = 9
|
18
|
+
STOP_READING_FD_EVENT: Event = Event()
|
16
19
|
|
17
20
|
class FileDescriptorInterceptor:
|
18
21
|
"""
|
@@ -32,10 +35,12 @@ class FileDescriptorInterceptor:
|
|
32
35
|
injection_hook: Callable[[], str]
|
33
36
|
A callable which returns a string to be injected into the written data.
|
34
37
|
"""
|
38
|
+
self.stop_event = Event()
|
35
39
|
self.injection_hook = injection_hook
|
36
40
|
self.original_file_descriptor = file_descriptor
|
37
41
|
self.new_file_descriptor = os.dup(file_descriptor)
|
38
42
|
self.read_pipe, self.write_pipe = os.pipe()
|
43
|
+
self.signal_read_pipe, self.signal_write_pipe = os.pipe()
|
39
44
|
os.dup2(self.write_pipe, file_descriptor)
|
40
45
|
|
41
46
|
def start_interception(self):
|
@@ -44,11 +49,23 @@ class FileDescriptorInterceptor:
|
|
44
49
|
|
45
50
|
NOTE: This is blocking and is meant to be run in a thread.
|
46
51
|
"""
|
52
|
+
os.set_blocking(self.read_pipe, False)
|
53
|
+
os.set_blocking(self.signal_read_pipe, False)
|
47
54
|
is_first_read = True
|
48
|
-
while
|
49
|
-
|
50
|
-
|
51
|
-
|
55
|
+
while not self.stop_event.is_set():
|
56
|
+
try:
|
57
|
+
rlist, _, _ = select.select([self.read_pipe, self.signal_read_pipe], [], [], 0.1)
|
58
|
+
if self.signal_read_pipe in rlist:
|
59
|
+
break
|
60
|
+
if not rlist:
|
61
|
+
continue
|
62
|
+
data = os.read(self.read_pipe, 1024)
|
63
|
+
if not data:
|
64
|
+
break
|
65
|
+
except BlockingIOError:
|
66
|
+
continue
|
67
|
+
except OSError as e:
|
68
|
+
continue
|
52
69
|
|
53
70
|
first_char_is_newline = data[0] == b'\n'
|
54
71
|
last_char_is_newline = data[-1] == b'\n'
|
@@ -65,16 +82,17 @@ class FileDescriptorInterceptor:
|
|
65
82
|
if last_char_is_newline
|
66
83
|
else data.replace(b'\n', b'\n' + injected_bytes)
|
67
84
|
)
|
68
|
-
|
69
85
|
os.write(self.new_file_descriptor, modified_data)
|
70
86
|
|
87
|
+
|
71
88
|
def stop_interception(self):
|
72
89
|
"""
|
73
|
-
|
90
|
+
Close the new file descriptors.
|
74
91
|
"""
|
92
|
+
self.stop_event.set()
|
93
|
+
os.write(self.signal_write_pipe, b'\0')
|
75
94
|
try:
|
76
|
-
os.
|
77
|
-
# os.close(self.new_file_descriptor)
|
95
|
+
os.close(self.new_file_descriptor)
|
78
96
|
except OSError as e:
|
79
97
|
if e.errno != FD_CLOSED:
|
80
98
|
warn(
|
@@ -100,3 +118,23 @@ class FileDescriptorInterceptor:
|
|
100
118
|
+ "to the intercepted file descriptor:\n"
|
101
119
|
+ f"{traceback.format_exc()}"
|
102
120
|
)
|
121
|
+
|
122
|
+
try:
|
123
|
+
os.close(self.signal_read_pipe)
|
124
|
+
except OSError as e:
|
125
|
+
if e.errno != FD_CLOSED:
|
126
|
+
warn(
|
127
|
+
f"Error while trying to close the signal-read-pipe "
|
128
|
+
+ "to the intercepted file descriptor:\n"
|
129
|
+
+ f"{traceback.format_exc()}"
|
130
|
+
)
|
131
|
+
|
132
|
+
try:
|
133
|
+
os.close(self.signal_write_pipe)
|
134
|
+
except OSError as e:
|
135
|
+
if e.errno != FD_CLOSED:
|
136
|
+
warn(
|
137
|
+
f"Error while trying to close the signal-write-pipe "
|
138
|
+
+ "to the intercepted file descriptor:\n"
|
139
|
+
+ f"{traceback.format_exc()}"
|
140
|
+
)
|
@@ -621,6 +621,10 @@ class RotatingFile(io.IOBase):
|
|
621
621
|
self._stdout_interceptor_thread,
|
622
622
|
self._stderr_interceptor_thread,
|
623
623
|
])
|
624
|
+
self._interceptors.extend([
|
625
|
+
self._stdout_interceptor,
|
626
|
+
self._stderr_interceptor,
|
627
|
+
])
|
624
628
|
self.stop_log_fd_interception(unused_only=True)
|
625
629
|
|
626
630
|
def stop_log_fd_interception(self, unused_only: bool = False):
|
@@ -64,6 +64,8 @@ def daemon_entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
|
|
64
64
|
|
65
65
|
### Only run if the kwargs equal or no actions are provided.
|
66
66
|
if existing_kwargs == _args or not _args.get('action', []):
|
67
|
+
if daemon.status == 'running':
|
68
|
+
return True, f"Daemon '{daemon}' is already running."
|
67
69
|
return daemon.run(
|
68
70
|
debug = debug,
|
69
71
|
allow_dirty_run = True,
|
@@ -829,8 +829,11 @@ def pip_install(
|
|
829
829
|
check_wheel = False, debug = debug,
|
830
830
|
):
|
831
831
|
warn(
|
832
|
-
|
833
|
-
|
832
|
+
(
|
833
|
+
"Failed to install `setuptools` and `wheel` for virtual "
|
834
|
+
+ f"environment '{venv}'."
|
835
|
+
),
|
836
|
+
color = False,
|
834
837
|
)
|
835
838
|
|
836
839
|
if requirements_file_path is not None:
|
@@ -893,13 +896,16 @@ def pip_install(
|
|
893
896
|
f"Failed to clean up package '{_install_no_version}'.",
|
894
897
|
)
|
895
898
|
|
896
|
-
|
899
|
+
rc = run_python_package(
|
897
900
|
'pip',
|
898
901
|
_args + _packages,
|
899
902
|
venv = venv,
|
900
903
|
env = _get_pip_os_env(),
|
901
904
|
debug = debug,
|
902
|
-
)
|
905
|
+
)
|
906
|
+
if debug:
|
907
|
+
print(f"{rc=}")
|
908
|
+
success = rc == 0
|
903
909
|
|
904
910
|
msg = (
|
905
911
|
"Successfully " + ('un' if _uninstall else '') + "installed packages." if success
|
@@ -60,7 +60,7 @@ packages: Dict[str, Dict[str, str]] = {
|
|
60
60
|
'pymysql' : 'PyMySQL>=0.9.0',
|
61
61
|
'aiomysql' : 'aiomysql>=0.0.21',
|
62
62
|
'sqlalchemy_cockroachdb' : 'sqlalchemy-cockroachdb>=2.0.0',
|
63
|
-
'duckdb' : 'duckdb
|
63
|
+
'duckdb' : 'duckdb<0.10.0',
|
64
64
|
'duckdb_engine' : 'duckdb-engine>=0.9.2',
|
65
65
|
},
|
66
66
|
'_drivers': {
|
@@ -120,8 +120,8 @@ packages: Dict[str, Dict[str, str]] = {
|
|
120
120
|
packages['sql'] = {
|
121
121
|
'numpy' : 'numpy>=1.18.5',
|
122
122
|
'pandas' : 'pandas[parquet]>=2.0.1',
|
123
|
-
'pyarrow' : 'pyarrow>=
|
124
|
-
'dask' : 'dask>=
|
123
|
+
'pyarrow' : 'pyarrow>=16.1.0',
|
124
|
+
'dask' : 'dask[dataframe]>=2024.5.1',
|
125
125
|
'pytz' : 'pytz',
|
126
126
|
'joblib' : 'joblib>=0.17.0',
|
127
127
|
'sqlalchemy' : 'SQLAlchemy>=2.0.5',
|
@@ -142,14 +142,13 @@ packages['dash'] = {
|
|
142
142
|
'tornado' : 'tornado>=6.1.0',
|
143
143
|
}
|
144
144
|
packages['api'] = {
|
145
|
-
'uvicorn' : 'uvicorn[standard]>=0.
|
146
|
-
'gunicorn' : 'gunicorn>=
|
145
|
+
'uvicorn' : 'uvicorn[standard]>=0.29.0',
|
146
|
+
'gunicorn' : 'gunicorn>=22.0.0',
|
147
147
|
'dotenv' : 'python-dotenv>=0.20.0',
|
148
148
|
'websockets' : 'websockets>=11.0.3',
|
149
|
-
'fastapi' : 'fastapi>=0.
|
150
|
-
'passlib' : 'passlib>=1.7.4',
|
149
|
+
'fastapi' : 'fastapi>=0.111.0',
|
151
150
|
'fastapi_login' : 'fastapi-login>=1.7.2',
|
152
|
-
'multipart' : 'python-multipart>=0.0.
|
151
|
+
'multipart' : 'python-multipart>=0.0.9',
|
153
152
|
'httpx' : 'httpx>=0.24.1',
|
154
153
|
'websockets' : 'websockets>=11.0.3',
|
155
154
|
}
|
meerschaum/utils/process.py
CHANGED
@@ -11,6 +11,7 @@ See `meerschaum.utils.pool` for multiprocessing and
|
|
11
11
|
from __future__ import annotations
|
12
12
|
import os, signal, subprocess, sys, platform
|
13
13
|
from meerschaum.utils.typing import Union, Optional, Any, Callable, Dict, Tuple
|
14
|
+
from meerschaum.config.static import STATIC_CONFIG
|
14
15
|
|
15
16
|
def run_process(
|
16
17
|
*args,
|
@@ -68,9 +69,18 @@ def run_process(
|
|
68
69
|
if platform.system() == 'Windows':
|
69
70
|
foreground = False
|
70
71
|
|
71
|
-
|
72
|
+
def print_line(line):
|
73
|
+
sys.stdout.write(line.decode('utf-8'))
|
74
|
+
sys.stdout.flush()
|
75
|
+
|
76
|
+
if capture_output or line_callback is not None:
|
77
|
+
kw['stdout'] = subprocess.PIPE
|
78
|
+
kw['stderr'] = subprocess.STDOUT
|
79
|
+
elif os.environ.get(STATIC_CONFIG['environment']['daemon_id']):
|
72
80
|
kw['stdout'] = subprocess.PIPE
|
73
81
|
kw['stderr'] = subprocess.STDOUT
|
82
|
+
if line_callback is None:
|
83
|
+
line_callback = print_line
|
74
84
|
|
75
85
|
if 'env' not in kw:
|
76
86
|
kw['env'] = os.environ
|
@@ -112,15 +122,6 @@ def run_process(
|
|
112
122
|
kw['preexec_fn'] = new_pgid
|
113
123
|
|
114
124
|
try:
|
115
|
-
# fork the child
|
116
|
-
# stdout, stderr = (
|
117
|
-
# (sys.stdout, sys.stderr) if not capture_output
|
118
|
-
# else (subprocess.PIPE, subprocess.PIPE)
|
119
|
-
# )
|
120
|
-
if capture_output:
|
121
|
-
kw['stdout'] = subprocess.PIPE
|
122
|
-
kw['stderr'] = subprocess.PIPE
|
123
|
-
|
124
125
|
child = subprocess.Popen(*args, **kw)
|
125
126
|
|
126
127
|
# we can't set the process group id from the parent since the child
|
@@ -197,6 +198,8 @@ def poll_process(
|
|
197
198
|
while proc.poll() is None:
|
198
199
|
line = proc.stdout.readline()
|
199
200
|
line_callback(line)
|
201
|
+
|
200
202
|
if timeout_seconds is not None:
|
201
203
|
watchdog_thread.cancel()
|
204
|
+
|
202
205
|
return proc.poll()
|
meerschaum/utils/schedule.py
CHANGED
@@ -278,7 +278,21 @@ def parse_start_time(schedule: str, now: Optional[datetime] = None) -> datetime:
|
|
278
278
|
starting_str = ('now' if len(starting_parts) == 1 else starting_parts[-1]).strip()
|
279
279
|
now = now or round_time(datetime.now(timezone.utc), timedelta(minutes=1))
|
280
280
|
try:
|
281
|
-
|
281
|
+
if starting_str == 'now':
|
282
|
+
starting_ts = now
|
283
|
+
elif 'tomorrow' in starting_str or 'today' in starting_str:
|
284
|
+
today = round_time(now, timedelta(days=1))
|
285
|
+
tomorrow = today + timedelta(days=1)
|
286
|
+
is_tomorrow = 'tomorrow' in starting_str
|
287
|
+
time_str = starting_str.replace('tomorrow', '').replace('today', '').strip()
|
288
|
+
time_ts = dateutil_parser.parse(time_str) if time_str else today
|
289
|
+
starting_ts = (
|
290
|
+
(tomorrow if is_tomorrow else today)
|
291
|
+
+ timedelta(hours=time_ts.hour)
|
292
|
+
+ timedelta(minutes=time_ts.minute)
|
293
|
+
)
|
294
|
+
else:
|
295
|
+
starting_ts = dateutil_parser.parse(starting_str)
|
282
296
|
schedule_parse_error = None
|
283
297
|
except Exception as e:
|
284
298
|
warn(f"Unable to parse starting time from '{starting_str}'.", stack=False)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: meerschaum
|
3
|
-
Version: 2.2.
|
3
|
+
Version: 2.2.0rc3
|
4
4
|
Summary: Sync Time-Series Pipes with Meerschaum
|
5
5
|
Home-page: https://meerschaum.io
|
6
6
|
Author: Bennett Meares
|
@@ -58,19 +58,18 @@ Requires-Dist: dill >=0.3.3 ; extra == '_required'
|
|
58
58
|
Requires-Dist: virtualenv >=20.1.0 ; extra == '_required'
|
59
59
|
Requires-Dist: APScheduler >=4.0.0a5 ; extra == '_required'
|
60
60
|
Provides-Extra: api
|
61
|
-
Requires-Dist: uvicorn[standard] >=0.
|
62
|
-
Requires-Dist: gunicorn >=
|
61
|
+
Requires-Dist: uvicorn[standard] >=0.29.0 ; extra == 'api'
|
62
|
+
Requires-Dist: gunicorn >=22.0.0 ; extra == 'api'
|
63
63
|
Requires-Dist: python-dotenv >=0.20.0 ; extra == 'api'
|
64
64
|
Requires-Dist: websockets >=11.0.3 ; extra == 'api'
|
65
|
-
Requires-Dist: fastapi >=0.
|
66
|
-
Requires-Dist: passlib >=1.7.4 ; extra == 'api'
|
65
|
+
Requires-Dist: fastapi >=0.111.0 ; extra == 'api'
|
67
66
|
Requires-Dist: fastapi-login >=1.7.2 ; extra == 'api'
|
68
|
-
Requires-Dist: python-multipart >=0.0.
|
67
|
+
Requires-Dist: python-multipart >=0.0.9 ; extra == 'api'
|
69
68
|
Requires-Dist: httpx >=0.24.1 ; extra == 'api'
|
70
69
|
Requires-Dist: numpy >=1.18.5 ; extra == 'api'
|
71
70
|
Requires-Dist: pandas[parquet] >=2.0.1 ; extra == 'api'
|
72
|
-
Requires-Dist: pyarrow >=
|
73
|
-
Requires-Dist: dask >=
|
71
|
+
Requires-Dist: pyarrow >=16.1.0 ; extra == 'api'
|
72
|
+
Requires-Dist: dask[dataframe] >=2024.5.1 ; extra == 'api'
|
74
73
|
Requires-Dist: pytz ; extra == 'api'
|
75
74
|
Requires-Dist: joblib >=0.17.0 ; extra == 'api'
|
76
75
|
Requires-Dist: SQLAlchemy >=2.0.5 ; extra == 'api'
|
@@ -82,7 +81,7 @@ Requires-Dist: psycopg[binary] >=3.1.18 ; extra == 'api'
|
|
82
81
|
Requires-Dist: PyMySQL >=0.9.0 ; extra == 'api'
|
83
82
|
Requires-Dist: aiomysql >=0.0.21 ; extra == 'api'
|
84
83
|
Requires-Dist: sqlalchemy-cockroachdb >=2.0.0 ; extra == 'api'
|
85
|
-
Requires-Dist: duckdb
|
84
|
+
Requires-Dist: duckdb <0.10.0 ; extra == 'api'
|
86
85
|
Requires-Dist: duckdb-engine >=0.9.2 ; extra == 'api'
|
87
86
|
Requires-Dist: wheel >=0.34.2 ; extra == 'api'
|
88
87
|
Requires-Dist: setuptools >=63.3.0 ; extra == 'api'
|
@@ -165,7 +164,7 @@ Requires-Dist: psycopg[binary] >=3.1.18 ; extra == 'drivers'
|
|
165
164
|
Requires-Dist: PyMySQL >=0.9.0 ; extra == 'drivers'
|
166
165
|
Requires-Dist: aiomysql >=0.0.21 ; extra == 'drivers'
|
167
166
|
Requires-Dist: sqlalchemy-cockroachdb >=2.0.0 ; extra == 'drivers'
|
168
|
-
Requires-Dist: duckdb
|
167
|
+
Requires-Dist: duckdb <0.10.0 ; extra == 'drivers'
|
169
168
|
Requires-Dist: duckdb-engine >=0.9.2 ; extra == 'drivers'
|
170
169
|
Provides-Extra: extras
|
171
170
|
Requires-Dist: cmd2 >=1.4.0 ; extra == 'extras'
|
@@ -218,15 +217,15 @@ Requires-Dist: psycopg[binary] >=3.1.18 ; extra == 'full'
|
|
218
217
|
Requires-Dist: PyMySQL >=0.9.0 ; extra == 'full'
|
219
218
|
Requires-Dist: aiomysql >=0.0.21 ; extra == 'full'
|
220
219
|
Requires-Dist: sqlalchemy-cockroachdb >=2.0.0 ; extra == 'full'
|
221
|
-
Requires-Dist: duckdb
|
220
|
+
Requires-Dist: duckdb <0.10.0 ; extra == 'full'
|
222
221
|
Requires-Dist: duckdb-engine >=0.9.2 ; extra == 'full'
|
223
222
|
Requires-Dist: toga >=0.3.0-dev29 ; extra == 'full'
|
224
223
|
Requires-Dist: pywebview >=3.6.3 ; extra == 'full'
|
225
224
|
Requires-Dist: pycparser >=2.21.0 ; extra == 'full'
|
226
225
|
Requires-Dist: numpy >=1.18.5 ; extra == 'full'
|
227
226
|
Requires-Dist: pandas[parquet] >=2.0.1 ; extra == 'full'
|
228
|
-
Requires-Dist: pyarrow >=
|
229
|
-
Requires-Dist: dask >=
|
227
|
+
Requires-Dist: pyarrow >=16.1.0 ; extra == 'full'
|
228
|
+
Requires-Dist: dask[dataframe] >=2024.5.1 ; extra == 'full'
|
230
229
|
Requires-Dist: pytz ; extra == 'full'
|
231
230
|
Requires-Dist: joblib >=0.17.0 ; extra == 'full'
|
232
231
|
Requires-Dist: SQLAlchemy >=2.0.5 ; extra == 'full'
|
@@ -241,14 +240,13 @@ Requires-Dist: dash-extensions >=1.0.4 ; extra == 'full'
|
|
241
240
|
Requires-Dist: dash-daq >=0.5.0 ; extra == 'full'
|
242
241
|
Requires-Dist: terminado >=0.12.1 ; extra == 'full'
|
243
242
|
Requires-Dist: tornado >=6.1.0 ; extra == 'full'
|
244
|
-
Requires-Dist: uvicorn[standard] >=0.
|
245
|
-
Requires-Dist: gunicorn >=
|
243
|
+
Requires-Dist: uvicorn[standard] >=0.29.0 ; extra == 'full'
|
244
|
+
Requires-Dist: gunicorn >=22.0.0 ; extra == 'full'
|
246
245
|
Requires-Dist: python-dotenv >=0.20.0 ; extra == 'full'
|
247
246
|
Requires-Dist: websockets >=11.0.3 ; extra == 'full'
|
248
|
-
Requires-Dist: fastapi >=0.
|
249
|
-
Requires-Dist: passlib >=1.7.4 ; extra == 'full'
|
247
|
+
Requires-Dist: fastapi >=0.111.0 ; extra == 'full'
|
250
248
|
Requires-Dist: fastapi-login >=1.7.2 ; extra == 'full'
|
251
|
-
Requires-Dist: python-multipart >=0.0.
|
249
|
+
Requires-Dist: python-multipart >=0.0.9 ; extra == 'full'
|
252
250
|
Requires-Dist: httpx >=0.24.1 ; extra == 'full'
|
253
251
|
Provides-Extra: gui
|
254
252
|
Requires-Dist: toga >=0.3.0-dev29 ; extra == 'gui'
|
@@ -260,8 +258,8 @@ Provides-Extra: setup
|
|
260
258
|
Provides-Extra: sql
|
261
259
|
Requires-Dist: numpy >=1.18.5 ; extra == 'sql'
|
262
260
|
Requires-Dist: pandas[parquet] >=2.0.1 ; extra == 'sql'
|
263
|
-
Requires-Dist: pyarrow >=
|
264
|
-
Requires-Dist: dask >=
|
261
|
+
Requires-Dist: pyarrow >=16.1.0 ; extra == 'sql'
|
262
|
+
Requires-Dist: dask[dataframe] >=2024.5.1 ; extra == 'sql'
|
265
263
|
Requires-Dist: pytz ; extra == 'sql'
|
266
264
|
Requires-Dist: joblib >=0.17.0 ; extra == 'sql'
|
267
265
|
Requires-Dist: SQLAlchemy >=2.0.5 ; extra == 'sql'
|
@@ -273,7 +271,7 @@ Requires-Dist: psycopg[binary] >=3.1.18 ; extra == 'sql'
|
|
273
271
|
Requires-Dist: PyMySQL >=0.9.0 ; extra == 'sql'
|
274
272
|
Requires-Dist: aiomysql >=0.0.21 ; extra == 'sql'
|
275
273
|
Requires-Dist: sqlalchemy-cockroachdb >=2.0.0 ; extra == 'sql'
|
276
|
-
Requires-Dist: duckdb
|
274
|
+
Requires-Dist: duckdb <0.10.0 ; extra == 'sql'
|
277
275
|
Requires-Dist: duckdb-engine >=0.9.2 ; extra == 'sql'
|
278
276
|
Requires-Dist: wheel >=0.34.2 ; extra == 'sql'
|
279
277
|
Requires-Dist: setuptools >=63.3.0 ; extra == 'sql'
|
@@ -48,7 +48,7 @@ meerschaum/actions/tag.py,sha256=SJf5qFW0ccLXjqlTdkK_0MCcrCMdg6xhYrhKdco0hdA,305
|
|
48
48
|
meerschaum/actions/uninstall.py,sha256=2fUd5ZK45VGGCI8V4NLmSnavdKjOv7cGM22x2WlTStw,6068
|
49
49
|
meerschaum/actions/upgrade.py,sha256=VQKyjCGioEF2FYbQmldHh21imDqApNl0xal0rhxzrJk,6302
|
50
50
|
meerschaum/actions/verify.py,sha256=tY5slGpHiWiE0v9TDnjbmxSKn86zBnu9WBpixUgKNQU,4885
|
51
|
-
meerschaum/api/__init__.py,sha256=
|
51
|
+
meerschaum/api/__init__.py,sha256=TfhjWIyg3AbG74LWhMBpcr487L_4Aak7YNO1rGIV5Vc,7410
|
52
52
|
meerschaum/api/_chain.py,sha256=h8-WXUGXX6AqzdALfsBC5uv0FkAcLdHJXCGzqzuq89k,875
|
53
53
|
meerschaum/api/_events.py,sha256=NrjiabEr7rmHMfxnX07DOGzr9sPiEbRkFqPjuA_8Zx8,1603
|
54
54
|
meerschaum/api/_oauth2.py,sha256=eH5r2rWuDmMHJPuukG0hj1E-LqtcDf5-lzp1YShOQOo,961
|
@@ -128,23 +128,23 @@ meerschaum/config/_default.py,sha256=DSbyVcAL55Xf8MJCTxpgF7ZXL-O9peeMEqL29WFfsJ4
|
|
128
128
|
meerschaum/config/_edit.py,sha256=CE8gumBiOtnZZdTATCLAZgUnhL04yJdReaNCrv1yuJc,8218
|
129
129
|
meerschaum/config/_environment.py,sha256=Vv4DLDfc2vKLbCLsMvkQDj77K4kEvHKEBmUBo-wCrgo,4419
|
130
130
|
meerschaum/config/_formatting.py,sha256=RT_oU0OSfUkzeqbY5jvEJwuove_t9sP4MyUb1Px250U,6635
|
131
|
-
meerschaum/config/_jobs.py,sha256=
|
131
|
+
meerschaum/config/_jobs.py,sha256=ki3Wb3QejAXyJhbBfme21EBhEntiOa6Pynp5OMfffp0,1227
|
132
132
|
meerschaum/config/_patch.py,sha256=21N30q1ANmWMDQ-2RUjpMx7KafWfPQ3lKx9rrMqg1s4,1526
|
133
|
-
meerschaum/config/_paths.py,sha256=
|
133
|
+
meerschaum/config/_paths.py,sha256=TihDGA6IQou3ms1xKYHmRTU48kOflqV5ZOMguG25NM4,8154
|
134
134
|
meerschaum/config/_preprocess.py,sha256=-AEA8m_--KivZwTQ1sWN6LTn5sio_fUr2XZ51BO6wLs,1220
|
135
135
|
meerschaum/config/_read_config.py,sha256=WFZKIXZMDe_ca0ES7ivgM_mnwShvFxLdoeisT_X5-h0,14720
|
136
136
|
meerschaum/config/_shell.py,sha256=s74cmJl8NrhM_Y1cB_P41_JDUYXV0g4WXnKFZWMtnrY,3551
|
137
137
|
meerschaum/config/_sync.py,sha256=oK2ZujO2T1he08BXCFyiniBUevNGWSQKXLcS_jRv_7Y,4155
|
138
|
-
meerschaum/config/_version.py,sha256=
|
138
|
+
meerschaum/config/_version.py,sha256=2-cyfpj01b8gfsTjUSjwd1-HjDjJ9lsq--ZPCqI2ZgA,74
|
139
139
|
meerschaum/config/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
140
140
|
meerschaum/config/stack/__init__.py,sha256=c_WdTSejVdj8lqSE_pK5MhIBkHoftiZWDuEuB9dmk2I,9007
|
141
141
|
meerschaum/config/stack/grafana/__init__.py,sha256=LNXQw2FvHKrD68RDhqDmi2wJjAHaKw9IWx8rNuyWEPo,2010
|
142
142
|
meerschaum/config/stack/mosquitto/__init__.py,sha256=-OwOjq8KiBoSH_pmgCAAF3Dp3CRD4KgAEdimZSadROs,186
|
143
143
|
meerschaum/config/stack/mosquitto/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
144
144
|
meerschaum/config/stack/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
145
|
-
meerschaum/config/static/__init__.py,sha256=
|
145
|
+
meerschaum/config/static/__init__.py,sha256=zsSq54OkLqjfG_QGyH6zXzZnoaGpDyjmV0OCvbygFr8,4474
|
146
146
|
meerschaum/connectors/Connector.py,sha256=cJKinmk7eWZwCBvtX4H9r66macTZOY1qjxR7JUEmDmg,6381
|
147
|
-
meerschaum/connectors/__init__.py,sha256=
|
147
|
+
meerschaum/connectors/__init__.py,sha256=OCNfIEeuom6g7GOO3xj37YAuxLOesGCZ-VrcltyHsSY,12071
|
148
148
|
meerschaum/connectors/parse.py,sha256=gidA2jvOLTvEeL5hM9JjcUwkMRBadUhd4IfA5Jy1tgg,4044
|
149
149
|
meerschaum/connectors/poll.py,sha256=gIY9TvFBqMvMNQvR0O2No7koLLz2PjfExBr_Dsosgpg,7363
|
150
150
|
meerschaum/connectors/api/APIConnector.py,sha256=pj-RncLhDUEBK7R4tByH6nrxZWU8zxGVOS2Wyik36zs,4355
|
@@ -160,15 +160,15 @@ meerschaum/connectors/api/_uri.py,sha256=h4Gj63f0q2V-TNMd8aAkQZMIj_-pA6uGacg_RNE
|
|
160
160
|
meerschaum/connectors/api/_users.py,sha256=kzb7ENgXwQ19OJYKOuuWzx2rwVuUZCly9dTnyvVuT2Q,5275
|
161
161
|
meerschaum/connectors/plugin/PluginConnector.py,sha256=aQ1QaB7MordCFimZqoGLb0R12PfDUN_nWks2J5mzeAs,2084
|
162
162
|
meerschaum/connectors/plugin/__init__.py,sha256=pwF7TGY4WNz2_HaVdmK4rPQ9ZwTOEuPHgzOqsGcoXJw,198
|
163
|
-
meerschaum/connectors/sql/SQLConnector.py,sha256=
|
163
|
+
meerschaum/connectors/sql/SQLConnector.py,sha256=QvsFgAv2NAUdsJrcNYZIkQ9x_ow5JRe4Ie_UgSrDz3M,11709
|
164
164
|
meerschaum/connectors/sql/__init__.py,sha256=xwSYhYuketTXhQLXyD9pZ0NNBPboW5Oqv9zrKfjx0Ic,175
|
165
165
|
meerschaum/connectors/sql/_cli.py,sha256=XaWjWZzGIfhMiYoXAs2FrwHUGNyZpxIzH4g4xugLKsw,4123
|
166
|
-
meerschaum/connectors/sql/_create_engine.py,sha256=
|
166
|
+
meerschaum/connectors/sql/_create_engine.py,sha256=vPVwR3cpfcQm0aW9xo_DUWA3gMdlkuB0wJ8JoTpRYD0,10396
|
167
167
|
meerschaum/connectors/sql/_fetch.py,sha256=NYYWDoEd-aGIS337KwH-D9_3KVWVCZOHAspGLfdEuUE,13086
|
168
|
-
meerschaum/connectors/sql/_instance.py,sha256=
|
169
|
-
meerschaum/connectors/sql/_pipes.py,sha256=
|
168
|
+
meerschaum/connectors/sql/_instance.py,sha256=r_S96vzSuKnBVGROSKQAPl-DnFnOOEPUkz1KFDFPHFQ,6509
|
169
|
+
meerschaum/connectors/sql/_pipes.py,sha256=WruMoLGMckUIardNtYzC7P0gavaz_HVlDb-IMv3pF9s,101357
|
170
170
|
meerschaum/connectors/sql/_plugins.py,sha256=OsCmDlZKyJnY77QAWghmpuXR0z_CmFq5uHpZK7Cj-ZI,8321
|
171
|
-
meerschaum/connectors/sql/_sql.py,sha256=
|
171
|
+
meerschaum/connectors/sql/_sql.py,sha256=553BTPtvnnLMERYK8IcxR4CS3R4Sq7id-5hbApOEsIU,34199
|
172
172
|
meerschaum/connectors/sql/_uri.py,sha256=0BrhQtqQdzg9mR04gWBZINs_BbPFtSlTECXT_TCUwik,3460
|
173
173
|
meerschaum/connectors/sql/_users.py,sha256=JkD6lKYJO8JVnpVySMqPM20NWUr-XzD_JO-lLMcAD_c,10100
|
174
174
|
meerschaum/connectors/sql/tools.py,sha256=jz8huOaRCwGlYdtGfAqAh7SoK8uydYBrasKQba9FT38,187
|
@@ -191,10 +191,10 @@ meerschaum/core/Pipe/_show.py,sha256=nG50y8eBT9TVuKkRgAKtNDNIxysJvMNxfu__lkL1F9k
|
|
191
191
|
meerschaum/core/Pipe/_sync.py,sha256=48qk1xvkcKOqfzzYf3QdA7ojsP80yrso1YU8QIGJxwE,28038
|
192
192
|
meerschaum/core/Pipe/_verify.py,sha256=KSnthUzImRLjt9fxyBaLvArqDuOLRpKBfk0tnseJClc,14262
|
193
193
|
meerschaum/core/Plugin/__init__.py,sha256=UXg64EvJPgI1PCxkY_KM02-ZmBm4FZpLPIQR_uSJJDc,137
|
194
|
-
meerschaum/core/User/_User.py,sha256=
|
194
|
+
meerschaum/core/User/_User.py,sha256=CApB7Y0QJL6S9QOCCfrG4SbPuPXJ9AsAYQ5pASMP_Aw,6527
|
195
195
|
meerschaum/core/User/__init__.py,sha256=lJ7beIZTG9sO4dAi3367fFBl17dXYEWHKi7HoaPlDyk,193
|
196
196
|
meerschaum/plugins/_Plugin.py,sha256=LpplVPviSskKqf_igl4yIsD72H2C9vaFPQgU7-93ytg,34039
|
197
|
-
meerschaum/plugins/__init__.py,sha256=
|
197
|
+
meerschaum/plugins/__init__.py,sha256=g-KFejGEqcfBukqqF13Vsj8TdjGo99nrv_Z6CB8-mCg,21866
|
198
198
|
meerschaum/utils/__init__.py,sha256=QrK1K9hIbPCRCM5k2nZGFqGnrqhA0Eh-iSmCU7FG6Cs,612
|
199
199
|
meerschaum/utils/_get_pipes.py,sha256=dlPckpYYyM0IwRZ2VL0u9DiEeYhr5Ho9gkzvWxzNVwI,11460
|
200
200
|
meerschaum/utils/dataframe.py,sha256=vxZ72ME7IWuadtktgjFZF5bc9fXW_0TuynjFlJljlLU,31955
|
@@ -203,18 +203,18 @@ meerschaum/utils/interactive.py,sha256=t-6jWozXSqL7lYGDHuwiOjTgr-UKhdcg61q_eR5mi
|
|
203
203
|
meerschaum/utils/misc.py,sha256=H26hLtCP8QHwXoHlvkxjWu6cPTwudDbbsbRkGw6ultg,43296
|
204
204
|
meerschaum/utils/networking.py,sha256=Sr_eYUGW8_UV9-k9LqRFf7xLtbUcsDucODyLCRsFRUc,1006
|
205
205
|
meerschaum/utils/pool.py,sha256=vkE42af4fjrTEJTxf6Ek3xGucm1MtEkpsSEiaVzNKHs,2655
|
206
|
-
meerschaum/utils/process.py,sha256=
|
206
|
+
meerschaum/utils/process.py,sha256=IHnUhX79XofHwMsOs1A_irLMa7i48xXB-GCL83MtZOY,7192
|
207
207
|
meerschaum/utils/prompt.py,sha256=0mBFbgi_l9rCou9UnC_6qKTHkqyl1Z_jSRzfmc0xRXM,16490
|
208
|
-
meerschaum/utils/schedule.py,sha256=
|
208
|
+
meerschaum/utils/schedule.py,sha256=coJm8s91DZjezv4h9dkgUkU3R_O7gWJUBojxjItkrCQ,10654
|
209
209
|
meerschaum/utils/sql.py,sha256=4sCNEpgUd6uFz6ySs4nnUMVaOT0YAvPM1ZlQYJTSF-0,46656
|
210
210
|
meerschaum/utils/threading.py,sha256=3N8JXPAnwqJiSjuQcbbJg3Rv9-CCUMJpeQRfKFR7MaA,2489
|
211
211
|
meerschaum/utils/typing.py,sha256=L05wOXfWdn_nJ0KnZVr-2zdMYcqjdyOW_7InT3xe6-s,2807
|
212
212
|
meerschaum/utils/warnings.py,sha256=0b5O2DBbhEAGnu6RAB1hlHSVmwL_hcR3EiMkExXmBJ0,6535
|
213
213
|
meerschaum/utils/yaml.py,sha256=vbCrFjdapKsZ9wRRaI9Ih8dVUwZ-KHpSzfGhRcpDBgQ,3162
|
214
|
-
meerschaum/utils/daemon/Daemon.py,sha256=
|
215
|
-
meerschaum/utils/daemon/FileDescriptorInterceptor.py,sha256=
|
216
|
-
meerschaum/utils/daemon/RotatingFile.py,sha256=
|
217
|
-
meerschaum/utils/daemon/__init__.py,sha256=
|
214
|
+
meerschaum/utils/daemon/Daemon.py,sha256=2e929fSd79TokURbgw5G3Cyopp_ztmV2_YxrJZYJB2Y,34414
|
215
|
+
meerschaum/utils/daemon/FileDescriptorInterceptor.py,sha256=1cn5nQYLImL-BHXlLoxN_TadgN7XmGRLl1b7xecYMPc,4544
|
216
|
+
meerschaum/utils/daemon/RotatingFile.py,sha256=qFGlpPVa_j1VCc_S6UtsAQ4nZyxGYLajFyXmAh-UfT4,23499
|
217
|
+
meerschaum/utils/daemon/__init__.py,sha256=I_ki51yml4vsh9OoH7BWTaz9SnATD8qM0i0fN3aUMn0,8375
|
218
218
|
meerschaum/utils/daemon/_names.py,sha256=Prf7xA2GWDbKR_9Xq9_5RTTIf9GNWY3Yt0s4tEU3JgM,4330
|
219
219
|
meerschaum/utils/dtypes/__init__.py,sha256=JR9PViJTzhukZhq0QoPIs73HOnXZZr8OmfhAAD4OAUA,6261
|
220
220
|
meerschaum/utils/dtypes/sql.py,sha256=IkEOyB63je-rCLHM6WwFzGbCerYk1zobL1cXkWqmTa4,14638
|
@@ -223,16 +223,16 @@ meerschaum/utils/formatting/_jobs.py,sha256=s1lVcdMkzNj5Bqw-GsUhcguUFtahi5nQ-kg1
|
|
223
223
|
meerschaum/utils/formatting/_pipes.py,sha256=wy0iWJFsFl3X2VloaiA_gp9Yx9w6tD3FQZvAQAqef4A,19492
|
224
224
|
meerschaum/utils/formatting/_pprint.py,sha256=tgrT3FyGyu5CWJYysqK3kX1xdZYorlbOk9fcU_vt9Qg,3096
|
225
225
|
meerschaum/utils/formatting/_shell.py,sha256=ox75O7VHDAiwzSvdMSJZhXLadvAqYJVeihU6WeZ2Ogc,3677
|
226
|
-
meerschaum/utils/packages/__init__.py,sha256=
|
227
|
-
meerschaum/utils/packages/_packages.py,sha256=
|
226
|
+
meerschaum/utils/packages/__init__.py,sha256=HEJYz_rceqljpyRFlnToLR6vc_b7r-2d2K8zh_th2lg,57185
|
227
|
+
meerschaum/utils/packages/_packages.py,sha256=EJ6nBHECMUj0UBeMZ0BWA5c1NlGPgvHE_37VcjPvUoo,7923
|
228
228
|
meerschaum/utils/packages/lazy_loader.py,sha256=VHnph3VozH29R4JnSSBfwtA5WKZYZQFT_GeQSShCnuc,2540
|
229
229
|
meerschaum/utils/venv/_Venv.py,sha256=sBnlmxHdAh2bx8btfVoD79-H9-cYsv5lP02IIXkyECs,3553
|
230
230
|
meerschaum/utils/venv/__init__.py,sha256=sj-n8scWH2NPDJGAxfpqzsYqVUt2jMEr-7Uq9G7YUNQ,23183
|
231
|
-
meerschaum-2.2.
|
232
|
-
meerschaum-2.2.
|
233
|
-
meerschaum-2.2.
|
234
|
-
meerschaum-2.2.
|
235
|
-
meerschaum-2.2.
|
236
|
-
meerschaum-2.2.
|
237
|
-
meerschaum-2.2.
|
238
|
-
meerschaum-2.2.
|
231
|
+
meerschaum-2.2.0rc3.dist-info/LICENSE,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
|
232
|
+
meerschaum-2.2.0rc3.dist-info/METADATA,sha256=FCRvolp0e892DTcU7zLQzgnG2csLBwyQXPNfR7c41-M,23903
|
233
|
+
meerschaum-2.2.0rc3.dist-info/NOTICE,sha256=OTA9Fcthjf5BRvWDDIcBC_xfLpeDV-RPZh3M-HQBRtQ,114
|
234
|
+
meerschaum-2.2.0rc3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
235
|
+
meerschaum-2.2.0rc3.dist-info/entry_points.txt,sha256=5YBVzibw-0rNA_1VjB16z5GABsOGf-CDhW4yqH8C7Gc,88
|
236
|
+
meerschaum-2.2.0rc3.dist-info/top_level.txt,sha256=bNoSiDj0El6buocix-FRoAtJOeq1qOF5rRm2u9i7Q6A,11
|
237
|
+
meerschaum-2.2.0rc3.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
238
|
+
meerschaum-2.2.0rc3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|