Karan6124 commited on
Commit
fd9fd80
·
1 Parent(s): e615b1f

feat: configure Alembic env.py to dynamically load settings database URL and metadata

Browse files
Files changed (4) hide show
  1. alembic/env.py +15 -26
  2. backend/app/config/settings.py +10 -5
  3. pyproject.toml +1 -0
  4. uv.lock +16 -0
alembic/env.py CHANGED
@@ -1,5 +1,7 @@
1
  import asyncio
 
2
  from logging.config import fileConfig
 
3
 
4
  from sqlalchemy import pool
5
  from sqlalchemy.engine import Connection
@@ -7,39 +9,29 @@ from sqlalchemy.ext.asyncio import async_engine_from_config
7
 
8
  from alembic import context
9
 
 
 
 
 
 
 
10
  # this is the Alembic Config object, which provides
11
  # access to the values within the .ini file in use.
12
  config = context.config
13
 
 
 
 
14
  # Interpret the config file for Python logging.
15
- # This line sets up loggers basically.
16
  if config.config_file_name is not None:
17
  fileConfig(config.config_file_name)
18
 
19
- # add your model's MetaData object here
20
- # for 'autogenerate' support
21
- # from myapp import mymodel
22
- # target_metadata = mymodel.Base.metadata
23
- target_metadata = None
24
-
25
- # other values from the config, defined by the needs of env.py,
26
- # can be acquired:
27
- # my_important_option = config.get_main_option("my_important_option")
28
- # ... etc.
29
 
30
 
31
  def run_migrations_offline() -> None:
32
- """Run migrations in 'offline' mode.
33
-
34
- This configures the context with just a URL
35
- and not an Engine, though an Engine is acceptable
36
- here as well. By skipping the Engine creation
37
- we don't even need a DBAPI to be available.
38
-
39
- Calls to context.execute() here emit the given string to the
40
- script output.
41
-
42
- """
43
  url = config.get_main_option("sqlalchemy.url")
