Setting up the configuration files and refactoring
This commit is contained in:
+4
-1
@@ -1,3 +1,6 @@
|
|||||||
app/__pycache__
|
app/__pycache__
|
||||||
|
__pycache__
|
||||||
|
.pytest_cache/
|
||||||
venv/
|
venv/
|
||||||
test.txt
|
test.txt
|
||||||
|
diff.txt
|
||||||
@@ -10,7 +10,7 @@ source venv/bin/activate
|
|||||||
|
|
||||||
## Run locally
|
## Run locally
|
||||||
```bash
|
```bash
|
||||||
uvicorn app.main:app --reload
|
python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||||||
```
|
```
|
||||||
Then check:<br>
|
Then check:<br>
|
||||||
http://127.0.0.1:8000<br>
|
http://127.0.0.1:8000<br>
|
||||||
@@ -23,5 +23,5 @@ http://127.0.0.1:8000/shorten
|
|||||||
```bash
|
```bash
|
||||||
PYTHONPATH=./ pytest
|
PYTHONPATH=./ pytest
|
||||||
export PYTHONPATH=$(pwd)
|
export PYTHONPATH=$(pwd)
|
||||||
pytest
|
python -m pytest --cov=app --cov-report=term-missing
|
||||||
```
|
```
|
||||||
+19
-17
@@ -1,36 +1,38 @@
|
|||||||
# app/core/config.py
|
# app/core/config.py
|
||||||
|
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
from pydantic import BaseSettings
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
# App
|
app_name: str = "URL Shortener"
|
||||||
app_name: str = "URL Shortener API"
|
allowed_hosts: List[str] = ["*"]
|
||||||
debug: bool = False
|
database_url: str
|
||||||
|
|
||||||
# Server
|
# Server settings
|
||||||
host: str = "0.0.0.0"
|
host: str = "0.0.0.0"
|
||||||
port: int = 8000
|
port: int = 8000
|
||||||
base_url: str = "http://localhost:8000"
|
base_url: str = "http://localhost:8000"
|
||||||
|
|
||||||
# Database
|
# Debug flag
|
||||||
database_url: str = "sqlite:///./urls.db"
|
debug: bool = True
|
||||||
|
|
||||||
# Optional future extensions
|
# Optional future extensions
|
||||||
allowed_hosts: list[str] = ["*"]
|
|
||||||
rate_limit_per_minute: int = 60
|
rate_limit_per_minute: int = 60
|
||||||
|
|
||||||
model_config = SettingsConfigDict(
|
class Config:
|
||||||
env_file=".env",
|
env_file = ".env"
|
||||||
env_file_encoding="utf-8",
|
env_file_encoding = "utf-8"
|
||||||
case_sensitive=False,
|
case_sensitive = False
|
||||||
extra="ignore",
|
extra = "ignore"
|
||||||
)
|
|
||||||
|
|
||||||
@lru_cache
|
|
||||||
|
# Cached singleton-style access
|
||||||
|
@lru_cache()
|
||||||
def get_settings() -> Settings:
|
def get_settings() -> Settings:
|
||||||
return Settings()
|
return Settings()
|
||||||
|
|
||||||
# Singleton-style access
|
|
||||||
|
# Global settings instance
|
||||||
settings = get_settings()
|
settings = get_settings()
|
||||||
+2
-2
@@ -4,7 +4,7 @@ from sqlalchemy import String, Integer, DateTime, func, Index
|
|||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from app.db.base import Base
|
from app.db.base import Base
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
class URL(Base):
|
class URL(Base):
|
||||||
__tablename__ = "urls"
|
__tablename__ = "urls"
|
||||||
@@ -40,7 +40,7 @@ class URL(Base):
|
|||||||
nullable=False
|
nullable=False
|
||||||
)
|
)
|
||||||
|
|
||||||
last_accessed: Mapped[datetime | None] = mapped_column(
|
last_accessed: Mapped[Optional[datetime]] = mapped_column(
|
||||||
DateTime(timezone=True),
|
DateTime(timezone=True),
|
||||||
nullable=True
|
nullable=True
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ from app.db.models import URL
|
|||||||
from app.utils.short_code import generate_short_code
|
from app.utils.short_code import generate_short_code
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
|
||||||
|
|
||||||
SHORT_CODE_LENGTH = 6
|
SHORT_CODE_LENGTH = 6
|
||||||
MAX_GENERATION_ATTEMPTS = 5
|
MAX_GENERATION_ATTEMPTS = 5
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ import os
|
|||||||
|
|
||||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||||
from app.main import app
|
from app.main import app
|
||||||
from app import settings
|
from app.core.config import settings
|
||||||
import tempfile
|
import tempfile
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# app/utils/short_code.py
|
||||||
|
import string
|
||||||
|
import random
|
||||||
|
|
||||||
|
def generate_short_code(length: int = 6) -> str:
|
||||||
|
"""Generate a random alphanumeric short code."""
|
||||||
|
chars = string.ascii_letters + string.digits
|
||||||
|
return ''.join(random.choices(chars, k=length))
|
||||||
Reference in New Issue
Block a user