Skip to content

Commit b2047dd

Browse files
committed
fix: pycache, init added to gitignore
1 parent 6b476a8 commit b2047dd

File tree

71 files changed

+648
-204
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+648
-204
lines changed

.gitignore

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
node_modules
22
.vscode
33
.coverage
4-
__pycache__/
4+
*__pycache__/
5+
*/__pycache__/*
6+
*/__init__.cpython-312.pyc
7+
*__init__*
58
*.py[cod]
69
*$py.class
710
src/quant_research_starter.egg-info/PKG-INFO
@@ -16,14 +19,14 @@ dist/
1619
*.egg
1720
pip-wheel-metadata/
1821
output/
19-
20-
__pycache__/
2122
*.py[cod]
2223
*.pyo
2324
*.pyd
2425
*.log
2526
.vscode/
2627
.idea/
27-
\.venv\
28-
.venv\
29-
\.venv
28+
\.venv
29+
.env
30+
.env.local
31+
*.env
32+
*.env.local

pytest.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[pytest]
2+
pythonpath = src
3+
addopts = -q

requirements-dev.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Developer and test dependencies for running the test suite locally
2+
# Install with: pip install -r requirements-dev.txt
3+
4+
# testing and async test helpers
5+
pytest
6+
pytest-asyncio
7+
httpx
8+
9+
# optional/runtime packages used by the API and tasks
10+
python-jose[cryptography]
11+
passlib[bcrypt]
12+
asyncpg
13+
celery
14+
redis
15+
alembic
16+
17+
# DB / ORM
18+
SQLAlchemy>=1.4

src/quant_research_starter/__init__.py

Lines changed: 0 additions & 23 deletions
This file was deleted.
-971 Bytes
Binary file not shown.
-820 Bytes
Binary file not shown.
-10.9 KB
Binary file not shown.
-9.79 KB
Binary file not shown.

src/quant_research_starter/api/__init__.py

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/quant_research_starter/api/auth.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import os
66
from datetime import datetime, timedelta
7-
from typing import Optional
7+
from typing import Annotated, Optional
88

99
from fastapi import Depends, HTTPException, status
1010
from fastapi.security import OAuth2PasswordBearer
@@ -13,12 +13,14 @@
1313
from sqlalchemy.ext.asyncio import AsyncSession
1414

1515
from . import db, models
16+
from . import supabase
17+
import secrets
1618

1719
SECRET_KEY = os.getenv("JWT_SECRET", "dev-secret-change-me")
1820
ALGORITHM = "HS256"
1921
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("JWT_EXPIRE_MINUTES", "60"))
2022

21-
pwd_ctx = CryptContext(schemes=["bcrypt"], deprecated="auto")
23+
pwd_ctx = CryptContext(schemes=["pbkdf2_sha256"], deprecated="auto")
2224
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/token")
2325

2426

@@ -41,20 +43,48 @@ def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -
4143

4244

4345
async def get_current_user(
44-
token: str = Depends(oauth2_scheme), session: AsyncSession = Depends(db.get_session)
46+
token: Annotated[str, Depends(oauth2_scheme)],
47+
session: Annotated[AsyncSession, Depends(db.get_session)],
4548
):
4649
credentials_exception = HTTPException(
4750
status_code=status.HTTP_401_UNAUTHORIZED,
4851
detail="Could not validate credentials",
4952
headers={"WWW-Authenticate": "Bearer"},
5053
)
54+
# If Supabase is configured, prefer verifying tokens via Supabase
55+
if supabase.is_enabled():
56+
user_info = supabase.get_user_from_token(token)
57+
if not user_info:
58+
raise credentials_exception
59+
# Map/ensure a local user exists for this supabase user (by email)
60+
email = user_info.get("email")
61+
if not email:
62+
raise credentials_exception
63+
64+
q = await session.execute(
65+
models.User.__table__.select().where(models.User.username == email)
66+
)
67+
row = q.first()
68+
if row:
69+
return row[0]
70+
71+
# Create a local user mapping (no password — managed by Supabase)
72+
random_pw = secrets.token_urlsafe(32)
73+
hashed = pwd_ctx.hash(random_pw)
74+
user = models.User(username=email, hashed_password=hashed)
75+
session.add(user)
76+
await session.commit()
77+
await session.refresh(user)
78+
return user
79+
80+
# Local JWT flow
5181
try:
5282
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
5383
username: str = payload.get("sub")
5484
if username is None:
5585
raise credentials_exception
5686
except JWTError:
57-
raise credentials_exception
87+
raise credentials_exception from None
5888

5989
q = await session.execute(
6090
models.User.__table__.select().where(models.User.username == username)
@@ -66,7 +96,7 @@ async def get_current_user(
6696
return user
6797

6898

69-
async def require_active_user(current_user=Depends(get_current_user)):
99+
async def require_active_user(current_user: Annotated[models.User, Depends(get_current_user)]):
70100
if not current_user.is_active:
71101
raise HTTPException(status_code=400, detail="Inactive user")
72102
return current_user

0 commit comments

Comments
 (0)