44
  context.configure(
45
  url=url,
@@ -62,9 +54,7 @@ def do_run_migrations(connection: Connection) -> None:
62
  async def run_async_migrations() -> None:
63
  """In this scenario we need to create an Engine
64
  and associate a connection with the context.
65
-
66
  """
67
-
68
  connectable = async_engine_from_config(
69
  config.get_section(config.config_ini_section, {}),
70
  prefix="sqlalchemy.",
@@ -79,11 +69,10 @@ async def run_async_migrations() -> None:
79
 
80
  def run_migrations_online() -> None:
81
  """Run migrations in 'online' mode."""
82
-
83
  asyncio.run(run_async_migrations())
84
 
85
 
86
  if context.is_offline_mode():
87
  run_migrations_offline()
88
  else:
89
- run_migrations_online()
 
1
  import asyncio
2
+ import sys
3
  from logging.config import fileConfig
4
+ from pathlib import Path
5
 
6
  from sqlalchemy import pool
7
  from sqlalchemy.engine import Connection
 
9
 
10
  from alembic import context
11
 
12
+ # 1. Add the project root to Python Path to allow imports from backend
13
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
14
+
15
+ from backend.app.config.settings import settings
16
+ from backend.app.database.models import Base
17
+
18
  # this is the Alembic Config object, which provides
19
  # access to the values within the .ini file in use.
20
  config = context.config
21
 
22
+ # 2. Inject our dynamic database URL from settings into Alembic's configuration
23
+ config.set_main_option("sqlalchemy.url", settings.database_url_async)
24
+
25
  # Interpret the config file for Python logging.
 
26
  if config.config_file_name is not None:
27
  fileConfig(config.config_file_name)
28
 
29
+ # 3. Hook up our SQLAlchemy Base metadata to enable schema autogeneration
30
+ target_metadata = Base.metadata
 
 
 
 
 
 
 
 
31
 
32
 
33
  def run_migrations_offline() -> None:
34
+ """Run migrations in 'offline' mode."""
 
 
 
 
 
 
 
 
 
 
35
  url = config.get_main_option("sqlalchemy.url")
36
  context.configure(
37
  url=url,
 
54
  async def run_async_migrations() -> None:
55
  """In this scenario we need to create an Engine
56
  and associate a connection with the context.
 
57
  """
 
58
  connectable = async_engine_from_config(
59
  config.get_section(config.config_ini_section, {}),
60
  prefix="sqlalchemy.",
 
69
 
70
  def run_migrations_online() -> None:
71
  """Run migrations in 'online' mode."""
 
72
  asyncio.run(run_async_migrations())
73
 
74
 
75
  if context.is_offline_mode():
76
  run_migrations_offline()
77
  else:
78
+ run_migrations_online()
backend/app/config/settings.py CHANGED
@@ -11,13 +11,18 @@ class Settings(BaseSettings):
11
  GEMINI_API_KEY: str
12
 
13
  # Optional Razorpay Credentials (defaults to empty string if not set)
14
- RAZORPAY_KEY_ID: str= Field(default="")
15
- RAZORPAY_KEY_SECRET: str= Field(default="")
16
- RAZORPAY_WEBHOOK_SECRET: str= Field(default="")
 
 
 
 
 
17
 
18
  # Auth configuration
19
- SECRET_KEY: str= Field(default="supersecretkeychangeinproduction")
20
- ACCESS_TOKEN_EXPIRE_MINUTES: int= 60*24*8
21
 
22
  @property
23
  def database_url_async(self) -> str:
 
11
  GEMINI_API_KEY: str
12
 
13
  # Optional Razorpay Credentials (defaults to empty string if not set)
14
+ RAZORPAY_KEY_ID: str = Field(default="")
15
+ RAZORPAY_KEY_SECRET: str = Field(default="")
16
+ RAZORPAY_WEBHOOK_SECRET: str = Field(default="")
17
+
18
+ # Optional Cloudinary Credentials (defaults to empty string if not set)
19
+ CLOUDINARY_CLOUD_NAME: str = Field(default="")
20
+ CLOUDINARY_API_KEY: str = Field(default="")
21
+ CLOUDINARY_API_SECRET: str = Field(default="")
22
 
23
  # Auth configuration
24
+ SECRET_KEY: str = Field(default="supersecretkeychangeinproduction")
25
+ ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 8
26
 
27
  @property
28
  def database_url_async(self) -> str:
pyproject.toml CHANGED
@@ -21,4 +21,5 @@ dependencies = [
21
  "prometheus-fastapi-instrumentator>=7.0.0",
22
  "razorpay>=1.4.1",
23
  "httpx>=0.27.0",
 
24
  ]
 
21
  "prometheus-fastapi-instrumentator>=7.0.0",
22
  "razorpay>=1.4.1",
23
  "httpx>=0.27.0",
24
+ "cloudinary>=1.38.0",
25
  ]
uv.lock CHANGED
@@ -305,6 +305,20 @@ wheels = [
305
  { url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" },
306
  ]
307
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  [[package]]
309
  name = "colorama"
310
  version = "0.4.6"
@@ -1507,6 +1521,7 @@ source = { virtual = "." }
1507
  dependencies = [
1508
  { name = "alembic" },
1509
  { name = "asyncpg" },
 
1510
  { name = "fastapi" },
1511
  { name = "google-generativeai" },
1512
  { name = "httpx" },
@@ -1528,6 +1543,7 @@ dependencies = [
1528
  requires-dist = [
1529
  { name = "alembic", specifier = ">=1.13.1" },
1530
  { name = "asyncpg", specifier = ">=0.29.0" },
 
1531
  { name = "fastapi", specifier = ">=0.110.0" },
1532
  { name = "google-generativeai", specifier = ">=0.4.1" },
1533
  { name = "httpx", specifier = ">=0.27.0" },
 
305
  { url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" },
306
  ]
307
 
308
+ [[package]]
309
+ name = "cloudinary"
310
+ version = "1.44.2"
311
+ source = { registry = "https://pypi.org/simple" }
312
+ dependencies = [
313
+ { name = "certifi" },
314
+ { name = "six" },
315
+ { name = "urllib3" },
316
+ ]
317
+ sdist = { url = "https://files.pythonhosted.org/packages/0c/1b/ae48dbbe3c2ff81b94816dd6645af2d609e135cea4fcd65b1a8a61672cea/cloudinary-1.44.2.tar.gz", hash = "sha256:bc9139c68f2ef6996ba62a5d0300e63c711d4f6564644c0c82aa31bf641ef3c7", size = 188389, upload-time = "2026-04-16T08:18:19.92Z" }
318
+ wheels = [
319
+ { url = "https://files.pythonhosted.org/packages/b2/8b/0da00a22362c89ef53f9d64af29546d24aba8533ffdb7bbcb19631c7f636/cloudinary-1.44.2-py3-none-any.whl", hash = "sha256:6624d06014c33f50c0c9e740fde1dfe4579d03311025d8bb7183824b7443aa09", size = 147805, upload-time = "2026-04-16T08:18:18.84Z" },
320
+ ]
321
+
322
  [[package]]
323
  name = "colorama"
324
  version = "0.4.6"
 
1521
  dependencies = [
1522
  { name = "alembic" },
1523
  { name = "asyncpg" },
1524
+ { name = "cloudinary" },
1525
  { name = "fastapi" },
1526
  { name = "google-generativeai" },
1527
  { name = "httpx" },
 
1543
  requires-dist = [
1544
  { name = "alembic", specifier = ">=1.13.1" },
1545
  { name = "asyncpg", specifier = ">=0.29.0" },
1546
+ { name = "cloudinary", specifier = ">=1.38.0" },
1547
  { name = "fastapi", specifier = ">=0.110.0" },
1548
  { name = "google-generativeai", specifier = ">=0.4.1" },
1549
  { name = "httpx", specifier = ">=0.27.0" },