macrostrat.database 4.1.1__tar.gz → 4.2.0__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.
Files changed (18) hide show
  1. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/PKG-INFO +1 -1
  2. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/__init__.py +1 -4
  3. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/query.py +24 -0
  4. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/utils.py +36 -30
  5. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/pyproject.toml +1 -1
  6. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/.DS_Store +0 -0
  7. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/compat.py +0 -0
  8. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/mapper/__init__.py +0 -0
  9. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/mapper/base.py +0 -0
  10. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/mapper/cache.py +0 -0
  11. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/mapper/utils.py +0 -0
  12. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/postgresql.py +0 -0
  13. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/transfer/__init__.py +0 -0
  14. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/transfer/dump_database.py +0 -0
  15. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/transfer/move_tables.py +0 -0
  16. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/transfer/restore_database.py +0 -0
  17. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/transfer/stream_utils.py +0 -0
  18. {macrostrat_database-4.1.1 → macrostrat_database-4.2.0}/macrostrat/database/transfer/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: macrostrat.database
3
- Version: 4.1.1
3
+ Version: 4.2.0
4
4
  Summary: A SQLAlchemy-based database toolkit.
5
5
  Author: Daven Quinn
6
6
  Author-email: Daven Quinn <dev@davenquinn.com>
@@ -12,9 +12,9 @@ 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
-
16
15
  from .mapper import DatabaseMapper
17
16
  from .postgresql import on_conflict, prefix_inserts # noqa
