Skip to content

Commit c649e25

Browse files
committed
chore: consolidate load_dotenv + remove decorative headers + fix emojis
OPE-86: Consolidate load_dotenv() to single call in main.py - Added load_dotenv() at top of main.py BEFORE any service imports - Removed from: dependencies.py, cache.py, indexer_optimized.py, supabase_service.py (4 duplicate calls) - Prevents import-order-dependent env var issues OPE-74: Remove decorative ASCII headers - Removed '# =====' and '# -----' section dividers from 13 files - Affected: main.py, config/api.py, middleware/auth.py, observability.py, sentry.py, playground_limiter.py, playground.py, supabase_service.py, conftest.py, and 4 test files - Plain section comments retained where they add value OPE-74: Fix emojis in sentry.py startup messages - Replaced emoji print statements with plain text markers: [INFO], [OK], [WARN] Net change: -104 lines (113 deleted, 9 added). 284 tests pass. Closes OPE-86, OPE-74
1 parent c667760 commit c649e25

16 files changed

Lines changed: 9 additions & 113 deletions

backend/config/api.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,11 @@
55
Example: "v1" -> "v2" will change /api/v1/* to /api/v2/*
66
"""
77

8-
# =============================================================================
98
# API VERSION CONFIGURATION
10-
# =============================================================================
119

1210
API_VERSION = "v1"
1311

14-
# =============================================================================
1512
# DERIVED PREFIXES (auto-calculated from version)
16-
# =============================================================================
1713

1814
# Current versioned API prefix: /api/v1
1915
API_PREFIX = f"/api/{API_VERSION}"
@@ -22,9 +18,7 @@
2218
# Routes here will be deprecated but still functional
2319
LEGACY_API_PREFIX = "/api"
2420

25-
# =============================================================================
2621
# DEPRECATION SETTINGS
27-
# =============================================================================
2822

2923
# When True, legacy routes (/api/*) will include deprecation warning headers
3024
LEGACY_DEPRECATION_ENABLED = True
@@ -33,9 +27,7 @@
3327
DEPRECATION_HEADER = "X-API-Deprecated"
3428
DEPRECATION_MESSAGE = f"This endpoint is deprecated. Please use {API_PREFIX} instead."
3529

36-
# =============================================================================
3730
# HELPER FUNCTIONS
38-
# =============================================================================
3931

4032
def get_versioned_prefix() -> str:
4133
"""Get the current versioned API prefix."""

backend/dependencies.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@
33
All route modules import from here to avoid circular imports.
44
"""
55
from fastapi import HTTPException, Depends
6-
from dotenv import load_dotenv
7-
8-
# Load env vars first
9-
load_dotenv()
106

117
from services.indexer_optimized import OptimizedCodeIndexer
128
from services.repo_manager import RepositoryManager

backend/main.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
CodeIntel Backend API
33
FastAPI backend for codebase intelligence
44
"""
5+
# Load environment variables ONCE, before any service imports.
6+
# Do not call load_dotenv() anywhere else in the codebase.
7+
from dotenv import load_dotenv
8+
load_dotenv()
9+
510
from contextlib import asynccontextmanager
611
from fastapi import FastAPI, Request
712
from fastapi.middleware.cors import CORSMiddleware
@@ -51,7 +56,6 @@ async def lifespan(app: FastAPI):
5156
)
5257

5358

54-
# ===== MIDDLEWARE =====
5559

5660
class RequestSizeLimitMiddleware(BaseHTTPMiddleware):
5761
"""Limit request body size to prevent abuse."""
@@ -81,7 +85,6 @@ async def dispatch(self, request: Request, call_next):
8185
)
8286

8387

84-
# ===== ROUTERS =====
8588
# All API routes are prefixed with API_PREFIX (e.g., /api/v1)
8689
# Route files define their sub-path (e.g., /auth, /repos)
8790
# Final paths: /api/v1/auth, /api/v1/repos, etc.
@@ -104,7 +107,6 @@ async def dispatch(self, request: Request, call_next):
104107
app.add_api_websocket_route(f"{API_PREFIX}/ws/repos/{{repo_id}}/indexing", websocket_repo_indexing)
105108

106109

107-
# ===== ERROR HANDLERS =====
108110

109111
@app.exception_handler(RequestValidationError)
110112
async def validation_exception_handler(request: Request, exc: RequestValidationError):

backend/middleware/auth.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ async def demo_search(auth: AuthContext = Depends(public_auth)):
2929
from fastapi.security.http import HTTPAuthorizationCredentials
3030

3131

32-
# ---------------------------------------------------------------------------
3332
# Auth Context - unified return type for all auth methods
34-
# ---------------------------------------------------------------------------
3533

3634
@dataclass
3735
class AuthContext:
@@ -52,17 +50,13 @@ def identifier(self) -> str:
5250
return self.user_id or self.api_key_name or "anonymous"
5351

5452

55-
# ---------------------------------------------------------------------------
5653
# Bearer token scheme (auto_error=False allows optional auth)
57-
# ---------------------------------------------------------------------------
5854

5955
_bearer = HTTPBearer(auto_error=False)
6056
_bearer_required = HTTPBearer(auto_error=True)
6157

6258

63-
# ---------------------------------------------------------------------------
6459
# Core validation functions
65-
# ---------------------------------------------------------------------------
6660

6761
def _validate_jwt(token: str) -> Optional[AuthContext]:
6862
"""Validate Supabase JWT token"""
@@ -143,9 +137,7 @@ def _authenticate(token: str) -> AuthContext:
143137
)
144138

145139

146-
# ---------------------------------------------------------------------------
147140
# FastAPI Dependencies - use these in your routes
148-
# ---------------------------------------------------------------------------
149141

150142
async def require_auth(
151143
credentials: HTTPAuthorizationCredentials = Depends(_bearer_required)
@@ -177,9 +169,7 @@ async def public_auth(
177169
return AuthContext(is_public=True)
178170

179171

180-
# ---------------------------------------------------------------------------
181172
# Legacy functions - kept for backwards compatibility
182-
# ---------------------------------------------------------------------------
183173

184174
async def get_current_user(
185175
credentials: HTTPAuthorizationCredentials = Depends(_bearer_required)

backend/routes/playground.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -785,9 +785,7 @@ async def validate_github_repo(request: ValidateRepoRequest, req: Request):
785785
return result
786786

787787

788-
# =============================================================================
789788
# Anonymous Indexing Endpoint (#125)
790-
# =============================================================================
791789

792790
@router.post("/index", status_code=202)
793791
async def start_anonymous_indexing(
@@ -1030,9 +1028,7 @@ async def start_anonymous_indexing(
10301028
return response_data
10311029

10321030

1033-
# =============================================================================
10341031
# GET /playground/index/{job_id} - Check indexing job status (#126)
1035-
# =============================================================================
10361032

10371033
@router.get(
10381034
"/index/{job_id}",

backend/services/cache.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,9 @@
77
import hashlib
88
from typing import Optional, List, Dict
99
import os
10-
from dotenv import load_dotenv
1110

1211
from services.observability import logger, metrics
1312

14-
load_dotenv()
15-
1613
# Configuration
1714
REDIS_URL = os.getenv("REDIS_URL") # Railway/Cloud Redis URL
1815
REDIS_HOST = os.getenv("REDIS_HOST", "localhost")

backend/services/indexer_optimized.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
# Utils
2929
import hashlib
30-
from dotenv import load_dotenv
3130
import time
3231

3332
# Search enhancement
@@ -39,8 +38,6 @@
3938
# Observability
4039
from services.observability import logger, trace_operation, track_time, capture_exception, add_breadcrumb, metrics
4140

42-
load_dotenv()
43-
4441
# Configuration
4542
# Note: If using existing Pinecone index, match the dimension (1536 for small, 3072 for large)
4643
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "text-embedding-3-small")

backend/services/observability.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ async def index_repo(repo_id: str):
3030
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO" if IS_PRODUCTION else "DEBUG")
3131

3232

33-
# =============================================================================
3433
# STRUCTURED LOGGER
35-
# =============================================================================
3634

3735
class StructuredLogger:
3836
"""
@@ -112,9 +110,7 @@ def critical(self, message: str, **kwargs):
112110
logger = StructuredLogger()
113111

114112

115-
# =============================================================================
116113
# SENTRY INTEGRATION HELPERS
117-
# =============================================================================
118114

119115
def set_operation_context(operation: str, **kwargs):
120116
"""
@@ -191,9 +187,7 @@ def capture_message(message: str, level: str = "info", **context):
191187
pass
192188

193189

194-
# =============================================================================
195190
# PERFORMANCE TRACKING
196-
# =============================================================================
197191

198192
@contextmanager
199193
def track_time(operation: str, **tags):
@@ -307,9 +301,7 @@ def sync_wrapper(*args, **kwargs):
307301
return decorator
308302

309303

310-
# =============================================================================
311304
# SIMPLE METRICS (in-memory counters)
312-
# =============================================================================
313305

314306
class Metrics:
315307
"""

backend/services/playground_limiter.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@
2525
from services.sentry import capture_exception
2626

2727

28-
# =============================================================================
2928
# DATA CLASSES
30-
# =============================================================================
3129

3230
@dataclass
3331
class PlaygroundLimitResult:
@@ -134,9 +132,7 @@ def _truncate_id(session_id: str) -> str:
134132
return session_id
135133

136134

137-
# =============================================================================
138135
# MAIN CLASS
139-
# =============================================================================
140136

141137
class PlaygroundLimiter:
142138
"""
@@ -788,9 +784,7 @@ def get_usage_stats(self) -> dict:
788784
return {"error": str(e), "redis_available": False}
789785

790786

791-
# =============================================================================
792787
# SINGLETON
793-
# =============================================================================
794788

795789
_playground_limiter: Optional[PlaygroundLimiter] = None
796790

backend/services/sentry.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def init_sentry() -> bool:
1919
sentry_dsn = os.getenv("SENTRY_DSN")
2020

2121
if not sentry_dsn:
22-
print("ℹ️ Sentry DSN not configured - error tracking disabled")
22+
print("[INFO] Sentry DSN not configured - error tracking disabled")
2323
return False
2424

2525
try:
@@ -61,14 +61,14 @@ def init_sentry() -> bool:
6161
include_local_variables=True,
6262
)
6363

64-
print(f" Sentry initialized (environment: {environment})")
64+
print(f"[OK] Sentry initialized (environment: {environment})")
6565
return True
6666

6767
except ImportError:
68-
print("⚠️ sentry-sdk not installed - error tracking disabled")
68+
print("[WARN] sentry-sdk not installed - error tracking disabled")
6969
return False
7070
except Exception as e:
71-
print(f"⚠️ Failed to initialize Sentry: {e}")
71+
print(f"[WARN] Failed to initialize Sentry: {e}")
7272
return False
7373

7474

@@ -97,9 +97,7 @@ def _filter_events(event, hint):
9797
return event
9898

9999

100-
# ============================================================================
101100
# LEGACY FUNCTIONS - Use observability module for new code
102-
# ============================================================================
103101

104102
def set_user_context(user_id: Optional[str] = None, email: Optional[str] = None):
105103
"""

0 commit comments

Comments
 (0)