Skip to content

Commit d87dde8

Browse files
committed
refactoring migration commands to work with auto
1 parent 93fa700 commit d87dde8

File tree

14 files changed

+217
-118
lines changed

14 files changed

+217
-118
lines changed

piccolo/commands/app/new.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import sys
44
import typing as t
55

6+
import black
67
import click
78
import jinja2
89

@@ -34,8 +35,11 @@ def new_app(app_name: str):
3435
for filename, context in templates.items():
3536
with open(os.path.join(app_name, filename), "w") as f:
3637
template = JINJA_ENV.get_template(filename + ".jinja")
37-
rendered = template.render(**context)
38-
f.write(rendered)
38+
file_contents = template.render(**context)
39+
file_contents = black.format_str(
40+
file_contents, mode=black.FileMode(line_length=82)
41+
)
42+
f.write(file_contents)
3943

4044
migrations_folder_path = os.path.join(app_name, "piccolo_migrations")
4145
os.mkdir(migrations_folder_path)
Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
1+
"""
2+
Import all of the Tables subclasses in your app here, and register them with
3+
the APP_CONFIG.
4+
"""
5+
16
import os
27

3-
APP_NAME = '{{ app_name }}'
8+
from piccolo.conf.apps import AppConfig
49

5-
CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__))
610

7-
TABLES_MODULE = 'tables'
11+
CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__))
812

9-
MIGRATIONS_FOLDER = os.path.join(CURRENT_DIRECTORY, 'piccolo_migrations')
1013

11-
MIGRATION_DEPENDENCIES = []
14+
APP_CONFIG = AppConfig(
15+
app_name='{{ app_name }}',
16+
migrations_folder_path=os.path.join(CURRENT_DIRECTORY, 'piccolo_migrations'),
17+
table_classes=[],
18+
migration_dependencies=[],
19+
)

piccolo/commands/conf/new.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
import sys
44

5+
import black
56
import click
67
import jinja2
78

@@ -26,8 +27,12 @@ def new_piccolo_conf(engine_name: str, force: bool = False):
2627

2728
with open("piccolo_conf.py", "w") as f:
2829
template = JINJA_ENV.get_template("piccolo_conf.py.jinja")
29-
rendered = template.render(engine_name=engine_name)
30-
f.write(rendered)
30+
file_contents = template.render(engine_name=engine_name)
31+
file_contents = black.format_str(
32+
file_contents, mode=black.FileMode(line_length=82)
33+
)
34+
35+
f.write(file_contents)
3136

3237

