diff --git a/.gitignore b/.gitignore index 9aaeae7..1bbc918 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ app/__pycache__ +__pycache__ +.pytest_cache/ venv/ -test.txt \ No newline at end of file +test.txt +diff.txt \ No newline at end of file diff --git a/README.md b/README.md index 507a444..cf24f59 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ source venv/bin/activate ## Run locally ```bash -uvicorn app.main:app --reload +python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 ``` Then check:
http://127.0.0.1:8000
@@ -23,5 +23,5 @@ http://127.0.0.1:8000/shorten ```bash PYTHONPATH=./ pytest export PYTHONPATH=$(pwd) -pytest +python -m pytest --cov=app --cov-report=term-missing ``` \ No newline at end of file diff --git a/app/core/config.py b/app/core/config.py index f55452d..54c8793 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -1,36 +1,38 @@ # app/core/config.py from functools import lru_cache -from pydantic_settings import BaseSettings, SettingsConfigDict +from pydantic import BaseSettings +from typing import List class Settings(BaseSettings): - # App - app_name: str = "URL Shortener API" - debug: bool = False + app_name: str = "URL Shortener" + allowed_hosts: List[str] = ["*"] + database_url: str - # Server + # Server settings host: str = "0.0.0.0" port: int = 8000 base_url: str = "http://localhost:8000" - # Database - database_url: str = "sqlite:///./urls.db" - + # Debug flag + debug: bool = True + # Optional future extensions - allowed_hosts: list[str] = ["*"] rate_limit_per_minute: int = 60 - model_config = SettingsConfigDict( - env_file=".env", - env_file_encoding="utf-8", - case_sensitive=False, - extra="ignore", - ) + class Config: + env_file = ".env" + env_file_encoding = "utf-8" + case_sensitive = False + extra = "ignore" -@lru_cache + +# Cached singleton-style access +@lru_cache() def get_settings() -> Settings: return Settings() -# Singleton-style access + +# Global settings instance settings = get_settings() \ No newline at end of file diff --git a/app/db/models.py b/app/db/models.py index 207dc07..f3c37e5 100644 --- a/app/db/models.py +++ b/app/db/models.py @@ -4,7 +4,7 @@ from sqlalchemy import String, Integer, DateTime, func, Index from sqlalchemy.orm import Mapped, mapped_column from datetime import datetime from app.db.base import Base - +from typing import Optional class URL(Base): __tablename__ = "urls" @@ -40,7 +40,7 @@ class URL(Base): nullable=False ) - last_accessed: Mapped[datetime | None] = mapped_column( + last_accessed: Mapped[Optional[datetime]] = mapped_column( DateTime(timezone=True), nullable=True ) diff --git a/app/services/url_service.py b/app/services/url_service.py index f537085..7c2300d 100644 --- a/app/services/url_service.py +++ b/app/services/url_service.py @@ -9,7 +9,6 @@ from app.db.models import URL from app.utils.short_code import generate_short_code from app.core.config import settings - SHORT_CODE_LENGTH = 6 MAX_GENERATION_ATTEMPTS = 5 diff --git a/app/test_main.py b/app/test_main.py index 9355bf4..bfe170a 100644 --- a/app/test_main.py +++ b/app/test_main.py @@ -4,7 +4,7 @@ import os sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) from app.main import app -from app import settings +from app.core.config import settings import tempfile import pytest diff --git a/app/utils/__init__.py b/app/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/utils/short_code.py b/app/utils/short_code.py new file mode 100644 index 0000000..54cc355 --- /dev/null +++ b/app/utils/short_code.py @@ -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)) \ No newline at end of file diff --git a/test.db b/test.db new file mode 100644 index 0000000..efee9ea Binary files /dev/null and b/test.db differ