Skip to content

Commit 63287ed

Browse files
abrookinsclaude
andcommitted
Fix CLI async/sync transformation and execution pattern
Fixed the proper async/sync pattern for CLI commands: - CLI command functions are sync (required by Click) - Inner functions are async and called with run_async() wrapper - Proper imports to use async migrators in async CLI, sync in sync CLI - Fixed unasync transformation issues for CLI execution 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 865ef35 commit 63287ed

File tree

2 files changed

+117
-97
lines changed

2 files changed

+117
-97
lines changed

aredis_om/model/cli/migrate.py

Lines changed: 109 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
import click
66

7-
from aredis_om.model.migrations.schema_migrator import SchemaMigrator
8-
from aredis_om.settings import get_root_migrations_dir
7+
from ..migrations.schema_migrator import SchemaMigrator
8+
from ...settings import get_root_migrations_dir
99

1010

1111
def run_async(coro):
@@ -25,29 +25,32 @@ def migrate():
2525

2626
@migrate.command()
2727
@click.option("--migrations-dir", help="Directory containing schema migration files")
28-
async def status(migrations_dir: Optional[str]):
28+
def status(migrations_dir: Optional[str]):
2929
"""Show current schema migration status from files."""
3030

31-
dir_path = migrations_dir or os.path.join(
32-
get_root_migrations_dir(), "schema-migrations"
33-
)
34-
migrator = SchemaMigrator(migrations_dir=dir_path)
35-
status_info = await migrator.status()
31+
async def _status():
32+
dir_path = migrations_dir or os.path.join(
33+
get_root_migrations_dir(), "schema-migrations"
34+
)
35+
migrator = SchemaMigrator(migrations_dir=dir_path)
36+
status_info = await migrator.status()
3637

37-
click.echo("Schema Migration Status:")
38-
click.echo(f" Total migrations: {status_info['total_migrations']}")
39-
click.echo(f" Applied: {status_info['applied_count']}")
40-
click.echo(f" Pending: {status_info['pending_count']}")
38+
click.echo("Schema Migration Status:")
39+
click.echo(f" Total migrations: {status_info['total_migrations']}")
40+
click.echo(f" Applied: {status_info['applied_count']}")
41+
click.echo(f" Pending: {status_info['pending_count']}")
42+
43+
if status_info["pending_migrations"]:
44+
click.echo("\nPending migrations:")
45+
for migration_id in status_info["pending_migrations"]:
46+
click.echo(f"- {migration_id}")
4147

42-
if status_info["pending_migrations"]:
43-
click.echo("\nPending migrations:")
44-
for migration_id in status_info["pending_migrations"]:
45-
click.echo(f"- {migration_id}")
48+
if status_info["applied_migrations"]:
49+
click.echo("\nApplied migrations:")
50+
for migration_id in status_info["applied_migrations"]:
51+
click.echo(f"- {migration_id}")
4652

47-
if status_info["applied_migrations"]:
48-
click.echo("\nApplied migrations:")
49-
for migration_id in status_info["applied_migrations"]:
50-
click.echo(f"- {migration_id}")
53+
run_async(_status())
5154

5255