17
+ from .query import run_fixtures, run_query, run_sql, execute # noqa
18
18
  from .utils import ( # noqa
19
19
  create_database,
20
20
  create_engine,
@@ -23,9 +23,6 @@ from .utils import ( # noqa
23
23
  get_dataframe,
24
24
  get_or_create,
25
25
  reflect_table,
26
- run_fixtures,
27
- run_query,
28
- run_sql,
29
26
  )
30
27
 
31
28
  metadata = MetaData()
@@ -595,3 +595,27 @@ def run_sql(*args, **kwargs):
595
595
  if kwargs.pop("yield_results", False):
596
596
  return res
597
597
  return list(res)
598
+
599
+
600
+ def execute(connectable, sql, params=None, stop_on_error=False, **kwargs):
601
+ output_file = kwargs.pop("output_file", None)
602
+ output_mode = kwargs.pop("output_mode", None)
603
+ sql = format(sql, strip_comments=True).strip()
604
+ if sql == "":
605
+ return
606
+ try:
607
+ connectable.begin()
608
+ res = connectable.execute(text(sql), params=params)
609
+ if hasattr(connectable, "commit"):
610
+ connectable.commit()
611
+ pretty_print(sql, dim=True, file=output_file, mode=output_mode)
612
+ return res
613
+ except (ProgrammingError, IntegrityError) as err:
614
+ if hasattr(connectable, "rollback"):
615
+ connectable.rollback()
616
+ _print_error(sql, dim=True, file=output_file, mode=output_mode)
617
+ if stop_on_error:
618
+ return
619
+ finally:
620
+ if hasattr(connectable, "close"):
621
+ connectable.close()
@@ -1,5 +1,7 @@
1
+ import warnings
1
2
  from contextlib import contextmanager
2
3
  from time import sleep
4
+ from uuid import uuid4
3
5
 
4
6
  from click import echo
5
7
  from sqlalchemy import MetaData
@@ -8,19 +10,16 @@ from sqlalchemy import text
8
10
  from sqlalchemy.engine import Engine
9
11
  from sqlalchemy.engine.url import make_url
10
12
  from sqlalchemy.exc import (
11
- IntegrityError,
12
13
  OperationalError,
13
- ProgrammingError,
14
14
  )
15
15
  from sqlalchemy.orm import sessionmaker
16
16
  from sqlalchemy.schema import Table
17
17
  from sqlalchemy.sql.elements import ClauseElement
18
18
  from sqlalchemy_utils import create_database as _create_database
19
19
  from sqlalchemy_utils import database_exists, drop_database
20
- from sqlparse import format
21
20
 
22
21
  from macrostrat.utils import cmd, get_logger
23
- from .query import get_sql_text
22
+ from .query import get_sql_text, execute # noqa
24
23
 
25
24
  log = get_logger(__name__)
26
25
 
@@ -46,30 +45,6 @@ def db_session(engine):
46
45
  return factory()
47
46
 
48
47
 
49
- def execute(connectable, sql, params=None, stop_on_error=False, **kwargs):
50
- output_file = kwargs.pop("output_file", None)
51
- output_mode = kwargs.pop("output_mode", None)
52
- sql = format(sql, strip_comments=True).strip()
53
- if sql == "":
54
- return
55
- try:
56
- connectable.begin()
57
- res = connectable.execute(text(sql), params=params)
58
- if hasattr(connectable, "commit"):
59
- connectable.commit()
60
- pretty_print(sql, dim=True, file=output_file, mode=output_mode)
61
- return res
62
- except (ProgrammingError, IntegrityError) as err:
63
- if hasattr(connectable, "rollback"):
64
- connectable.rollback()
65
- _print_error(sql, dim=True, file=output_file, mode=output_mode)
66
- if stop_on_error:
67
- return
68
- finally:
69
- if hasattr(connectable, "close"):
70
- connectable.close()
71
-
72
-
73
48
  def get_or_create(session, model, defaults=None, **kwargs):
74
49
  """
75
50
  Get an instance of a model, or create it if it doesn't
@@ -97,9 +72,13 @@ def get_db_model(db, model_name: str):
97
72
 
98
73
 
99
74
  @contextmanager
100
- def temp_database(conn_string, drop=True, ensure_empty=False):
75
+ def temporary_database(
76
+ conn_string, *, drop=True, ensure_empty=False, exists_ok=True, template=None
77
+ ):
101
78
  """Create a temporary database and tear it down after tests."""
102
- create_database(conn_string, exists_ok=True, replace=ensure_empty)
79
+ create_database(
80
+ conn_string, exists_ok=exists_ok, replace=ensure_empty, template=template
81
+ )
103
82
  try:
104
83
  engine = create_engine(conn_string)
105
84
  yield engine
@@ -109,6 +88,33 @@ def temp_database(conn_string, drop=True, ensure_empty=False):
109
88
  drop_database(conn_string)
110
89
 
111
90
 
91
+ @contextmanager
92
+ def temp_database(*args, **kwargs):
93
+ warnings.warn(
94
+ "temp_database is deprecated, use temporary_database instead",
95
+ DeprecationWarning,
96
+ )
97
+ with temporary_database(*args, **kwargs) as engine:
98
+ yield engine
99
+
100
+
101
+ @contextmanager
102
+ def template_database(engine: Engine, *, name: str = None):
103
+ """Create a temporary template database using an existing database as a template."""
104
+ db_name = engine.url.database
105
+ template_db_name = name
106
+ if name is None:
107
+ uid = str(uuid4())[:8]
108
+ template_db_name = db_name + "_template_" + uid
109
+ # Close connection to the database so we can create a new one based on the template
110
+ new_db_url = engine.url.set(database=template_db_name)
111
+ engine.dispose()
112
+ with temporary_database(
113
+ new_db_url, drop=True, exists_ok=False, template=db_name
114
+ ) as engine:
115
+ yield engine
116
+
117
+
112
118
  def create_database(url, **kwargs):
113
119
  """Create a database if it doesn't exist.
114
120
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "macrostrat.database"
3
- version = "4.1.1"
3
+ version = "4.2.0"
4
4
  description = "A SQLAlchemy-based database toolkit."
5
5
  authors = [{ name = "Daven Quinn", email = "dev@davenquinn.com" }]
6
6
  requires-python = ">=3.10,<4"