3338
@click.option(
Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
from piccolo.conf.app import AppConfig
2-
1+
from piccolo.conf.apps import AppRegistry
32
{% if engine_name == 'postgres' %}
43
from piccolo.engine.postgres import PostgresEngine
54

@@ -14,9 +13,6 @@ DB = SQLiteEngine(path='project.sqlite')
1413
{% endif %}
1514

1615

17-
MIGRATIONS = []
18-
19-
20-
# A list of paths to piccolo apps, which are basically just Python packages
21-
# containing a piccolo_app.py file.
22-
APPS = AppConfig()
16+
# A list of paths to piccolo apps/
17+
# e.g. ['blog.piccolo_app']
18+
APP_REGISTRY = AppRegistry(apps=[])

piccolo/commands/migration/backwards.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import asyncio
2-
import os
32
import sys
43

54
import click
@@ -14,19 +13,23 @@ def __init__(self, app_name: str, migration_name: str):
1413
self.app_name = app_name
1514

1615
def run(self):
17-
config_modules = self.get_config_modules()
16+
app_modules = self.get_app_modules()
1817

1918
migration_modules = []
2019

21-
for config_module in config_modules:
22-
if self.get_app_name(config_module) == self.app_name:
20+
for app_module in app_modules:
21+
app_config = getattr(app_module, "APP_CONFIG")
22+
if app_config.app_name == self.app_name:
2323
migration_modules = self.get_migration_modules(
24-
os.path.dirname(config_module.__file__)
24+
app_config.migrations_folder_path
2525
)
2626
break
2727

2828
migration_ids = self.get_migration_ids(migration_modules)
2929

30+
if self.migration_name == "all":
31+
self.migration_name = migration_ids[0]
32+
3033
if self.migration_name not in migration_ids:
3134
print(
3235
f"Unrecognized migration name - must be one of {migration_ids}"
@@ -70,7 +73,8 @@ def run(self):
7073
@click.argument("migration_name")
7174
def backwards(migration_name: str, app_name: str):
7275
"""
73-
Undo migrations up to a specific migrations.
76+
Undo migrations up to a specific migrations. Specify a migration_name of
77+
'all' to undo all of the migrations.
7478
7579
- make sure the migration name is valid
7680
- work out which to undo, and in which order

piccolo/commands/migration/base.py

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from types import ModuleType
66
import typing as t
77

8+
from piccolo.conf.apps import AppConfig, AppRegistry
89
from piccolo.migrations.tables import Migration
910

1011

@@ -18,9 +19,8 @@ async def backwards() -> None:
1819
pass
1920

2021

21-
class ConfigModule(ModuleType):
22-
NAME: str
23-
DEPENDENCIES: t.List[str]
22+
class PiccoloAppModule(ModuleType):
23+
APP_CONFIG: AppConfig
2424

2525

2626
class BaseMigrationManager:
@@ -35,52 +35,53 @@ def create_migration_table(self) -> bool:
3535
return False
3636

3737
def _deduplicate(
38-
self, config_modules: t.List[ConfigModule]
39-
) -> t.List[ConfigModule]:
38+
self, config_modules: t.List[PiccoloAppModule]
39+
) -> t.List[PiccoloAppModule]:
4040
"""
4141
Remove all duplicates - just leaving the first instance.
4242
"""
4343
# Deduplicate, but preserve order - which is why set() isn't used.
4444
return list(dict([(c, None) for c in config_modules]).keys())
4545

46-
def import_config_modules(
47-
self, migrations: t.List[str]
48-
) -> t.List[ConfigModule]:
46+
def _import_app_modules(
47+
self, config_module_paths: t.List[str]
48+
) -> t.List[PiccoloAppModule]:
4949
"""
50-
Import all config modules, and all dependencies.
50+
Import all piccolo_app.py modules, and all dependencies.
5151
"""
5252
config_modules = []
5353

54-
for config_module_path in migrations:
54+
for config_module_path in config_module_paths:
5555
try:
5656
config_module = t.cast(
57-
ConfigModule, importlib.import_module(config_module_path)
57+
PiccoloAppModule,
58+
importlib.import_module(config_module_path),
5859
)
5960
except ImportError:
6061
raise Exception(f"Unable to import {config_module_path}")
61-
DEPENDENCIES = getattr(config_module, "DEPENDENCIES", [])
62-
dependency_config_modules = self.import_config_modules(
63-
DEPENDENCIES
62+
app_config: AppConfig = getattr(config_module, "APP_CONFIG")
63+
dependency_config_modules = self._import_app_modules(
64+
app_config.migration_dependencies
6465
)
6566
config_modules.extend(dependency_config_modules + [config_module])
6667

6768
return config_modules
6869

69-
def get_config_modules(self) -> t.List[ConfigModule]:
70+
def get_app_modules(self) -> t.List[PiccoloAppModule]:
7071
try:
71-
from piccolo_conf import MIGRATIONS
72+
from piccolo_conf import APP_REGISTRY
7273
except ImportError:
7374
raise Exception(
74-
"Unable to import MIGRATIONS from piccolo_conf - make sure "
75+
"Unable to import APP_REGISTRY from piccolo_conf - make sure "
7576
"it's in your path."
7677
)
7778

78-
config_modules = self.import_config_modules(MIGRATIONS)
79+
app_modules = self._import_app_modules(APP_REGISTRY.apps)
7980

8081
# Now deduplicate any dependencies
81-
config_modules = self._deduplicate(config_modules)
82+
app_modules = self._deduplicate(app_modules)
8283

83-
return config_modules
84+
return app_modules
8485

8586
def get_migration_modules(
8687
self, folder_path: str
@@ -93,7 +94,7 @@ def get_migration_modules(
9394
sys.path.insert(0, folder_path)
9495

9596
folder_contents = os.listdir(folder_path)
96-
excluded = ("__init__.py", "__pycache__", "config.py")
97+
excluded = ("__init__.py", "__pycache__")
9798
migration_names = [
9899
i.split(".py")[0]
99100
for i in folder_contents
@@ -116,7 +117,7 @@ def get_migration_ids(
116117
) -> t.List[str]:
117118
return sorted(list(migration_module_dict.keys()))
118119

119-
def get_app_name(self, config_module: ConfigModule) -> str:
120+
def get_app_name(self, config_module: PiccoloAppModule) -> str:
120121
# TODO - default to package name instead.
121122
app_name = getattr(config_module, "NAME", "").strip()
122123
return app_name

piccolo/commands/migration/check.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import os
2-
31
import click
42

53
from .base import BaseMigrationManager
@@ -18,14 +16,17 @@ def get_fixed_length_string(self, string: str, length=20) -> str:
1816
def run(self):
1917
print("Listing migrations ...")
2018

21-
config_modules = self.get_config_modules()
19+
app_modules = self.get_app_modules()
20+
21+
for app_module in app_modules:
22+
app_config = app_module.APP_CONFIG
2223

23-
for config_module in config_modules:
24-
app_name = self.get_app_name(config_module)
24+
app_name = app_config.app_name
2525
fixed_length_app_name = self.get_fixed_length_string(app_name)
2626

27-
path = os.path.dirname(config_module.__file__)
28-
migration_modules = self.get_migration_modules(path)
27+
migration_modules = self.get_migration_modules(
28+
app_config.migrations_folder_path
29+
)
2930
ids = self.get_migration_ids(migration_modules)
3031
for _id in ids:
3132
has_ran = (
Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22
import asyncio
3-
import os
43
import pprint
54
import typing as t
65

@@ -9,56 +8,63 @@
98
from piccolo.commands.migration.base import (
109
BaseMigrationManager,
1110
MigrationModule,
12-
ConfigModule,
11+
PiccoloAppModule,
1312
)
13+
from piccolo.conf.apps import AppConfig
1414
from piccolo.migrations.tables import Migration
15+
from piccolo.migrations.auto import MigrationManager
1516

1617

1718
class ForwardsMigrationManager(BaseMigrationManager):
18-
def run_migrations(self, config_modules: t.List[ConfigModule]) -> None:
19+
def __init__(self, app_name: str, *args, **kwargs):
20+
self.app_name = app_name
21+
22+
def run_migrations(self, app_modules: t.List[PiccoloAppModule]) -> None:
1923
already_ran = Migration.get_migrations_which_ran()
2024
print(f"Already ran:\n{already_ran}\n")
2125

22-
for config_module in config_modules:
23-
migrations_folder = os.path.dirname(config_module.__file__)
26+
for app_module in app_modules:
27+
app_config: AppConfig = getattr(app_module, "APP_CONFIG")
2428

2529
migration_modules: t.Dict[
2630
str, MigrationModule
27-
] = self.get_migration_modules(migrations_folder)
31+
] = self.get_migration_modules(app_config.migrations_folder_path)
2832

2933
ids = self.get_migration_ids(migration_modules)
3034
print(f"Migration ids = {ids}")
3135

32-
app_name = self.get_app_name(config_module)
33-
3436
havent_run = sorted(set(ids) - set(already_ran))
3537
for _id in havent_run:
3638
migration_module = migration_modules[_id]
37-
asyncio.run(migration_module.forwards())
39+
response = asyncio.run(migration_module.forwards())
40+
41+
if isinstance(response, MigrationManager):
42+
asyncio.run(response.run())
3843

3944
print(f"Ran {_id}")
4045
Migration.insert().add(
41-
Migration(name=_id, app_name=app_name)
46+
Migration(name=_id, app_name=self.app_name)
4247
).run_sync()
4348

4449
def run(self):
4550
print("Running migrations ...")
4651
self.create_migration_table()
4752

48-
config_modules = self.get_config_modules()
53+
app_modules = self.get_app_modules()
4954

5055
print("Config Modules:")
51-
pprint.pprint(config_modules)
56+
pprint.pprint(app_modules)
5257
print("\n")
5358

54-
self.run_migrations(config_modules)
59+
self.run_migrations(app_modules)
5560

5661

5762
@click.command()
58-
def forwards():
63+
@click.argument("app_name")
64+
def forwards(app_name: str):
5965
"""
6066
Runs any migrations which haven't been run yet, or up to a specific
6167
migration.
6268
"""
63-
manager = ForwardsMigrationManager()
69+
manager = ForwardsMigrationManager(app_name=app_name)
6470
manager.run()

0 commit comments

Comments
 (0)