macrostrat.database 3.5.1__tar.gz → 3.5.2__tar.gz
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.
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/PKG-INFO +1 -1
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/__init__.py +25 -1
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/transfer/dump_database.py +1 -0
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/transfer/move_tables.py +1 -0
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/transfer/restore_database.py +1 -0
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/transfer/stream_utils.py +1 -0
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/transfer/utils.py +1 -1
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/utils.py +71 -46
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/pyproject.toml +1 -1
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/mapper/__init__.py +0 -0
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/mapper/base.py +0 -0
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/mapper/cache.py +0 -0
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/mapper/utils.py +0 -0
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/postgresql.py +0 -0
- {macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/transfer/__init__.py +0 -0
|
@@ -5,13 +5,14 @@ from typing import Optional, Union
|
|
|
5
5
|
|
|
6
6
|
from psycopg2.errors import InvalidSavepointSpecification
|
|
7
7
|
from psycopg2.sql import Identifier
|
|
8
|
-
from sqlalchemy import URL, MetaData, create_engine, inspect
|
|
8
|
+
from sqlalchemy import URL, Engine, MetaData, create_engine, inspect
|
|
9
9
|
from sqlalchemy.exc import IntegrityError, InternalError
|
|
10
10
|
from sqlalchemy.ext.compiler import compiles
|
|
11
11
|
from sqlalchemy.orm import Session, scoped_session, sessionmaker
|
|
12
12
|
from sqlalchemy.sql.expression import Insert
|
|
13
13
|
|
|
14
14
|
from macrostrat.utils import get_logger
|
|
15
|
+
|
|
15
16
|
from .mapper import DatabaseMapper
|
|
16
17
|
from .postgresql import on_conflict, prefix_inserts # noqa
|
|
17
18
|
from .utils import ( # noqa
|
|
@@ -184,6 +185,29 @@ class Database(object):
|
|
|
184
185
|
self.__inspector__ = inspect(self.engine)
|
|
185
186
|
return self.__inspector__
|
|
186
187
|
|
|
188
|
+
def refresh_schema(self, *, automap=None):
|
|
189
|
+
"""
|
|
190
|
+
Refresh the current database connection
|
|
191
|
+
|
|
192
|
+
- closes the session and flushes
|
|
193
|
+
- removes the inspector
|
|
194
|
+
|
|
195
|
+
If automap is True, will automap the database after refreshing.
|
|
196
|
+
If automap is False, will not automap the database after refreshing.
|
|
197
|
+
If automap is None, it will re-map the database if it was previously mapped.
|
|
198
|
+
"""
|
|
199
|
+
# Close the session
|
|
200
|
+
self.session.flush()
|
|
201
|
+
self.session.close()
|
|
202
|
+
# Remove the inspector
|
|
203
|
+
self.__inspector__ = None
|
|
204
|
+
|
|
205
|
+
if automap is None:
|
|
206
|
+
automap = self.mapper is not None
|
|
207
|
+
|
|
208
|
+
if automap:
|
|
209
|
+
self.automap()
|
|
210
|
+
|
|
187
211
|
def entity_names(self, **kwargs):
|
|
188
212
|
"""
|
|
189
213
|
Returns an iterator of names of *schema objects*
|
{macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/transfer/utils.py
RENAMED
|
@@ -5,7 +5,7 @@ from sqlalchemy.engine import Engine
|
|
|
5
5
|
from sqlalchemy.engine.url import URL
|
|
6
6
|
from sqlalchemy_utils import create_database, database_exists, drop_database
|
|
7
7
|
|
|
8
|
-
from macrostrat.utils import
|
|
8
|
+
from macrostrat.utils import ApplicationError, get_logger
|
|
9
9
|
|
|
10
10
|
console = Console()
|
|
11
11
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from contextlib import contextmanager
|
|
2
|
+
from enum import Enum
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
from re import search
|
|
5
|
+
from sys import stderr
|
|
4
6
|
from time import sleep
|
|
5
7
|
from typing import IO, Union
|
|
6
8
|
from warnings import warn
|
|
@@ -17,8 +19,8 @@ from sqlalchemy.exc import (
|
|
|
17
19
|
IntegrityError,
|
|
18
20
|
InternalError,
|
|
19
21
|
InvalidRequestError,
|
|
20
|
-
ProgrammingError,
|
|
21
22
|
OperationalError,
|
|
23
|
+
ProgrammingError,
|
|
22
24
|
)
|
|
23
25
|
from sqlalchemy.orm import sessionmaker
|
|
24
26
|
from sqlalchemy.schema import Table
|
|
@@ -46,23 +48,11 @@ def infer_is_sql_text(_string: str) -> bool:
|
|
|
46
48
|
if isinstance(_string, bytes):
|
|
47
49
|
_string = _string.decode("utf-8")
|
|
48
50
|
|
|
49
|
-
keywords = [
|
|
50
|
-
"SELECT",
|
|
51
|
-
"INSERT",
|
|
52
|
-
"UPDATE",
|
|
53
|
-
"CREATE",
|
|
54
|
-
"DROP",
|
|
55
|
-
"DELETE",
|
|
56
|
-
"ALTER",
|
|
57
|
-
"SET",
|
|
58
|
-
"GRANT",
|
|
59
|
-
"WITH",
|
|
60
|
-
]
|
|
61
51
|
lines = _string.split("\n")
|
|
62
52
|
if len(lines) > 1:
|
|
63
53
|
return True
|
|
64
54
|
_string = _string.lower()
|
|
65
|
-
for i in
|
|
55
|
+
for i in _sql_keywords:
|
|
66
56
|
if _string.strip().startswith(i.lower() + " "):
|
|
67
57
|
return True
|
|
68
58
|
return False
|
|
@@ -97,26 +87,40 @@ def get_dataframe(connectable, filename_or_query, **kwargs):
|
|
|
97
87
|
|
|
98
88
|
|
|
99
89
|
def pretty_print(sql, **kwargs):
|
|
90
|
+
"""Print and optionally summarize an SQL query"""
|
|
91
|
+
summarize = kwargs.pop("summarize", True)
|
|
92
|
+
if summarize:
|
|
93
|
+
sql = summarize_statement(sql)
|
|
94
|
+
secho(sql, **kwargs)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
_sql_keywords = [
|
|
98
|
+
"SELECT",
|
|
99
|
+
"INSERT",
|
|
100
|
+
"UPDATE",
|
|
101
|
+
"CREATE",
|
|
102
|
+
"DROP",
|
|
103
|
+
"DELETE",
|
|
104
|
+
"ALTER",
|
|
105
|
+
"SET",
|
|
106
|
+
"GRANT",
|
|
107
|
+
"WITH",
|
|
108
|
+
"NOTIFY",
|
|
109
|
+
"COPY",
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def summarize_statement(sql):
|
|
100
114
|
for line in sql.split("\n"):
|
|
101
|
-
for i in
|
|
102
|
-
"SELECT",
|
|
103
|
-
"INSERT",
|
|
104
|
-
"UPDATE",
|
|
105
|
-
"CREATE",
|
|
106
|
-
"DROP",
|
|
107
|
-
"DELETE",
|
|
108
|
-
"ALTER",
|
|
109
|
-
"SET",
|
|
110
|
-
"GRANT",
|
|
111
|
-
"WITH",
|
|
112
|
-
"NOTIFY",
|
|
113
|
-
"COPY",
|
|
114
|
-
]:
|
|
115
|
+
for i in _sql_keywords:
|
|
115
116
|
if not line.startswith(i):
|
|
116
117
|
continue
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
return line.split("(")[0].strip().rstrip(";").replace(" AS", "")
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class DevNull(object):
|
|
122
|
+
def write(self, *_):
|
|
123
|
+
pass
|
|
120
124
|
|
|
121
125
|
|
|
122
126
|
def get_sql_text(sql, interpret_as_file=None, echo_file_name=True):
|
|
@@ -235,6 +239,13 @@ def infer_has_server_binds(sql):
|
|
|
235
239
|
_default_statement_filter = lambda sql_text, params: True
|
|
236
240
|
|
|
237
241
|
|
|
242
|
+
class PrintMode(Enum):
|
|
243
|
+
NONE = "none"
|
|
244
|
+
ERRORS = "errors"
|
|
245
|
+
SUMMARY = "summary"
|
|
246
|
+
ALL = "all"
|
|
247
|
+
|
|
248
|
+
|
|
238
249
|
def _run_sql(connectable, sql, params=None, **kwargs):
|
|
239
250
|
"""
|
|
240
251
|
Internal function for running a query on a SQLAlchemy connectable,
|
|
@@ -251,6 +262,11 @@ def _run_sql(connectable, sql, params=None, **kwargs):
|
|
|
251
262
|
has_server_binds = kwargs.pop("has_server_binds", None)
|
|
252
263
|
ensure_single_query = kwargs.pop("ensure_single_query", False)
|
|
253
264
|
statement_filter = kwargs.pop("statement_filter", _default_statement_filter)
|
|
265
|
+
output_mode = kwargs.pop("output_mode", PrintMode.SUMMARY)
|
|
266
|
+
output_file = kwargs.pop("output_file", stderr)
|
|
267
|
+
|
|
268
|
+
if output_mode == PrintMode.NONE:
|
|
269
|
+
output_file = DevNull()
|
|
254
270
|
|
|
255
271
|
if stop_on_error:
|
|
256
272
|
raise_errors = True
|
|
@@ -283,6 +299,7 @@ def _run_sql(connectable, sql, params=None, **kwargs):
|
|
|
283
299
|
query = _render_query(query, connectable)
|
|
284
300
|
|
|
285
301
|
sql_text = str(query)
|
|
302
|
+
|
|
286
303
|
if isinstance(query, str):
|
|
287
304
|
sql_text = format(query, strip_comments=True).strip()
|
|
288
305
|
if sql_text == "":
|
|
@@ -293,8 +310,18 @@ def _run_sql(connectable, sql, params=None, **kwargs):
|
|
|
293
310
|
has_server_binds = infer_has_server_binds(sql_text)
|
|
294
311
|
|
|
295
312
|
should_run = statement_filter(sql_text, params)
|
|
313
|
+
|
|
314
|
+
# Shorten summary text for printing
|
|
315
|
+
if output_mode != PrintMode.ALL:
|
|
316
|
+
sql_text = summarize_statement(sql_text)
|
|
317
|
+
|
|
296
318
|
if not should_run:
|
|
297
|
-
|
|
319
|
+
secho(
|
|
320
|
+
sql_text,
|
|
321
|
+
dim=True,
|
|
322
|
+
strikethrough=True,
|
|
323
|
+
file=output_file,
|
|
324
|
+
)
|
|
298
325
|
continue
|
|
299
326
|
|
|
300
327
|
# This only does something for postgresql, but it's harmless to run it for other engines
|
|
@@ -318,7 +345,7 @@ def _run_sql(connectable, sql, params=None, **kwargs):
|
|
|
318
345
|
trans.commit()
|
|
319
346
|
elif hasattr(connectable, "commit"):
|
|
320
347
|
connectable.commit()
|
|
321
|
-
|
|
348
|
+
secho(sql_text, dim=True, file=output_file)
|
|
322
349
|
except Exception as err:
|
|
323
350
|
if trans is not None:
|
|
324
351
|
trans.rollback()
|
|
@@ -327,7 +354,7 @@ def _run_sql(connectable, sql, params=None, **kwargs):
|
|
|
327
354
|
if raise_errors or _should_raise_query_error(err):
|
|
328
355
|
raise err
|
|
329
356
|
|
|
330
|
-
_print_error(sql_text, err)
|
|
357
|
+
_print_error(sql_text, err, file=output_file)
|
|
331
358
|
finally:
|
|
332
359
|
set_wait_callback(None)
|
|
333
360
|
|
|
@@ -356,17 +383,18 @@ def _should_raise_query_error(err):
|
|
|
356
383
|
return False
|
|
357
384
|
|
|
358
385
|
|
|
359
|
-
def _print_error(sql_text, err):
|
|
386
|
+
def _print_error(sql_text, err, **kwargs):
|
|
360
387
|
if orig := getattr(err, "orig", None):
|
|
361
388
|
_err = str(orig)
|
|
362
389
|
else:
|
|
363
390
|
_err = str(err)
|
|
364
391
|
_err = _err.strip()
|
|
365
|
-
|
|
366
|
-
|
|
392
|
+
# Decide whether error should be dimmed
|
|
393
|
+
dim = kwargs.pop("dim", "already exists" in _err)
|
|
394
|
+
secho(sql_text, fg=None if dim else "red", dim=True, **kwargs)
|
|
367
395
|
if dim:
|
|
368
396
|
_err = " " + _err
|
|
369
|
-
secho(_err, fg="red", dim=dim)
|
|
397
|
+
secho(_err, fg="red", dim=dim, **kwargs)
|
|
370
398
|
log.error(err)
|
|
371
399
|
|
|
372
400
|
|
|
@@ -468,7 +496,9 @@ def run_sql(*args, **kwargs):
|
|
|
468
496
|
return list(res)
|
|
469
497
|
|
|
470
498
|
|
|
471
|
-
def execute(connectable, sql, params=None, stop_on_error=False):
|
|
499
|
+
def execute(connectable, sql, params=None, stop_on_error=False, **kwargs):
|
|
500
|
+
output_file = kwargs.pop("output_file", None)
|
|
501
|
+
output_mode = kwargs.pop("output_mode", None)
|
|
472
502
|
sql = format(sql, strip_comments=True).strip()
|
|
473
503
|
if sql == "":
|
|
474
504
|
return
|
|
@@ -477,17 +507,12 @@ def execute(connectable, sql, params=None, stop_on_error=False):
|
|
|
477
507
|
res = connectable.execute(text(sql), params=params)
|
|
478
508
|
if hasattr(connectable, "commit"):
|
|
479
509
|
connectable.commit()
|
|
480
|
-
pretty_print(sql, dim=True)
|
|
510
|
+
pretty_print(sql, dim=True, file=output_file, mode=output_mode)
|
|
481
511
|
return res
|
|
482
512
|
except (ProgrammingError, IntegrityError) as err:
|
|
483
|
-
err = str(err.orig).strip()
|
|
484
|
-
dim = "already exists" in err
|
|
485
513
|
if hasattr(connectable, "rollback"):
|
|
486
514
|
connectable.rollback()
|
|
487
|
-
|
|
488
|
-
if dim:
|
|
489
|
-
err = " " + err
|
|
490
|
-
secho(err, fg="red", dim=dim)
|
|
515
|
+
_print_error(sql, dim=True, file=output_file, mode=output_mode)
|
|
491
516
|
if stop_on_error:
|
|
492
517
|
return
|
|
493
518
|
finally:
|
|
@@ -3,7 +3,7 @@ authors = ["Daven Quinn <dev@davenquinn.com>"]
|
|
|
3
3
|
description = "A SQLAlchemy-based database toolkit."
|
|
4
4
|
name = "macrostrat.database"
|
|
5
5
|
packages = [{ include = "macrostrat" }]
|
|
6
|
-
version = "3.5.
|
|
6
|
+
version = "3.5.2"
|
|
7
7
|
|
|
8
8
|
[tool.poetry.dependencies]
|
|
9
9
|
GeoAlchemy2 = "^0.15.2"
|
{macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/mapper/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{macrostrat_database-3.5.1 → macrostrat_database-3.5.2}/macrostrat/database/transfer/__init__.py
RENAMED
|
File without changes
|