spark-sql-migrations 0.0.2__tar.gz → 0.0.4__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.
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/PKG-INFO +10 -7
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/setup.py +10 -7
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations/__init__.py +2 -3
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations/spark_sql/spark_sql.py +20 -6
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations.egg-info/PKG-INFO +10 -7
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations.egg-info/SOURCES.txt +0 -1
- spark_sql_migrations-0.0.2/spark_sql_migrations/custom_logging.py +0 -78
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/LICENSE +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/MANIFEST.in +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/backend_shim.py +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/setup.cfg +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations/migration_templates/default_migration_template.sql +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations/migrations_initial/first_01_intial_create_cat_dbr_only.sql +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations/migrations_initial/first_02_intial_create_schema_all.sql +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations/migrations_initial/first_03_intial_create_state_table_all.sql +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations/py.typed +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations/spark_sql/__init__.py +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations/spark_utils.py +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations.egg-info/dependency_links.txt +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations.egg-info/entry_points.txt +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations.egg-info/namespace_packages.txt +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations.egg-info/requires.txt +0 -0
- {spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spark_sql_migrations
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Chained, idempotent SQL migrations for Spark and Databricks.
|
|
5
5
|
Home-page: https://github.com/mcjug2015/spark_sql_migrations
|
|
6
6
|
Author: Victor Semenov
|
|
@@ -81,10 +81,12 @@ Migrations come from two different owners, and they behave differently:
|
|
|
81
81
|
| **what** | catalog, schema, `_spark_migrations_version` table | your tables and columns |
|
|
82
82
|
| **where** | `spark_sql_migrations/migrations_initial/` | `all_spark_migrations/`, `dbr_only_migrations/` |
|
|
83
83
|
| **selected by** | filename suffix — `_all.sql` everywhere, `_dbr_only.sql` on Databricks | the `prev_revision_id` chain |
|
|
84
|
-
| **when applied** |
|
|
84
|
+
| **when applied** | until the version table exists | once, then recorded |
|
|
85
85
|
|
|
86
|
-
The bootstrap chain is
|
|
87
|
-
|
|
86
|
+
The bootstrap chain is applied on every run until `_spark_migrations_version` exists, and
|
|
87
|
+
skipped from then on. A run that fails partway through bootstrapping replays it, so it must
|
|
88
|
+
still be idempotent. Your own chains are applied once each and their head revision is
|
|
89
|
+
written to the version table.
|
|
88
90
|
|
|
89
91
|
## Laying out your chains
|
|
90
92
|
|
|
@@ -106,9 +108,10 @@ Choose deliberately. SQL that only Databricks understands must not live in
|
|
|
106
108
|
spark-sql-migrations run --cat spark_catalog --schema default --migrations-dir path/to/migrations
|
|
107
109
|
```
|
|
108
110
|
|
|
109
|
-
The command configures logging via `
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
The command configures logging via `logging.basicConfig()`, so each applied migration is
|
|
112
|
+
logged to stderr at INFO. It leaves an already-configured root logger alone, and every
|
|
113
|
+
other entry point into this library inherits the host application's logging untouched.
|
|
114
|
+
The command needs a Spark flavour installed; it
|
|
112
115
|
fails to import on a bare install. `python -m spark_sql_migrations.spark_sql.spark_sql`
|
|
113
116
|
is equivalent.
|
|
114
117
|
|
|
@@ -82,10 +82,12 @@ Migrations come from two different owners, and they behave differently:
|
|
|
82
82
|
| **what** | catalog, schema, `_spark_migrations_version` table | your tables and columns |
|
|
83
83
|
| **where** | `spark_sql_migrations/migrations_initial/` | `all_spark_migrations/`, `dbr_only_migrations/` |
|
|
84
84
|
| **selected by** | filename suffix — `_all.sql` everywhere, `_dbr_only.sql` on Databricks | the `prev_revision_id` chain |
|
|
85
|
-
| **when applied** |
|
|
85
|
+
| **when applied** | until the version table exists | once, then recorded |
|
|
86
86
|
|
|
87
|
-
The bootstrap chain is
|
|
88
|
-
|
|
87
|
+
The bootstrap chain is applied on every run until `_spark_migrations_version` exists, and
|
|
88
|
+
skipped from then on. A run that fails partway through bootstrapping replays it, so it must
|
|
89
|
+
still be idempotent. Your own chains are applied once each and their head revision is
|
|
90
|
+
written to the version table.
|
|
89
91
|
|
|
90
92
|
## Laying out your chains
|
|
91
93
|
|
|
@@ -110,9 +112,10 @@ spark-sql-migrations run \
|
|
|
110
112
|
--migrations-dir path/to/migrations
|
|
111
113
|
```
|
|
112
114
|
|
|
113
|
-
The command configures logging via `
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
The command configures logging via `logging.basicConfig()`, so each applied migration is
|
|
116
|
+
logged to stderr at INFO. It leaves an already-configured root logger alone, and every
|
|
117
|
+
other entry point into this library inherits the host application's logging untouched.
|
|
118
|
+
The command needs a Spark flavour installed; it
|
|
116
119
|
fails to import on a bare install. `python -m spark_sql_migrations.spark_sql.spark_sql`
|
|
117
120
|
is equivalent.
|
|
118
121
|
|
|
@@ -251,5 +254,5 @@ Apache License 2.0 — see [LICENSE](LICENSE).
|
|
|
251
254
|
},
|
|
252
255
|
'python_requires': '>=3.10',
|
|
253
256
|
'url': 'https://github.com/mcjug2015/spark_sql_migrations',
|
|
254
|
-
'version': '0.0.
|
|
257
|
+
'version': '0.0.4',
|
|
255
258
|
})
|
|
@@ -2,7 +2,6 @@ import logging
|
|
|
2
2
|
|
|
3
3
|
# A library must not configure logging when it is imported. A NullHandler on the
|
|
4
4
|
# package root keeps our records off logging.lastResort while leaving every
|
|
5
|
-
# decision about handlers, levels and formats to the host application
|
|
6
|
-
#
|
|
7
|
-
# spark_sql_migrations.custom_logging.setup_logging() from its own entry point.
|
|
5
|
+
# decision about handlers, levels and formats to the host application, which
|
|
6
|
+
# configures logging from its own entry point.
|
|
8
7
|
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
|
@@ -5,7 +5,8 @@ Two kinds of migration exist, and they are owned by different parties:
|
|
|
5
5
|
* the *initial* chain and the new-migration template ship inside this package.
|
|
6
6
|
They bootstrap the catalog, the schema and the version table, are selected by
|
|
7
7
|
filename suffix (``_all.sql`` / ``_dbr_only.sql``) rather than by revision,
|
|
8
|
-
and are
|
|
8
|
+
and are applied on every run until the version table exists -- so a run that
|
|
9
|
+
failed partway through replays them, and they must be idempotent.
|
|
9
10
|
* the ``all_spark_migrations/`` and ``dbr_only_migrations/`` chains belong to
|
|
10
11
|
the consuming project. The caller passes their parent directory as
|
|
11
12
|
``migrations_root``; each chain is walked from its root via
|
|
@@ -24,7 +25,6 @@ from dataclasses import dataclass
|
|
|
24
25
|
from jinja2 import Environment, FileSystemLoader, PackageLoader, select_autoescape
|
|
25
26
|
from pyspark.sql.functions import col
|
|
26
27
|
|
|
27
|
-
from spark_sql_migrations import custom_logging
|
|
28
28
|
from spark_sql_migrations.spark_utils import get_spark, is_dbr
|
|
29
29
|
|
|
30
30
|
logger = logging.getLogger(__name__)
|
|
@@ -261,7 +261,11 @@ def record_revision(spark, cat: str, schema: str, migration_type: str, revision_
|
|
|
261
261
|
|
|
262
262
|
|
|
263
263
|
def migrate_w_rev(spark, output_folder, migrations_root, cat: str, schema: str, migration_type: str):
|
|
264
|
-
"""
|
|
264
|
+
"""
|
|
265
|
+
apply the migrations of one client chain that VERSION_TABLE hasn't recorded yet.
|
|
266
|
+
TODO XXX permit applying up to a revision below the head revision
|
|
267
|
+
TODO XXX add backwards migrations, permit migrating backwards
|
|
268
|
+
"""
|
|
265
269
|
migrations_dir = get_migrations_dir(migrations_root, migration_type)
|
|
266
270
|
unapplied = get_unapplied_migrations_list(spark, migrations_dir, migration_type, cat=cat, schema=schema)
|
|
267
271
|
|
|
@@ -285,7 +289,11 @@ def run_migrations(spark, cat, schema, output_folder, migrations_root):
|
|
|
285
289
|
os.makedirs(initial_output_folder, exist_ok=True)
|
|
286
290
|
os.makedirs(dbr_ouput_folder, exist_ok=True)
|
|
287
291
|
os.makedirs(all_spark_ouput_folder, exist_ok=True)
|
|
288
|
-
|
|
292
|
+
version_table = f"{cat}.{schema}.{VERSION_TABLE}"
|
|
293
|
+
if spark.catalog.tableExists(version_table):
|
|
294
|
+
logger.info(f"{version_table} already exists; skipping the initial migrations;")
|
|
295
|
+
else:
|
|
296
|
+
migrate_initial(spark, initial_output_folder, cat, schema)
|
|
289
297
|
if is_dbr():
|
|
290
298
|
migrate_w_rev(spark, dbr_ouput_folder, migrations_root, cat, schema, DBR_ONLY)
|
|
291
299
|
migrate_w_rev(spark, all_spark_ouput_folder, migrations_root, cat, schema, ALL_SPARK)
|
|
@@ -330,9 +338,15 @@ def cli(argv=None): # pragma: no cover
|
|
|
330
338
|
"""the `spark-sql-migrations` console command.
|
|
331
339
|
|
|
332
340
|
an application entry point, so unlike the rest of this package it configures
|
|
333
|
-
logging
|
|
341
|
+
logging. basicConfig is a no-op once the root logger has handlers, which keeps
|
|
342
|
+
this from clobbering a host application that got there first.
|
|
334
343
|
"""
|
|
335
|
-
|
|
344
|
+
logging.basicConfig(
|
|
345
|
+
level=logging.INFO,
|
|
346
|
+
format="%(levelname)s %(asctime)s %(name)s : %(message)s",
|
|
347
|
+
datefmt="%y/%m/%d %H:%M:%S",
|
|
348
|
+
)
|
|
349
|
+
logging.getLogger("py4j").setLevel(logging.ERROR)
|
|
336
350
|
kwargs = vars(build_parser().parse_args(argv))
|
|
337
351
|
func = kwargs.pop("func")
|
|
338
352
|
kwargs.pop("command")
|
{spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spark_sql_migrations
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Chained, idempotent SQL migrations for Spark and Databricks.
|
|
5
5
|
Home-page: https://github.com/mcjug2015/spark_sql_migrations
|
|
6
6
|
Author: Victor Semenov
|
|
@@ -81,10 +81,12 @@ Migrations come from two different owners, and they behave differently:
|
|
|
81
81
|
| **what** | catalog, schema, `_spark_migrations_version` table | your tables and columns |
|
|
82
82
|
| **where** | `spark_sql_migrations/migrations_initial/` | `all_spark_migrations/`, `dbr_only_migrations/` |
|
|
83
83
|
| **selected by** | filename suffix — `_all.sql` everywhere, `_dbr_only.sql` on Databricks | the `prev_revision_id` chain |
|
|
84
|
-
| **when applied** |
|
|
84
|
+
| **when applied** | until the version table exists | once, then recorded |
|
|
85
85
|
|
|
86
|
-
The bootstrap chain is
|
|
87
|
-
|
|
86
|
+
The bootstrap chain is applied on every run until `_spark_migrations_version` exists, and
|
|
87
|
+
skipped from then on. A run that fails partway through bootstrapping replays it, so it must
|
|
88
|
+
still be idempotent. Your own chains are applied once each and their head revision is
|
|
89
|
+
written to the version table.
|
|
88
90
|
|
|
89
91
|
## Laying out your chains
|
|
90
92
|
|
|
@@ -106,9 +108,10 @@ Choose deliberately. SQL that only Databricks understands must not live in
|
|
|
106
108
|
spark-sql-migrations run --cat spark_catalog --schema default --migrations-dir path/to/migrations
|
|
107
109
|
```
|
|
108
110
|
|
|
109
|
-
The command configures logging via `
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
The command configures logging via `logging.basicConfig()`, so each applied migration is
|
|
112
|
+
logged to stderr at INFO. It leaves an already-configured root logger alone, and every
|
|
113
|
+
other entry point into this library inherits the host application's logging untouched.
|
|
114
|
+
The command needs a Spark flavour installed; it
|
|
112
115
|
fails to import on a bare install. `python -m spark_sql_migrations.spark_sql.spark_sql`
|
|
113
116
|
is equivalent.
|
|
114
117
|
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
"""Opinionated logging configuration, for *applications* to opt into.
|
|
2
|
-
|
|
3
|
-
Importing spark_sql_migrations never configures logging: library modules take a plain
|
|
4
|
-
``logging.getLogger(__name__)`` and inherit whatever the host application set
|
|
5
|
-
up. An application that wants this format calls :func:`setup_logging` from its
|
|
6
|
-
own entry point -- never at import time, and never from library code, because
|
|
7
|
-
configuring the root logger is the application's decision to make.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import logging.config
|
|
11
|
-
import os
|
|
12
|
-
|
|
13
|
-
LOG_FILE_ENV_VAR = "SPARK_SQL_MIGRATIONS_LOG_FILE"
|
|
14
|
-
DEFAULT_LOG_FILENAME = "local_log.log"
|
|
15
|
-
|
|
16
|
-
FORMAT = "%(levelname)s %(asctime)s %(filename)s->%(funcName)s->%(lineno)d : %(message)s"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def get_log_file_path():
|
|
20
|
-
"""where the file handler writes.
|
|
21
|
-
|
|
22
|
-
resolved against the caller's cwd for the same reason as the spark warehouse
|
|
23
|
-
dir: a __file__-relative default would land inside site-packages once this
|
|
24
|
-
is installed from a wheel.
|
|
25
|
-
"""
|
|
26
|
-
return os.environ.get(LOG_FILE_ENV_VAR, os.path.join(os.getcwd(), DEFAULT_LOG_FILENAME))
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def build_config():
|
|
30
|
-
"""built per call, not a module constant: get_log_file_path() reads the
|
|
31
|
-
environment, and at module-import time the consumer hasn't set it yet."""
|
|
32
|
-
return {
|
|
33
|
-
"version": 1,
|
|
34
|
-
"disable_existing_loggers": False,
|
|
35
|
-
"formatters": {
|
|
36
|
-
"simple": {
|
|
37
|
-
"format": FORMAT,
|
|
38
|
-
"datefmt": "%y/%m/%d %H:%M:%S",
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
"handlers": {
|
|
42
|
-
"stdout": {
|
|
43
|
-
"class": "logging.StreamHandler",
|
|
44
|
-
"level": "INFO",
|
|
45
|
-
"formatter": "simple",
|
|
46
|
-
"stream": "ext://sys.stdout",
|
|
47
|
-
},
|
|
48
|
-
"stderr": {
|
|
49
|
-
"class": "logging.StreamHandler",
|
|
50
|
-
"level": "ERROR",
|
|
51
|
-
"formatter": "simple",
|
|
52
|
-
"stream": "ext://sys.stderr",
|
|
53
|
-
},
|
|
54
|
-
"file": {
|
|
55
|
-
"class": "logging.FileHandler",
|
|
56
|
-
"formatter": "simple",
|
|
57
|
-
"filename": get_log_file_path(),
|
|
58
|
-
"mode": "a",
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
"root": {"level": "DEBUG", "handlers": ["stderr", "stdout", "file"]},
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def is_logging_configured():
|
|
66
|
-
# Check if the root logger has any handlers explicitly assigned
|
|
67
|
-
return len(logging.getLogger().handlers) >= 3
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def setup_logging():
|
|
71
|
-
"""configure the root logger with our handlers; safe to call more than once.
|
|
72
|
-
|
|
73
|
-
for application entry points only -- see the module docstring.
|
|
74
|
-
"""
|
|
75
|
-
if not is_logging_configured():
|
|
76
|
-
logging.config.dictConfig(build_config())
|
|
77
|
-
logging.getLogger("py4j").setLevel(logging.ERROR)
|
|
78
|
-
return logging
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations/spark_sql/__init__.py
RENAMED
|
File without changes
|
{spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations/spark_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spark_sql_migrations-0.0.2 → spark_sql_migrations-0.0.4}/spark_sql_migrations.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|