swiftpy-framework 0.1.0__py3-none-any.whl
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.
- swiftpy/.gitignore +0 -0
- swiftpy/__init__.py +572 -0
- swiftpy/admin/__init__.py +50 -0
- swiftpy/admin/auth.py +522 -0
- swiftpy/admin/registry.py +567 -0
- swiftpy/admin/views.py +1583 -0
- swiftpy/ai/__init__.py +199 -0
- swiftpy/ai/_deterministic.py +40 -0
- swiftpy/ai/_fake.py +604 -0
- swiftpy/ai/agents/__init__.py +30 -0
- swiftpy/ai/agents/base_agent.py +506 -0
- swiftpy/ai/agents/memory.py +864 -0
- swiftpy/ai/client.py +1011 -0
- swiftpy/ai/conversation.py +171 -0
- swiftpy/ai/embeddings.py +321 -0
- swiftpy/ai/exceptions.py +75 -0
- swiftpy/ai/history_strategies.py +157 -0
- swiftpy/ai/middleware.py +918 -0
- swiftpy/ai/observability/__init__.py +28 -0
- swiftpy/ai/observability/drivers.py +763 -0
- swiftpy/ai/observability/observer.py +364 -0
- swiftpy/ai/pool.py +102 -0
- swiftpy/ai/pricing.py +101 -0
- swiftpy/ai/prompts/__init__.py +6 -0
- swiftpy/ai/prompts/loader.py +343 -0
- swiftpy/ai/providers/__init__.py +22 -0
- swiftpy/ai/providers/anthropic_provider.py +353 -0
- swiftpy/ai/providers/base.py +273 -0
- swiftpy/ai/providers/openai_provider.py +275 -0
- swiftpy/ai/rag/__init__.py +53 -0
- swiftpy/ai/rag/context_formatter.py +263 -0
- swiftpy/ai/rag/pipeline_builder.py +544 -0
- swiftpy/ai/rag/reranker.py +484 -0
- swiftpy/ai/rag/result.py +78 -0
- swiftpy/ai/rag/retriever.py +315 -0
- swiftpy/ai/redis_store.py +227 -0
- swiftpy/ai/streaming.py +115 -0
- swiftpy/ai/tools/__init__.py +22 -0
- swiftpy/ai/tools/base_tool.py +489 -0
- swiftpy/ai/tools/first_party.py +384 -0
- swiftpy/ai/tools/tool_loop.py +417 -0
- swiftpy/ai/vectorstore/__init__.py +46 -0
- swiftpy/ai/vectorstore/base.py +542 -0
- swiftpy/ai/vectorstore/chroma_adapter.py +435 -0
- swiftpy/ai/vectorstore/in_memory_adapter.py +321 -0
- swiftpy/ai/vectorstore/lancedb_adapter.py +370 -0
- swiftpy/ai/vectorstore/pgvector_adapter.py +496 -0
- swiftpy/ai/vectorstore/pinecone_adapter.py +445 -0
- swiftpy/ai/vectorstore/qdrant_adapter.py +418 -0
- swiftpy/auth/__init__.py +50 -0
- swiftpy/auth/api_key_guard.py +544 -0
- swiftpy/auth/auth_manager.py +259 -0
- swiftpy/auth/exceptions.py +71 -0
- swiftpy/auth/jwt_guard.py +230 -0
- swiftpy/auth/jwt_issuer.py +658 -0
- swiftpy/auth/token_blacklist.py +300 -0
- swiftpy/cache/__init__.py +14 -0
- swiftpy/cache/cache.py +251 -0
- swiftpy/cache/driver.py +216 -0
- swiftpy/cache/drivers/memory.py +199 -0
- swiftpy/cache/drivers/redis.py +421 -0
- swiftpy/console/__init__.py +0 -0
- swiftpy/console/cli.py +68 -0
- swiftpy/console/commands/__init__.py +0 -0
- swiftpy/console/commands/cache.py +164 -0
- swiftpy/console/commands/make.py +935 -0
- swiftpy/console/commands/migrate.py +280 -0
- swiftpy/console/commands/new.py +1806 -0
- swiftpy/console/commands/queue.py +306 -0
- swiftpy/console/commands/seed.py +252 -0
- swiftpy/console/commands/start.py +171 -0
- swiftpy/console/commands/storage.py +104 -0
- swiftpy/console/loader.py +21 -0
- swiftpy/console/stubs/__init__.py +26 -0
- swiftpy/console/stubs/controller.stub +14 -0
- swiftpy/console/stubs/event.stub +14 -0
- swiftpy/console/stubs/job.stub +22 -0
- swiftpy/console/stubs/listener.stub +14 -0
- swiftpy/console/stubs/mail.stub +20 -0
- swiftpy/console/stubs/middleware.stub +16 -0
- swiftpy/console/stubs/migration.alter.stub +17 -0
- swiftpy/console/stubs/migration.api_keys.stub +22 -0
- swiftpy/console/stubs/migration.blank.stub +11 -0
- swiftpy/console/stubs/migration.create.stub +15 -0
- swiftpy/console/stubs/migration.stub +11 -0
- swiftpy/console/stubs/migration.update.stub +17 -0
- swiftpy/console/stubs/model.stub +17 -0
- swiftpy/console/stubs/provider.stub +18 -0
- swiftpy/console/stubs/repository.stub +10 -0
- swiftpy/console/stubs/request.stub +16 -0
- swiftpy/console/stubs/resource.stub +21 -0
- swiftpy/console/stubs/schema.stub +12 -0
- swiftpy/console/stubs/seeder.stub +14 -0
- swiftpy/console/stubs/service.stub +10 -0
- swiftpy/core/__init__.py +0 -0
- swiftpy/core/application.py +1306 -0
- swiftpy/core/bootstrap.py +30 -0
- swiftpy/core/config.py +432 -0
- swiftpy/core/container.py +596 -0
- swiftpy/core/container_exceptions.py +18 -0
- swiftpy/core/context.py +148 -0
- swiftpy/core/exceptions.py +352 -0
- swiftpy/core/providers/base.py +35 -0
- swiftpy/database/__init__.py +41 -0
- swiftpy/database/exceptions.py +42 -0
- swiftpy/database/identifiers.py +105 -0
- swiftpy/database/migrations/__init__.py +36 -0
- swiftpy/database/migrations/blueprint.py +431 -0
- swiftpy/database/migrations/lock.py +104 -0
- swiftpy/database/migrations/migration.py +22 -0
- swiftpy/database/migrations/migrator.py +507 -0
- swiftpy/database/migrations/schema.py +435 -0
- swiftpy/database/orm/__init__.py +33 -0
- swiftpy/database/orm/fields.py +92 -0
- swiftpy/database/orm/model.py +2034 -0
- swiftpy/database/orm/registry.py +33 -0
- swiftpy/database/orm/relationships.py +836 -0
- swiftpy/database/pagination/__init__.py +16 -0
- swiftpy/database/pagination/contracts.py +60 -0
- swiftpy/database/pagination/paginator.py +112 -0
- swiftpy/database/pagination/simple_paginator.py +97 -0
- swiftpy/database/pool.py +218 -0
- swiftpy/database/query_builder.py +1803 -0
- swiftpy/database/seeder.py +39 -0
- swiftpy/database/transaction.py +276 -0
- swiftpy/events/__init__.py +10 -0
- swiftpy/events/dispatcher.py +308 -0
- swiftpy/events/redis_bus.py +552 -0
- swiftpy/filesystem/__init__.py +227 -0
- swiftpy/filesystem/disk.py +378 -0
- swiftpy/filesystem/drivers/__init__.py +11 -0
- swiftpy/filesystem/drivers/base.py +156 -0
- swiftpy/filesystem/drivers/local.py +559 -0
- swiftpy/filesystem/drivers/s3.py +655 -0
- swiftpy/filesystem/events.py +37 -0
- swiftpy/filesystem/exceptions.py +127 -0
- swiftpy/filesystem/manager.py +138 -0
- swiftpy/filesystem/metadata.py +22 -0
- swiftpy/filesystem/paths.py +99 -0
- swiftpy/filesystem/service_provider.py +17 -0
- swiftpy/filesystem/uploads/__init__.py +13 -0
- swiftpy/filesystem/uploads/handlers.py +362 -0
- swiftpy/filesystem/uploads/uploaded_file.py +222 -0
- swiftpy/filesystem/uploads/validators.py +186 -0
- swiftpy/filesystem/visibility.py +22 -0
- swiftpy/helpers/__init__.py +42 -0
- swiftpy/helpers/helper.py +180 -0
- swiftpy/http/exceptions.py +41 -0
- swiftpy/http/middleware.py +307 -0
- swiftpy/http/request.py +375 -0
- swiftpy/http/response.py +442 -0
- swiftpy/http/router.py +1050 -0
- swiftpy/mail/__init__.py +58 -0
- swiftpy/mail/attachments.py +255 -0
- swiftpy/mail/config.py +71 -0
- swiftpy/mail/envelope.py +183 -0
- swiftpy/mail/exceptions.py +90 -0
- swiftpy/mail/facade.py +312 -0
- swiftpy/mail/mailable.py +53 -0
- swiftpy/mail/manager.py +240 -0
- swiftpy/mail/message.py +186 -0
- swiftpy/mail/models.py +19 -0
- swiftpy/mail/queue/__init__.py +5 -0
- swiftpy/mail/queue/job.py +279 -0
- swiftpy/mail/service_provider.py +19 -0
- swiftpy/mail/templates/__init__.py +5 -0
- swiftpy/mail/templates/renderer.py +173 -0
- swiftpy/mail/transports/__init__.py +21 -0
- swiftpy/mail/transports/api/__init__.py +13 -0
- swiftpy/mail/transports/api/base.py +194 -0
- swiftpy/mail/transports/api/mailgun.py +158 -0
- swiftpy/mail/transports/api/resend.py +156 -0
- swiftpy/mail/transports/api/sendgrid.py +172 -0
- swiftpy/mail/transports/base.py +24 -0
- swiftpy/mail/transports/console.py +91 -0
- swiftpy/mail/transports/sendmail.py +128 -0
- swiftpy/mail/transports/smtp.py +466 -0
- swiftpy/queue/__init__.py +13 -0
- swiftpy/queue/dispatcher.py +813 -0
- swiftpy/queue/job.py +541 -0
- swiftpy/queue/worker.py +556 -0
- swiftpy/support/__init__.py +12 -0
- swiftpy/support/keys.py +108 -0
- swiftpy/support/redis_config.py +223 -0
- swiftpy/support/strings.py +114 -0
- swiftpy/testing/__init__.py +20 -0
- swiftpy/testing/fakes/__init__.py +11 -0
- swiftpy/testing/fakes/ai_fake.py +21 -0
- swiftpy/testing/fakes/vectorstore_fake.py +194 -0
- swiftpy/testing/fixtures.py +124 -0
- swiftpy/testing/http_client.py +730 -0
- swiftpy/testing/test_case.py +126 -0
- swiftpy/validation/__init__.py +97 -0
- swiftpy/validation/exceptions.py +26 -0
- swiftpy/validation/form_request.py +302 -0
- swiftpy/validation/protocols.py +33 -0
- swiftpy/validation/rules/__init__.py +89 -0
- swiftpy/validation/rules/builtin.py +391 -0
- swiftpy/validation/rules/exists.py +86 -0
- swiftpy/validation/rules/registry.py +290 -0
- swiftpy/validation/rules/required.py +55 -0
- swiftpy/validation/rules/unique.py +138 -0
- swiftpy/validation/validator.py +612 -0
- swiftpy/websockets/__init__.py +19 -0
- swiftpy/websockets/connection.py +317 -0
- swiftpy/websockets/manager.py +271 -0
- swiftpy_framework-0.1.0.dist-info/METADATA +603 -0
- swiftpy_framework-0.1.0.dist-info/RECORD +211 -0
- swiftpy_framework-0.1.0.dist-info/WHEEL +4 -0
- swiftpy_framework-0.1.0.dist-info/entry_points.txt +2 -0
- swiftpy_framework-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import asyncio
|
|
5
|
+
import concurrent.futures
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from swiftpy.console.loader import load_application
|
|
12
|
+
from swiftpy.core.config import env
|
|
13
|
+
from swiftpy.database.migrations.migrator import Migrator
|
|
14
|
+
from swiftpy.database.pool import DatabasePool
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _paint(text: str, code: str) -> str:
|
|
18
|
+
"""Format text with ANSI escape codes only if stdout is a terminal and NO_COLOR is unset."""
|
|
19
|
+
if sys.stdout.isatty() and "NO_COLOR" not in os.environ:
|
|
20
|
+
return f"\033[{code}m{text}\033[0m"
|
|
21
|
+
return text
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _run_coroutine(coro: Any) -> Any:
|
|
25
|
+
"""Run an async coroutine synchronously, safely handling existing active event loops."""
|
|
26
|
+
try:
|
|
27
|
+
asyncio.get_running_loop()
|
|
28
|
+
except RuntimeError:
|
|
29
|
+
return asyncio.run(coro)
|
|
30
|
+
|
|
31
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
|
|
32
|
+
return executor.submit(asyncio.run, coro).result()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class MigrateCommand:
|
|
36
|
+
"""Console commands for running and inspecting database migrations."""
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def _add_common_arguments(parser: argparse.ArgumentParser) -> None:
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"--app",
|
|
42
|
+
default="main:app",
|
|
43
|
+
help="Application target (module:attribute)",
|
|
44
|
+
)
|
|
45
|
+
parser.add_argument(
|
|
46
|
+
"--path",
|
|
47
|
+
default=None,
|
|
48
|
+
help="Path to the migrations directory",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def register(
|
|
53
|
+
subparsers: argparse._SubParsersAction[argparse.ArgumentParser],
|
|
54
|
+
) -> None:
|
|
55
|
+
# 1. `swiftpy migrate`
|
|
56
|
+
migrate_parser = subparsers.add_parser(
|
|
57
|
+
"migrate",
|
|
58
|
+
help="Run outstanding database migrations",
|
|
59
|
+
)
|
|
60
|
+
MigrateCommand._add_common_arguments(migrate_parser)
|
|
61
|
+
migrate_parser.add_argument(
|
|
62
|
+
"--step",
|
|
63
|
+
dest="step",
|
|
64
|
+
type=int,
|
|
65
|
+
default=None,
|
|
66
|
+
help="The number of migrations to execute",
|
|
67
|
+
)
|
|
68
|
+
migrate_parser.add_argument(
|
|
69
|
+
"--force",
|
|
70
|
+
dest="force",
|
|
71
|
+
action="store_true",
|
|
72
|
+
default=False,
|
|
73
|
+
help="Force the operation to run when in production",
|
|
74
|
+
)
|
|
75
|
+
migrate_parser.set_defaults(
|
|
76
|
+
_handler=MigrateCommand.handle_migrate,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# 2. `swiftpy migrate:rollback`
|
|
80
|
+
rollback_parser = subparsers.add_parser(
|
|
81
|
+
"migrate:rollback",
|
|
82
|
+
help="Rollback the last database migration batch",
|
|
83
|
+
)
|
|
84
|
+
MigrateCommand._add_common_arguments(rollback_parser)
|
|
85
|
+
rollback_parser.add_argument(
|
|
86
|
+
"--step",
|
|
87
|
+
dest="step",
|
|
88
|
+
type=int,
|
|
89
|
+
default=1,
|
|
90
|
+
help="The number of migration batches to rollback",
|
|
91
|
+
)
|
|
92
|
+
rollback_parser.add_argument(
|
|
93
|
+
"--force",
|
|
94
|
+
dest="force",
|
|
95
|
+
action="store_true",
|
|
96
|
+
default=False,
|
|
97
|
+
help="Force the operation to run when in production",
|
|
98
|
+
)
|
|
99
|
+
rollback_parser.set_defaults(
|
|
100
|
+
_handler=MigrateCommand.handle_rollback,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# 3. `swiftpy migrate:reset`
|
|
104
|
+
reset_parser = subparsers.add_parser(
|
|
105
|
+
"migrate:reset",
|
|
106
|
+
help="Rollback all database migrations",
|
|
107
|
+
)
|
|
108
|
+
MigrateCommand._add_common_arguments(reset_parser)
|
|
109
|
+
reset_parser.add_argument(
|
|
110
|
+
"--force",
|
|
111
|
+
dest="force",
|
|
112
|
+
action="store_true",
|
|
113
|
+
default=False,
|
|
114
|
+
help="Force the operation to run when in production",
|
|
115
|
+
)
|
|
116
|
+
reset_parser.set_defaults(
|
|
117
|
+
_handler=MigrateCommand.handle_reset,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# 4. `swiftpy migrate:status`
|
|
121
|
+
status_parser = subparsers.add_parser(
|
|
122
|
+
"migrate:status",
|
|
123
|
+
help="Show the status of each migration",
|
|
124
|
+
)
|
|
125
|
+
MigrateCommand._add_common_arguments(status_parser)
|
|
126
|
+
status_parser.set_defaults(
|
|
127
|
+
_handler=MigrateCommand.handle_status,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
@staticmethod
|
|
131
|
+
def _validate_step(step: int | None) -> None:
|
|
132
|
+
if step is not None and step < 1:
|
|
133
|
+
print("Error: --step must be an integer >= 1.", file=sys.stderr)
|
|
134
|
+
raise SystemExit(1)
|
|
135
|
+
|
|
136
|
+
@staticmethod
|
|
137
|
+
def _enforce_production_guard(
|
|
138
|
+
args: argparse.Namespace, app: Any | None = None
|
|
139
|
+
) -> None:
|
|
140
|
+
if getattr(args, "force", False):
|
|
141
|
+
return
|
|
142
|
+
env_val = (
|
|
143
|
+
env("SWIFTPY_APP__ENV")
|
|
144
|
+
or env("APP_ENV")
|
|
145
|
+
or (
|
|
146
|
+
str(app.config.get("app.env") or app.config.get("env") or "")
|
|
147
|
+
if app is not None and hasattr(app, "config")
|
|
148
|
+
else ""
|
|
149
|
+
)
|
|
150
|
+
)
|
|
151
|
+
if str(env_val).strip().lower() in ("production", "prod"):
|
|
152
|
+
print(
|
|
153
|
+
"Error: Application is in production. Pass --force to run migrations in production.",
|
|
154
|
+
file=sys.stderr,
|
|
155
|
+
)
|
|
156
|
+
raise SystemExit(1)
|
|
157
|
+
|
|
158
|
+
@classmethod
|
|
159
|
+
async def _init_migrator(
|
|
160
|
+
cls,
|
|
161
|
+
args: argparse.Namespace,
|
|
162
|
+
*,
|
|
163
|
+
require_guard: bool = False,
|
|
164
|
+
) -> tuple[DatabasePool, Migrator]:
|
|
165
|
+
"""Load application target, resolve DatabasePool, and return initialized Migrator."""
|
|
166
|
+
if require_guard:
|
|
167
|
+
cls._enforce_production_guard(args)
|
|
168
|
+
app = load_application(args.app)
|
|
169
|
+
if require_guard:
|
|
170
|
+
cls._enforce_production_guard(args, app=app)
|
|
171
|
+
pool = app.container.resolve(DatabasePool)
|
|
172
|
+
await pool.init()
|
|
173
|
+
|
|
174
|
+
mig_dir = (
|
|
175
|
+
Path(args.path) if args.path else Path.cwd() / "database" / "migrations"
|
|
176
|
+
)
|
|
177
|
+
return pool, Migrator(pool=pool, migrations_dir=mig_dir)
|
|
178
|
+
|
|
179
|
+
@staticmethod
|
|
180
|
+
def handle_migrate(args: argparse.Namespace) -> None:
|
|
181
|
+
MigrateCommand._validate_step(getattr(args, "step", None))
|
|
182
|
+
MigrateCommand._enforce_production_guard(args)
|
|
183
|
+
_run_coroutine(MigrateCommand._execute_migrate(args))
|
|
184
|
+
|
|
185
|
+
@classmethod
|
|
186
|
+
async def _execute_migrate(cls, args: argparse.Namespace) -> None:
|
|
187
|
+
pool, migrator = await cls._init_migrator(args, require_guard=True)
|
|
188
|
+
try:
|
|
189
|
+
print(_paint("Running migrations...", "1"))
|
|
190
|
+
applied = await migrator.run(
|
|
191
|
+
step=args.step,
|
|
192
|
+
on_applied=lambda name, ms: print(
|
|
193
|
+
f" {_paint('Migrated:', '32')} {name} ({ms:.1f}ms)"
|
|
194
|
+
),
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
if not applied:
|
|
198
|
+
print(_paint("Nothing to migrate.", "33"))
|
|
199
|
+
finally:
|
|
200
|
+
await pool.close()
|
|
201
|
+
|
|
202
|
+
@staticmethod
|
|
203
|
+
def handle_rollback(args: argparse.Namespace) -> None:
|
|
204
|
+
MigrateCommand._validate_step(getattr(args, "step", 1))
|
|
205
|
+
MigrateCommand._enforce_production_guard(args)
|
|
206
|
+
_run_coroutine(MigrateCommand._execute_rollback(args))
|
|
207
|
+
|
|
208
|
+
@classmethod
|
|
209
|
+
async def _execute_rollback(cls, args: argparse.Namespace) -> None:
|
|
210
|
+
pool, migrator = await cls._init_migrator(args, require_guard=True)
|
|
211
|
+
try:
|
|
212
|
+
print(_paint("Rolling back migrations...", "1"))
|
|
213
|
+
rolled_back = await migrator.rollback(
|
|
214
|
+
steps=args.step,
|
|
215
|
+
on_rolled_back=lambda name, ms: print(
|
|
216
|
+
f" {_paint('Rolled back:', '33')} {name} ({ms:.1f}ms)"
|
|
217
|
+
),
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
if not rolled_back:
|
|
221
|
+
print(_paint("Nothing to rollback.", "33"))
|
|
222
|
+
finally:
|
|
223
|
+
await pool.close()
|
|
224
|
+
|
|
225
|
+
@staticmethod
|
|
226
|
+
def handle_reset(args: argparse.Namespace) -> None:
|
|
227
|
+
MigrateCommand._enforce_production_guard(args)
|
|
228
|
+
_run_coroutine(MigrateCommand._execute_reset(args))
|
|
229
|
+
|
|
230
|
+
@classmethod
|
|
231
|
+
async def _execute_reset(cls, args: argparse.Namespace) -> None:
|
|
232
|
+
pool, migrator = await cls._init_migrator(args, require_guard=True)
|
|
233
|
+
try:
|
|
234
|
+
print(_paint("Resetting all migrations...", "1"))
|
|
235
|
+
rolled_back = await migrator.reset()
|
|
236
|
+
for name in rolled_back:
|
|
237
|
+
print(f" {_paint('Rolled back:', '33')} {name}")
|
|
238
|
+
|
|
239
|
+
if not rolled_back:
|
|
240
|
+
print(_paint("Nothing to reset.", "33"))
|
|
241
|
+
finally:
|
|
242
|
+
await pool.close()
|
|
243
|
+
|
|
244
|
+
@staticmethod
|
|
245
|
+
def handle_status(args: argparse.Namespace) -> None:
|
|
246
|
+
_run_coroutine(MigrateCommand._execute_status(args))
|
|
247
|
+
|
|
248
|
+
@classmethod
|
|
249
|
+
async def _execute_status(cls, args: argparse.Namespace) -> None:
|
|
250
|
+
pool, migrator = await cls._init_migrator(args)
|
|
251
|
+
try:
|
|
252
|
+
statuses: list[dict[str, Any]] = await migrator.status()
|
|
253
|
+
|
|
254
|
+
if not statuses:
|
|
255
|
+
print(_paint("No migrations found.", "33"))
|
|
256
|
+
return
|
|
257
|
+
|
|
258
|
+
print(
|
|
259
|
+
"\n+------+----------------------------------------------------------+-------+"
|
|
260
|
+
)
|
|
261
|
+
print(
|
|
262
|
+
"| Ran? | Migration | Batch |"
|
|
263
|
+
)
|
|
264
|
+
print(
|
|
265
|
+
"+------+----------------------------------------------------------+-------+"
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
for s in statuses:
|
|
269
|
+
ran_str = (
|
|
270
|
+
f"{_paint('Yes', '32')} " if s["ran"] else f"{_paint('No', '31')} "
|
|
271
|
+
)
|
|
272
|
+
name = str(s["migration"])[:56].ljust(56)
|
|
273
|
+
batch_str = str(s["batch"] if s["batch"] is not None else "").center(5)
|
|
274
|
+
print(f"| {ran_str} | {name} | {batch_str} |")
|
|
275
|
+
|
|
276
|
+
print(
|
|
277
|
+
"+------+----------------------------------------------------------+-------+\n"
|
|
278
|
+
)
|
|
279
|
+
finally:
|
|
280
|
+
await pool.close()
|