tablemaster 2.1.8__tar.gz → 2.1.9__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.
- {tablemaster-2.1.8 → tablemaster-2.1.9}/PKG-INFO +14 -2
- {tablemaster-2.1.8 → tablemaster-2.1.9}/README.md +13 -1
- {tablemaster-2.1.8 → tablemaster-2.1.9}/pyproject.toml +1 -1
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/cli.py +9 -2
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/__init__.py +2 -1
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/diff.py +4 -2
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/init.py +8 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/loader.py +43 -1
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster.egg-info/PKG-INFO +14 -2
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tests/test_schema_core.py +100 -1
- {tablemaster-2.1.8 → tablemaster-2.1.9}/LICENSE +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/setup.cfg +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/__init__.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/__main__.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/config.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/database.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/feishu.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/gspread.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/local.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/apply.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/dialects/__init__.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/dialects/base.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/dialects/mysql.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/dialects/postgresql.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/dialects/tidb.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/introspect.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/models.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/plan.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/schema/pull.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/sync.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster/utils.py +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster.egg-info/SOURCES.txt +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster.egg-info/dependency_links.txt +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster.egg-info/entry_points.txt +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster.egg-info/requires.txt +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tablemaster.egg-info/top_level.txt +0 -0
- {tablemaster-2.1.8 → tablemaster-2.1.9}/tests/test_error_visibility.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tablemaster
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.9
|
|
4
4
|
Summary: tablemaster is a Python toolkit for moving and managing tabular data across databases, Feishu/Lark, Google Sheets, and local files with one consistent API.
|
|
5
5
|
Author-email: Livid <livid.su@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/ilivid/tablemaster
|
|
@@ -220,6 +220,8 @@ tablemaster schema apply mydb --cfg-path ./cfg.yaml
|
|
|
220
220
|
tablemaster schema pull mydb --cfg-path ./cfg.yaml
|
|
221
221
|
```
|
|
222
222
|
|
|
223
|
+
After `tablemaster init`, each `schema/<connection>/` directory includes `_ignore_tables.yaml` by default.
|
|
224
|
+
|
|
223
225
|
Example schema file:
|
|
224
226
|
|
|
225
227
|
```yaml
|
|
@@ -238,6 +240,16 @@ indexes:
|
|
|
238
240
|
unique: true
|
|
239
241
|
```
|
|
240
242
|
|
|
243
|
+
Ignore specific tables from schema diff by editing `_ignore_tables.yaml` (or `_ignore_tables.yml`) under `schema/<connection>/`:
|
|
244
|
+
|
|
245
|
+
```yaml
|
|
246
|
+
tables:
|
|
247
|
+
- ods_orders_archive
|
|
248
|
+
- tmp_legacy_users
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Tables listed in this file are excluded from schema comparison, so they do not produce `plan` actions or warnings.
|
|
252
|
+
|
|
241
253
|
## CLI
|
|
242
254
|
|
|
243
255
|
`tablemaster` now ships with a built-in CLI:
|
|
@@ -271,7 +283,7 @@ CLI command groups:
|
|
|
271
283
|
- `db query <sql>`: Run SQL with `--cfg-key`; use `--limit` to control stdout preview and `--output` to export full result as CSV.
|
|
272
284
|
- `local read <pattern>`: Read one local CSV/Excel match and print preview; use `--det-header/--no-det-header` to control header detection.
|
|
273
285
|
- `config list`: List top-level keys from config.
|
|
274
|
-
- `init`: Bootstrap `cfg.yaml
|
|
286
|
+
- `init`: Bootstrap `cfg.yaml`, `schema/<connection>/`, and `_ignore_tables.yaml` scaffold in current directory.
|
|
275
287
|
- `schema plan <connection>`: Compare YAML schema and live DB, print/apply-safe plan.
|
|
276
288
|
- `schema apply <connection>`: Execute DDL actions from generated or saved plan.
|
|
277
289
|
- `schema pull <connection>`: Generate YAML schema files from live DB tables.
|
|
@@ -185,6 +185,8 @@ tablemaster schema apply mydb --cfg-path ./cfg.yaml
|
|
|
185
185
|
tablemaster schema pull mydb --cfg-path ./cfg.yaml
|
|
186
186
|
```
|
|
187
187
|
|
|
188
|
+
After `tablemaster init`, each `schema/<connection>/` directory includes `_ignore_tables.yaml` by default.
|
|
189
|
+
|
|
188
190
|
Example schema file:
|
|
189
191
|
|
|
190
192
|
```yaml
|
|
@@ -203,6 +205,16 @@ indexes:
|
|
|
203
205
|
unique: true
|
|
204
206
|
```
|
|
205
207
|
|
|
208
|
+
Ignore specific tables from schema diff by editing `_ignore_tables.yaml` (or `_ignore_tables.yml`) under `schema/<connection>/`:
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
tables:
|
|
212
|
+
- ods_orders_archive
|
|
213
|
+
- tmp_legacy_users
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Tables listed in this file are excluded from schema comparison, so they do not produce `plan` actions or warnings.
|
|
217
|
+
|
|
206
218
|
## CLI
|
|
207
219
|
|
|
208
220
|
`tablemaster` now ships with a built-in CLI:
|
|
@@ -236,7 +248,7 @@ CLI command groups:
|
|
|
236
248
|
- `db query <sql>`: Run SQL with `--cfg-key`; use `--limit` to control stdout preview and `--output` to export full result as CSV.
|
|
237
249
|
- `local read <pattern>`: Read one local CSV/Excel match and print preview; use `--det-header/--no-det-header` to control header detection.
|
|
238
250
|
- `config list`: List top-level keys from config.
|
|
239
|
-
- `init`: Bootstrap `cfg.yaml
|
|
251
|
+
- `init`: Bootstrap `cfg.yaml`, `schema/<connection>/`, and `_ignore_tables.yaml` scaffold in current directory.
|
|
240
252
|
- `schema plan <connection>`: Compare YAML schema and live DB, print/apply-safe plan.
|
|
241
253
|
- `schema apply <connection>`: Execute DDL actions from generated or saved plan.
|
|
242
254
|
- `schema pull <connection>`: Generate YAML schema files from live DB tables.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tablemaster"
|
|
7
|
-
version = "2.1.
|
|
7
|
+
version = "2.1.9"
|
|
8
8
|
description = "tablemaster is a Python toolkit for moving and managing tabular data across databases, Feishu/Lark, Google Sheets, and local files with one consistent API."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -43,9 +43,10 @@ def _build_plan(
|
|
|
43
43
|
from .schema.dialects import get_dialect
|
|
44
44
|
from .schema.diff import generate_plan
|
|
45
45
|
from .schema.introspect import introspect_tables
|
|
46
|
-
from .schema.loader import load_schema_definitions
|
|
46
|
+
from .schema.loader import load_ignored_tables, load_schema_definitions
|
|
47
47
|
|
|
48
48
|
db_cfg = _load_named_cfg(cfg_path, connection)
|
|
49
|
+
ignored_tables = load_ignored_tables(connection=connection, root_dir=schema_dir)
|
|
49
50
|
desired = load_schema_definitions(connection=connection, root_dir=schema_dir, table=table)
|
|
50
51
|
actual = introspect_tables(
|
|
51
52
|
db_cfg,
|
|
@@ -53,7 +54,13 @@ def _build_plan(
|
|
|
53
54
|
schema_name=getattr(desired[0], 'schema_name', None) if desired else None,
|
|
54
55
|
)
|
|
55
56
|
dialect = get_dialect(getattr(db_cfg, 'db_type', 'mysql'))
|
|
56
|
-
plan = generate_plan(
|
|
57
|
+
plan = generate_plan(
|
|
58
|
+
connection_name=connection,
|
|
59
|
+
desired=desired,
|
|
60
|
+
actual=actual,
|
|
61
|
+
dialect=dialect,
|
|
62
|
+
ignored_tables=ignored_tables,
|
|
63
|
+
)
|
|
57
64
|
return db_cfg, plan
|
|
58
65
|
|
|
59
66
|
|
|
@@ -2,7 +2,7 @@ from .apply import ApplyResult, apply_plan
|
|
|
2
2
|
from .diff import generate_plan
|
|
3
3
|
from .init import init_scaffold
|
|
4
4
|
from .introspect import introspect_tables
|
|
5
|
-
from .loader import load_schema_definitions
|
|
5
|
+
from .loader import load_ignored_tables, load_schema_definitions
|
|
6
6
|
from .models import (
|
|
7
7
|
ActualColumn,
|
|
8
8
|
ActualTable,
|
|
@@ -25,6 +25,7 @@ __all__ = [
|
|
|
25
25
|
'Plan',
|
|
26
26
|
'ApplyResult',
|
|
27
27
|
'load_schema_definitions',
|
|
28
|
+
'load_ignored_tables',
|
|
28
29
|
'introspect_tables',
|
|
29
30
|
'generate_plan',
|
|
30
31
|
'render_plan',
|
|
@@ -58,10 +58,12 @@ def generate_plan(
|
|
|
58
58
|
desired: list[TableDef],
|
|
59
59
|
actual: list[ActualTable],
|
|
60
60
|
dialect: BaseDialect,
|
|
61
|
+
ignored_tables: set[str] | None = None,
|
|
61
62
|
) -> Plan:
|
|
62
63
|
plan = Plan(connection=connection_name)
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
ignored = set(ignored_tables or [])
|
|
65
|
+
desired_map = {t.table: t for t in desired if t.table not in ignored}
|
|
66
|
+
actual_map = {t.table: t for t in actual if t.table not in ignored}
|
|
65
67
|
|
|
66
68
|
for table_name, table_def in desired_map.items():
|
|
67
69
|
current = actual_map.get(table_name)
|
|
@@ -15,6 +15,10 @@ _CFG_TEMPLATE = """mydb:
|
|
|
15
15
|
db_type: mysql
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
+
_IGNORE_TABLES_TEMPLATE = """# Tables listed here are ignored by schema plan/apply compare.
|
|
19
|
+
tables: []
|
|
20
|
+
"""
|
|
21
|
+
|
|
18
22
|
|
|
19
23
|
def _is_db_entry(value) -> bool:
|
|
20
24
|
return isinstance(value, dict) and 'host' in value and 'database' in value
|
|
@@ -67,6 +71,10 @@ def init_scaffold(
|
|
|
67
71
|
if not keep_file.exists():
|
|
68
72
|
keep_file.write_text('', encoding='utf-8')
|
|
69
73
|
created_paths.append(str(keep_file))
|
|
74
|
+
ignore_file = conn_dir / '_ignore_tables.yaml'
|
|
75
|
+
if not ignore_file.exists():
|
|
76
|
+
ignore_file.write_text(_IGNORE_TABLES_TEMPLATE, encoding='utf-8')
|
|
77
|
+
created_paths.append(str(ignore_file))
|
|
70
78
|
|
|
71
79
|
return {
|
|
72
80
|
'cfg_path': str(cfg_file),
|
|
@@ -7,6 +7,8 @@ import yaml
|
|
|
7
7
|
|
|
8
8
|
from .models import ColumnDef, IndexDef, TableDef
|
|
9
9
|
|
|
10
|
+
IGNORE_TABLES_FILENAMES = {'_ignore_tables.yaml', '_ignore_tables.yml'}
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
def _coerce_default(value) -> Optional[str]:
|
|
12
14
|
if value is None:
|
|
@@ -61,6 +63,43 @@ def parse_table_file(path: Path) -> TableDef:
|
|
|
61
63
|
)
|
|
62
64
|
|
|
63
65
|
|
|
66
|
+
def _is_ignore_tables_file(path: Path) -> bool:
|
|
67
|
+
return path.name.lower() in IGNORE_TABLES_FILENAMES
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _parse_ignore_tables_file(path: Path) -> set[str]:
|
|
71
|
+
with path.open('r', encoding='utf-8') as f:
|
|
72
|
+
raw = yaml.safe_load(f) or {}
|
|
73
|
+
|
|
74
|
+
if isinstance(raw, dict):
|
|
75
|
+
tables = raw.get('tables', raw.get('ignore_tables', []))
|
|
76
|
+
elif isinstance(raw, list):
|
|
77
|
+
tables = raw
|
|
78
|
+
else:
|
|
79
|
+
raise ValueError(f'Ignore tables file root must be list/dict: {path}')
|
|
80
|
+
|
|
81
|
+
if not isinstance(tables, list):
|
|
82
|
+
raise ValueError(f'Ignore tables must be a list: {path}')
|
|
83
|
+
return {str(t).strip() for t in tables if str(t).strip()}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def load_ignored_tables(
|
|
87
|
+
connection: str,
|
|
88
|
+
root_dir: str | Path = 'schema',
|
|
89
|
+
) -> set[str]:
|
|
90
|
+
root = Path(root_dir).resolve()
|
|
91
|
+
conn_dir = root / connection
|
|
92
|
+
if not conn_dir.exists() or not conn_dir.is_dir():
|
|
93
|
+
raise FileNotFoundError(f'Schema directory not found: {conn_dir}')
|
|
94
|
+
|
|
95
|
+
files = sorted(conn_dir.rglob('*.yaml')) + sorted(conn_dir.rglob('*.yml'))
|
|
96
|
+
ignored: set[str] = set()
|
|
97
|
+
for file in files:
|
|
98
|
+
if _is_ignore_tables_file(file):
|
|
99
|
+
ignored.update(_parse_ignore_tables_file(file))
|
|
100
|
+
return ignored
|
|
101
|
+
|
|
102
|
+
|
|
64
103
|
def load_schema_definitions(
|
|
65
104
|
connection: str,
|
|
66
105
|
root_dir: str | Path = 'schema',
|
|
@@ -71,12 +110,15 @@ def load_schema_definitions(
|
|
|
71
110
|
if not conn_dir.exists() or not conn_dir.is_dir():
|
|
72
111
|
raise FileNotFoundError(f'Schema directory not found: {conn_dir}')
|
|
73
112
|
files = sorted(conn_dir.rglob('*.yaml')) + sorted(conn_dir.rglob('*.yml'))
|
|
113
|
+
ignore_tables = load_ignored_tables(connection=connection, root_dir=root_dir)
|
|
74
114
|
defs: list[TableDef] = []
|
|
75
115
|
for file in files:
|
|
116
|
+
if _is_ignore_tables_file(file):
|
|
117
|
+
continue
|
|
76
118
|
parsed = parse_table_file(file)
|
|
77
119
|
if table and parsed.table != table:
|
|
78
120
|
continue
|
|
79
121
|
defs.append(parsed)
|
|
80
|
-
if table and not defs:
|
|
122
|
+
if table and not defs and table not in ignore_tables:
|
|
81
123
|
raise FileNotFoundError(f'Table schema not found under {conn_dir}: {table}')
|
|
82
124
|
return defs
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tablemaster
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.9
|
|
4
4
|
Summary: tablemaster is a Python toolkit for moving and managing tabular data across databases, Feishu/Lark, Google Sheets, and local files with one consistent API.
|
|
5
5
|
Author-email: Livid <livid.su@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/ilivid/tablemaster
|
|
@@ -220,6 +220,8 @@ tablemaster schema apply mydb --cfg-path ./cfg.yaml
|
|
|
220
220
|
tablemaster schema pull mydb --cfg-path ./cfg.yaml
|
|
221
221
|
```
|
|
222
222
|
|
|
223
|
+
After `tablemaster init`, each `schema/<connection>/` directory includes `_ignore_tables.yaml` by default.
|
|
224
|
+
|
|
223
225
|
Example schema file:
|
|
224
226
|
|
|
225
227
|
```yaml
|
|
@@ -238,6 +240,16 @@ indexes:
|
|
|
238
240
|
unique: true
|
|
239
241
|
```
|
|
240
242
|
|
|
243
|
+
Ignore specific tables from schema diff by editing `_ignore_tables.yaml` (or `_ignore_tables.yml`) under `schema/<connection>/`:
|
|
244
|
+
|
|
245
|
+
```yaml
|
|
246
|
+
tables:
|
|
247
|
+
- ods_orders_archive
|
|
248
|
+
- tmp_legacy_users
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Tables listed in this file are excluded from schema comparison, so they do not produce `plan` actions or warnings.
|
|
252
|
+
|
|
241
253
|
## CLI
|
|
242
254
|
|
|
243
255
|
`tablemaster` now ships with a built-in CLI:
|
|
@@ -271,7 +283,7 @@ CLI command groups:
|
|
|
271
283
|
- `db query <sql>`: Run SQL with `--cfg-key`; use `--limit` to control stdout preview and `--output` to export full result as CSV.
|
|
272
284
|
- `local read <pattern>`: Read one local CSV/Excel match and print preview; use `--det-header/--no-det-header` to control header detection.
|
|
273
285
|
- `config list`: List top-level keys from config.
|
|
274
|
-
- `init`: Bootstrap `cfg.yaml
|
|
286
|
+
- `init`: Bootstrap `cfg.yaml`, `schema/<connection>/`, and `_ignore_tables.yaml` scaffold in current directory.
|
|
275
287
|
- `schema plan <connection>`: Compare YAML schema and live DB, print/apply-safe plan.
|
|
276
288
|
- `schema apply <connection>`: Execute DDL actions from generated or saved plan.
|
|
277
289
|
- `schema pull <connection>`: Generate YAML schema files from live DB tables.
|
|
@@ -5,12 +5,23 @@ import unittest
|
|
|
5
5
|
from tablemaster.schema.dialects.mysql import MySQLDialect
|
|
6
6
|
from tablemaster.schema.dialects.postgresql import PostgreSQLDialect
|
|
7
7
|
from tablemaster.schema.diff import generate_plan
|
|
8
|
-
from tablemaster.schema.
|
|
8
|
+
from tablemaster.schema.init import init_scaffold
|
|
9
|
+
from tablemaster.schema.loader import load_ignored_tables, load_schema_definitions
|
|
9
10
|
from tablemaster.schema.models import ActualColumn, ActualTable
|
|
10
11
|
from tablemaster.schema.pull import write_pulled_schema
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class SchemaCoreTests(unittest.TestCase):
|
|
15
|
+
def test_init_creates_ignore_tables_template(self):
|
|
16
|
+
with TemporaryDirectory() as td:
|
|
17
|
+
root = Path(td)
|
|
18
|
+
result = init_scaffold(base_dir=root)
|
|
19
|
+
ignore_path = root / 'schema' / 'mydb' / '_ignore_tables.yaml'
|
|
20
|
+
self.assertTrue(ignore_path.exists())
|
|
21
|
+
content = ignore_path.read_text(encoding='utf-8')
|
|
22
|
+
self.assertIn('tables: []', content)
|
|
23
|
+
self.assertIn(str(ignore_path), result['created_paths'])
|
|
24
|
+
|
|
14
25
|
def test_loader_reads_yaml(self):
|
|
15
26
|
with TemporaryDirectory() as td:
|
|
16
27
|
root = Path(td)
|
|
@@ -34,6 +45,40 @@ class SchemaCoreTests(unittest.TestCase):
|
|
|
34
45
|
self.assertEqual('orders', tables[0].table)
|
|
35
46
|
self.assertEqual('id', tables[0].columns[0].name)
|
|
36
47
|
|
|
48
|
+
def test_loader_reads_ignored_tables_file(self):
|
|
49
|
+
with TemporaryDirectory() as td:
|
|
50
|
+
root = Path(td)
|
|
51
|
+
schema_dir = root / 'schema' / 'mydb'
|
|
52
|
+
schema_dir.mkdir(parents=True, exist_ok=True)
|
|
53
|
+
(schema_dir / '_ignore_tables.yaml').write_text(
|
|
54
|
+
'\n'.join(
|
|
55
|
+
[
|
|
56
|
+
'tables:',
|
|
57
|
+
' - orders',
|
|
58
|
+
' - legacy_users',
|
|
59
|
+
]
|
|
60
|
+
),
|
|
61
|
+
encoding='utf-8',
|
|
62
|
+
)
|
|
63
|
+
(schema_dir / 'orders.yaml').write_text(
|
|
64
|
+
'\n'.join(
|
|
65
|
+
[
|
|
66
|
+
'table: orders',
|
|
67
|
+
'columns:',
|
|
68
|
+
' - name: id',
|
|
69
|
+
' type: BIGINT',
|
|
70
|
+
' primary_key: true',
|
|
71
|
+
' nullable: false',
|
|
72
|
+
]
|
|
73
|
+
),
|
|
74
|
+
encoding='utf-8',
|
|
75
|
+
)
|
|
76
|
+
ignored = load_ignored_tables(connection='mydb', root_dir=root / 'schema')
|
|
77
|
+
tables = load_schema_definitions(connection='mydb', root_dir=root / 'schema')
|
|
78
|
+
self.assertEqual({'orders', 'legacy_users'}, ignored)
|
|
79
|
+
self.assertEqual(1, len(tables))
|
|
80
|
+
self.assertEqual('orders', tables[0].table)
|
|
81
|
+
|
|
37
82
|
def test_diff_emits_add_column_and_warning(self):
|
|
38
83
|
with TemporaryDirectory() as td:
|
|
39
84
|
root = Path(td)
|
|
@@ -281,6 +326,60 @@ class SchemaCoreTests(unittest.TestCase):
|
|
|
281
326
|
plan = generate_plan('mydb', desired, actual, PostgreSQLDialect())
|
|
282
327
|
self.assertFalse(any(a.action == 'ALTER_COLUMN_DEFAULT' for a in plan.actions))
|
|
283
328
|
|
|
329
|
+
def test_diff_ignored_table_has_no_actions_or_warnings(self):
|
|
330
|
+
with TemporaryDirectory() as td:
|
|
331
|
+
root = Path(td)
|
|
332
|
+
schema_dir = root / 'schema' / 'mydb'
|
|
333
|
+
schema_dir.mkdir(parents=True, exist_ok=True)
|
|
334
|
+
(schema_dir / '_ignore_tables.yaml').write_text(
|
|
335
|
+
'\n'.join(
|
|
336
|
+
[
|
|
337
|
+
'tables:',
|
|
338
|
+
' - orders',
|
|
339
|
+
]
|
|
340
|
+
),
|
|
341
|
+
encoding='utf-8',
|
|
342
|
+
)
|
|
343
|
+
(schema_dir / 'orders.yaml').write_text(
|
|
344
|
+
'\n'.join(
|
|
345
|
+
[
|
|
346
|
+
'table: orders',
|
|
347
|
+
'columns:',
|
|
348
|
+
' - name: id',
|
|
349
|
+
' type: BIGINT',
|
|
350
|
+
' nullable: false',
|
|
351
|
+
]
|
|
352
|
+
),
|
|
353
|
+
encoding='utf-8',
|
|
354
|
+
)
|
|
355
|
+
desired = load_schema_definitions(connection='mydb', root_dir=root / 'schema')
|
|
356
|
+
ignored = load_ignored_tables(connection='mydb', root_dir=root / 'schema')
|
|
357
|
+
actual = [
|
|
358
|
+
ActualTable(
|
|
359
|
+
table='orders',
|
|
360
|
+
columns=[
|
|
361
|
+
ActualColumn(
|
|
362
|
+
name='id',
|
|
363
|
+
type='BIGINT',
|
|
364
|
+
nullable=True,
|
|
365
|
+
default=None,
|
|
366
|
+
comment=None,
|
|
367
|
+
),
|
|
368
|
+
ActualColumn(
|
|
369
|
+
name='legacy_col',
|
|
370
|
+
type='VARCHAR(32)',
|
|
371
|
+
nullable=True,
|
|
372
|
+
default=None,
|
|
373
|
+
comment=None,
|
|
374
|
+
),
|
|
375
|
+
],
|
|
376
|
+
indexes=[],
|
|
377
|
+
)
|
|
378
|
+
]
|
|
379
|
+
plan = generate_plan('mydb', desired, actual, MySQLDialect(), ignored_tables=ignored)
|
|
380
|
+
self.assertEqual([], plan.actions)
|
|
381
|
+
self.assertEqual([], plan.warnings)
|
|
382
|
+
|
|
284
383
|
|
|
285
384
|
if __name__ == '__main__':
|
|
286
385
|
unittest.main()
|
|
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
|
|
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
|
|
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
|