5356
@migrate.command()
@@ -63,7 +66,7 @@ async def status(migrations_dir: Optional[str]):
6366
is_flag=True,
6467
help="Skip confirmation prompt to create directory or run",
6568
)
66-
async def run(
69+
def run(
6770
migrations_dir: Optional[str],
6871
dry_run: bool,
6972
verbose: bool,
@@ -72,38 +75,43 @@ async def run(
7275
):
7376
"""Run pending schema migrations from files."""
7477

75-
dir_path = migrations_dir or os.path.join(
76-
get_root_migrations_dir(), "schema-migrations"
77-
)
78-
79-
if not os.path.exists(dir_path):
80-
if yes or click.confirm(f"Create schema migrations directory at '{dir_path}'?"):
81-
os.makedirs(dir_path, exist_ok=True)
82-
else:
83-
click.echo("Aborted.")
84-
return
85-
86-
migrator = SchemaMigrator(migrations_dir=dir_path)
78+
async def _run():
79+
dir_path = migrations_dir or os.path.join(
80+
get_root_migrations_dir(), "schema-migrations"
81+
)
8782

88-
# Show list for confirmation
89-
if not dry_run and not yes:
90-
status_info = await migrator.status()
91-
if status_info["pending_migrations"]:
92-
listing = "\n".join(
93-
f"- {m}"
94-
for m in status_info["pending_migrations"][
95-
: (limit or len(status_info["pending_migrations"]))
96-
]
97-
)
98-
if not click.confirm(
99-
f"Run {min(limit or len(status_info['pending_migrations']), len(status_info['pending_migrations']))} migration(s)?\n{listing}"
83+
if not os.path.exists(dir_path):
84+
if yes or click.confirm(
85+
f"Create schema migrations directory at '{dir_path}'?"
10086
):
87+
os.makedirs(dir_path, exist_ok=True)
88+
else:
10189
click.echo("Aborted.")
10290
return
10391

104-
count = await migrator.run(dry_run=dry_run, limit=limit, verbose=verbose)
105-
if verbose and not dry_run:
106-
click.echo(f"Successfully applied {count} migration(s).")
92+
migrator = SchemaMigrator(migrations_dir=dir_path)
93+
94+
# Show list for confirmation
95+
if not dry_run and not yes:
96+
status_info = await migrator.status()
97+
if status_info["pending_migrations"]:
98+
listing = "\n".join(
99+
f"- {m}"
100+
for m in status_info["pending_migrations"][
101+
: (limit or len(status_info["pending_migrations"]))
102+
]
103+
)
104+
if not click.confirm(
105+
f"Run {min(limit or len(status_info['pending_migrations']), len(status_info['pending_migrations']))} migration(s)?\n{listing}"
106+
):
107+
click.echo("Aborted.")
108+
return
109+
110+
count = await migrator.run(dry_run=dry_run, limit=limit, verbose=verbose)
111+
if verbose and not dry_run:
112+
click.echo(f"Successfully applied {count} migration(s).")
113+
114+
run_async(_run())
107115

108116

109117
@migrate.command()
@@ -112,26 +120,31 @@ async def run(
112120
@click.option(
113121
"--yes", "-y", is_flag=True, help="Skip confirmation prompt to create directory"
114122
)
115-
async def create(name: str, migrations_dir: Optional[str], yes: bool):
123+
def create(name: str, migrations_dir: Optional[str], yes: bool):
116124
"""Create a new schema migration snapshot file from current pending operations."""
117125

118-
dir_path = migrations_dir or os.path.join(
119-
get_root_migrations_dir(), "schema-migrations"
120-
)
126+
async def _create():
127+
dir_path = migrations_dir or os.path.join(
128+
get_root_migrations_dir(), "schema-migrations"
129+
)
130+
131+
if not os.path.exists(dir_path):
132+
if yes or click.confirm(
133+
f"Create schema migrations directory at '{dir_path}'?"
134+
):
135+
os.makedirs(dir_path, exist_ok=True)
136+
else:
137+
click.echo("Aborted.")
138+
return
121139

122-
if not os.path.exists(dir_path):
123-
if yes or click.confirm(f"Create schema migrations directory at '{dir_path}'?"):
124-
os.makedirs(dir_path, exist_ok=True)
140+
migrator = SchemaMigrator(migrations_dir=dir_path)
141+
filepath = await migrator.create_migration_file(name)
142+
if filepath:
143+
click.echo(f"Created migration: {filepath}")
125144
else:
126-
click.echo("Aborted.")
127-
return
145+
click.echo("No pending schema changes detected. Nothing to snapshot.")
128146

129-
migrator = SchemaMigrator(migrations_dir=dir_path)
130-
filepath = await migrator.create_migration_file(name)
131-
if filepath:
132-
click.echo(f"Created migration: {filepath}")
133-
else:
134-
click.echo("No pending schema changes detected. Nothing to snapshot.")
147+
run_async(_create())
135148

136149

137150
@migrate.command()
@@ -147,7 +160,7 @@ async def create(name: str, migrations_dir: Optional[str], yes: bool):
147160
is_flag=True,
148161
help="Skip confirmation prompt to create directory or run",
149162
)
150-
async def rollback(
163+
def rollback(
151164
migration_id: str,
152165
migrations_dir: Optional[str],
153166
dry_run: bool,
@@ -156,30 +169,37 @@ async def rollback(
156169
):
157170
"""Rollback a specific schema migration by ID."""
158171

159-
dir_path = migrations_dir or os.path.join(
160-
get_root_migrations_dir(), "schema-migrations"
161-
)
172+
async def _rollback():
173+
dir_path = migrations_dir or os.path.join(
174+
get_root_migrations_dir(), "schema-migrations"
175+
)
162176

163-
if not os.path.exists(dir_path):
164-
if yes or click.confirm(f"Create schema migrations directory at '{dir_path}'?"):
165-
os.makedirs(dir_path, exist_ok=True)
166-
else:
167-
click.echo("Aborted.")
168-
return
169-
170-
migrator = SchemaMigrator(migrations_dir=dir_path)
171-
172-
if not yes and not dry_run:
173-
if not click.confirm(f"Rollback migration '{migration_id}'?"):
174-
click.echo("Aborted.")
175-
return
176-
177-
success = await migrator.rollback(migration_id, dry_run=dry_run, verbose=verbose)
178-
if success:
179-
if verbose:
180-
click.echo(f"Successfully rolled back migration: {migration_id}")
181-
else:
182-
click.echo(
183-
f"Migration '{migration_id}' does not support rollback or is not applied.",
184-
err=True,
177+
if not os.path.exists(dir_path):
178+
if yes or click.confirm(
179+
f"Create schema migrations directory at '{dir_path}'?"
180+
):
181+
os.makedirs(dir_path, exist_ok=True)
182+
else:
183+
click.echo("Aborted.")
184+
return
185+
186+
migrator = SchemaMigrator(migrations_dir=dir_path)
187+
188+
if not yes and not dry_run:
189+
if not click.confirm(f"Rollback migration '{migration_id}'?"):
190+
click.echo("Aborted.")
191+
return
192+
193+
success = await migrator.rollback(
194+
migration_id, dry_run=dry_run, verbose=verbose
185195
)
196+
if success:
197+
if verbose:
198+
click.echo(f"Successfully rolled back migration: {migration_id}")
199+
else:
200+
click.echo(
201+
f"Migration '{migration_id}' does not support rollback or is not applied.",
202+
err=True,
203+
)
204+
205+
run_async(_rollback())

aredis_om/model/cli/migrate_data.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def migrate_data():
3434
help="Directory containing migration files (default: <root>/data-migrations)",
3535
)
3636
@click.option("--module", help="Python module containing migrations")
37-
async def status(migrations_dir: str, module: str):
37+
def status(migrations_dir: str, module: str):
3838
"""Show current migration status."""
3939

4040
async def _status():
@@ -71,7 +71,7 @@ async def _status():
7171
click.echo(f"Error: {e}", err=True)
7272
raise click.Abort()
7373

74-
await _status()
74+
run_async(_status())
7575

7676

7777
@migrate_data.command()
@@ -86,7 +86,7 @@ async def _status():
8686
@click.option("--verbose", "-v", is_flag=True, help="Enable verbose output")
8787
@click.option("--limit", type=int, help="Limit number of migrations to run")
8888
@click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt")
89-
async def run(
89+
def run(
9090
migrations_dir: str,
9191
module: str,
9292
dry_run: bool,
@@ -164,7 +164,7 @@ async def _run():
164164
click.echo(f"Error: {e}", err=True)
165165
raise click.Abort()
166166

167-
await _run()
167+
run_async(_run())
168168

169169

170170
@migrate_data.command()
@@ -176,7 +176,7 @@ async def _run():
176176
@click.option(
177177
"--yes", "-y", is_flag=True, help="Skip confirmation prompt to create directory"
178178
)
179-
async def create(name: str, migrations_dir: Optional[str], yes: bool):
179+
def create(name: str, migrations_dir: Optional[str], yes: bool):
180180
"""Create a new migration file."""
181181

182182
async def _create():
@@ -206,7 +206,7 @@ async def _create():
206206
click.echo(f"Error creating migration: {e}", err=True)
207207
raise click.Abort()
208208

209-
await _create()
209+
run_async(_create())
210210

211211

212212
@migrate_data.command()
@@ -222,7 +222,7 @@ async def _create():
222222
)
223223
@click.option("--verbose", "-v", is_flag=True, help="Enable verbose output")
224224
@click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt")
225-
async def rollback(
225+
def rollback(
226226
migration_id: str,
227227
migrations_dir: str,
228228
module: str,
@@ -284,7 +284,7 @@ async def _rollback():
284284
click.echo(f"Error: {e}", err=True)
285285
raise click.Abort()
286286

287-
await _rollback()
287+
run_async(_rollback())
288288

289289

290290
if __name__ == "__main__":

0 commit comments

Comments
 (0)