Format everything
This commit is contained in:
parent
ed6c49a1b7
commit
ecfef9a09d
@ -1,9 +1,23 @@
|
|||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
class HouseCreateRequest(BaseModel):
|
|
||||||
address: str = Field(..., min_length=1, max_length=255, description="House address", examples=["123 Main St"])
|
|
||||||
city: str = Field(..., description="City where the house is located", examples=["Springfield"])
|
|
||||||
country: str = Field(..., description="Country where the house is located", examples=["USA"])
|
|
||||||
price: float = Field(..., description="Price of the house", examples=[250000.00])
|
|
||||||
description: str = Field(..., description="Description of the house", examples=["A beautiful 3-bedroom house"])
|
|
||||||
|
|
||||||
|
class HouseCreateRequest(BaseModel):
|
||||||
|
address: str = Field(
|
||||||
|
...,
|
||||||
|
min_length=1,
|
||||||
|
max_length=255,
|
||||||
|
description="House address",
|
||||||
|
examples=["123 Main St"],
|
||||||
|
)
|
||||||
|
city: str = Field(
|
||||||
|
..., description="City where the house is located", examples=["Springfield"]
|
||||||
|
)
|
||||||
|
country: str = Field(
|
||||||
|
..., description="Country where the house is located", examples=["USA"]
|
||||||
|
)
|
||||||
|
price: float = Field(..., description="Price of the house", examples=[250000.00])
|
||||||
|
description: str = Field(
|
||||||
|
...,
|
||||||
|
description="Description of the house",
|
||||||
|
examples=["A beautiful 3-bedroom house"],
|
||||||
|
)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class HouseCreateResponse(BaseModel):
|
class HouseCreateResponse(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class HouseResponse(BaseModel):
|
class HouseResponse(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
description: str
|
description: str
|
||||||
@ -8,5 +9,6 @@ class HouseResponse(BaseModel):
|
|||||||
country: str
|
country: str
|
||||||
price: float
|
price: float
|
||||||
|
|
||||||
|
|
||||||
class HousesListResponse(BaseModel):
|
class HousesListResponse(BaseModel):
|
||||||
houses: list[HouseResponse]
|
houses: list[HouseResponse]
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class OwnerDetailResponse(BaseModel):
|
class OwnerDetailResponse(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
user_id: str
|
user_id: str
|
||||||
email: str
|
email: str
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class OwnerResponse(BaseModel):
|
class OwnerResponse(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
user_id: str
|
user_id: str
|
||||||
|
|||||||
@ -8,11 +8,13 @@ from .middleware.authenticate import authenticate
|
|||||||
|
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(_app: FastAPI):
|
async def lifespan(_app: FastAPI):
|
||||||
create_db_and_tables()
|
create_db_and_tables()
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="Fair Housing API",
|
title="Fair Housing API",
|
||||||
description="Provides access to core functionality for the fair housing platform.",
|
description="Provides access to core functionality for the fair housing platform.",
|
||||||
|
|||||||
@ -3,7 +3,10 @@ from typing import Annotated
|
|||||||
from ..settings import get_settings
|
from ..settings import get_settings
|
||||||
from ..repositories.user_repository import UserRepository
|
from ..repositories.user_repository import UserRepository
|
||||||
|
|
||||||
async def authenticate(request: Request, user_repository: Annotated[UserRepository, Depends()]) -> bool:
|
|
||||||
|
async def authenticate(
|
||||||
|
request: Request, user_repository: Annotated[UserRepository, Depends()]
|
||||||
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Authenticate the current request.
|
Authenticate the current request.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
from sqlmodel import SQLModel, Field
|
from sqlmodel import SQLModel, Field
|
||||||
from uuid import uuid4, UUID
|
from uuid import uuid4, UUID
|
||||||
|
|
||||||
|
|
||||||
class House(SQLModel, table=True):
|
class House(SQLModel, table=True):
|
||||||
id: UUID = Field(primary_key=True, default_factory=uuid4)
|
id: UUID = Field(primary_key=True, default_factory=uuid4)
|
||||||
address: str = Field()
|
address: str = Field()
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
from sqlmodel import SQLModel, Field
|
from sqlmodel import SQLModel, Field
|
||||||
from uuid import uuid4, UUID
|
from uuid import uuid4, UUID
|
||||||
|
|
||||||
|
|
||||||
class Owner(SQLModel, table=True):
|
class Owner(SQLModel, table=True):
|
||||||
id: UUID = Field(default_factory=uuid4, primary_key=True)
|
id: UUID = Field(default_factory=uuid4, primary_key=True)
|
||||||
user_id: UUID = Field(foreign_key="user.id", unique=True)
|
user_id: UUID = Field(foreign_key="user.id", unique=True)
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
from sqlmodel import SQLModel, Field
|
from sqlmodel import SQLModel, Field
|
||||||
from uuid import uuid4, UUID
|
from uuid import uuid4, UUID
|
||||||
|
|
||||||
|
|
||||||
class User(SQLModel, table=True):
|
class User(SQLModel, table=True):
|
||||||
id: UUID = Field(default_factory=lambda: uuid4(), primary_key=True)
|
id: UUID = Field(default_factory=lambda: uuid4(), primary_key=True)
|
||||||
email: str = Field(unique=True, nullable=False)
|
email: str = Field(unique=True, nullable=False)
|
||||||
|
|||||||
@ -6,6 +6,7 @@ from ..repositories.user_repository import UserRepository
|
|||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
from fastapi import Depends, Request
|
from fastapi import Depends, Request
|
||||||
|
|
||||||
|
|
||||||
class AuthContext:
|
class AuthContext:
|
||||||
"""
|
"""
|
||||||
Provides authentication context for the current request.
|
Provides authentication context for the current request.
|
||||||
@ -16,7 +17,9 @@ class AuthContext:
|
|||||||
request: Request,
|
request: Request,
|
||||||
) -> None:
|
) -> None:
|
||||||
if not get_settings().environment == "development":
|
if not get_settings().environment == "development":
|
||||||
raise NotImplementedError("AuthProvider is only implemented for development environment.")
|
raise NotImplementedError(
|
||||||
|
"AuthProvider is only implemented for development environment."
|
||||||
|
)
|
||||||
|
|
||||||
self._authenticated_user = request.state.user
|
self._authenticated_user = request.state.user
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
from collections.abc import AsyncGenerator
|
from collections.abc import AsyncGenerator
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from sqlalchemy import Engine
|
from sqlalchemy import Engine
|
||||||
@ -21,9 +20,9 @@ settings = get_settings()
|
|||||||
|
|
||||||
async def _get_async_engine() -> AsyncEngine:
|
async def _get_async_engine() -> AsyncEngine:
|
||||||
return create_async_engine(
|
return create_async_engine(
|
||||||
f"postgresql+asyncpg://{settings.db.username}:{settings.db.password}@{settings.db.host}:{settings.db.port}/{settings.db.db_name}",
|
f"postgresql+asyncpg://{settings.db.username}:{settings.db.password}@{settings.db.host}:{settings.db.port}/{settings.db.db_name}",
|
||||||
future=True,
|
future=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def get_session() -> AsyncGenerator[AsyncSession, None]:
|
async def get_session() -> AsyncGenerator[AsyncSession, None]:
|
||||||
@ -64,7 +63,9 @@ def _seed_db():
|
|||||||
|
|
||||||
session = Session(_get_engine())
|
session = Session(_get_engine())
|
||||||
|
|
||||||
existing_user = session.query(User).filter(User.email == settings.app.mock_user_email).first()
|
existing_user = (
|
||||||
|
session.query(User).filter(User.email == settings.app.mock_user_email).first()
|
||||||
|
)
|
||||||
if not existing_user:
|
if not existing_user:
|
||||||
mock_user = User(
|
mock_user = User(
|
||||||
email=settings.app.mock_user_email,
|
email=settings.app.mock_user_email,
|
||||||
@ -80,4 +81,3 @@ def create_db_and_tables():
|
|||||||
engine = _get_engine()
|
engine = _get_engine()
|
||||||
SQLModel.metadata.create_all(engine)
|
SQLModel.metadata.create_all(engine)
|
||||||
_seed_db()
|
_seed_db()
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ from sqlmodel import select
|
|||||||
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
|
|
||||||
class HouseRepository:
|
class HouseRepository:
|
||||||
def __init__(self, session: Annotated[AsyncSession, Depends(get_session)]) -> None:
|
def __init__(self, session: Annotated[AsyncSession, Depends(get_session)]) -> None:
|
||||||
self.session = session
|
self.session = session
|
||||||
|
|||||||
@ -7,6 +7,7 @@ from sqlmodel import select
|
|||||||
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
|
|
||||||
class OwnerRepository:
|
class OwnerRepository:
|
||||||
def __init__(self, session: Annotated[AsyncSession, Depends(get_session)]) -> None:
|
def __init__(self, session: Annotated[AsyncSession, Depends(get_session)]) -> None:
|
||||||
self.session = session
|
self.session = session
|
||||||
|
|||||||
@ -7,6 +7,7 @@ from sqlmodel import select
|
|||||||
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
|
|
||||||
class UserRepository:
|
class UserRepository:
|
||||||
def __init__(self, session: Annotated[AsyncSession, Depends(get_session)]) -> None:
|
def __init__(self, session: Annotated[AsyncSession, Depends(get_session)]) -> None:
|
||||||
self.session = session
|
self.session = session
|
||||||
|
|||||||
@ -11,14 +11,18 @@ from ..dtos.houses_list_response import HousesListResponse, HouseResponse
|
|||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@router.post("")
|
@router.post("")
|
||||||
async def create_house(body: HouseCreateRequest, auth: Annotated[AuthContext, Depends()], house_repository: Annotated[HouseRepository, Depends()], owner_repository: Annotated[OwnerRepository, Depends()]) -> HouseCreateResponse:
|
async def create_house(
|
||||||
|
body: HouseCreateRequest,
|
||||||
|
auth: Annotated[AuthContext, Depends()],
|
||||||
|
house_repository: Annotated[HouseRepository, Depends()],
|
||||||
|
owner_repository: Annotated[OwnerRepository, Depends()],
|
||||||
|
) -> HouseCreateResponse:
|
||||||
owner = await owner_repository.get_by_id(auth.user.id)
|
owner = await owner_repository.get_by_id(auth.user.id)
|
||||||
|
|
||||||
if not owner:
|
if not owner:
|
||||||
new_owner = Owner(
|
new_owner = Owner(user_id=auth.user.id)
|
||||||
user_id=auth.user.id
|
|
||||||
)
|
|
||||||
|
|
||||||
await owner_repository.save(new_owner)
|
await owner_repository.save(new_owner)
|
||||||
|
|
||||||
@ -28,24 +32,33 @@ async def create_house(body: HouseCreateRequest, auth: Annotated[AuthContext, De
|
|||||||
city=body.city,
|
city=body.city,
|
||||||
country=body.country,
|
country=body.country,
|
||||||
price=body.price,
|
price=body.price,
|
||||||
description=body.description
|
description=body.description,
|
||||||
)
|
)
|
||||||
|
|
||||||
await house_repository.save(house)
|
await house_repository.save(house)
|
||||||
|
|
||||||
return HouseCreateResponse(
|
return HouseCreateResponse(id=str(house.id))
|
||||||
id=str(house.id)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("")
|
@router.get("")
|
||||||
async def get_all_houses(house_repository: Annotated[HouseRepository, Depends()], limit: int = 100, offset: int = 0) -> HousesListResponse:
|
async def get_all_houses(
|
||||||
|
house_repository: Annotated[HouseRepository, Depends()],
|
||||||
|
limit: int = 100,
|
||||||
|
offset: int = 0,
|
||||||
|
) -> HousesListResponse:
|
||||||
all_houses = await house_repository.get_all(offset=offset, limit=limit)
|
all_houses = await house_repository.get_all(offset=offset, limit=limit)
|
||||||
|
|
||||||
house_responses = ([HouseResponse(id=str(house.id), description=house.description, address=house.address, city=house.city, country=house.country, price=house.price) for house in all_houses])
|
house_responses = [
|
||||||
|
HouseResponse(
|
||||||
|
id=str(house.id),
|
||||||
|
description=house.description,
|
||||||
|
address=house.address,
|
||||||
|
city=house.city,
|
||||||
|
country=house.country,
|
||||||
|
price=house.price,
|
||||||
|
)
|
||||||
|
for house in all_houses
|
||||||
|
]
|
||||||
print(house_responses)
|
print(house_responses)
|
||||||
|
|
||||||
return HousesListResponse(
|
return HousesListResponse(houses=house_responses)
|
||||||
houses=house_responses
|
|
||||||
)
|
|
||||||
|
|||||||
@ -10,22 +10,27 @@ router = APIRouter()
|
|||||||
|
|
||||||
|
|
||||||
@router.get("")
|
@router.get("")
|
||||||
async def get_owners(owner_repository: Annotated[OwnerRepository, Depends()]) -> OwnerListResponse:
|
async def get_owners(
|
||||||
|
owner_repository: Annotated[OwnerRepository, Depends()],
|
||||||
|
) -> OwnerListResponse:
|
||||||
owners = await owner_repository.get_all()
|
owners = await owner_repository.get_all()
|
||||||
|
|
||||||
owners_response = [OwnerResponse(id=str(owner.id), user_id=str(owner.user_id)) for owner in owners]
|
owners_response = [
|
||||||
|
OwnerResponse(id=str(owner.id), user_id=str(owner.user_id)) for owner in owners
|
||||||
|
]
|
||||||
|
|
||||||
|
return OwnerListResponse(owners=owners_response)
|
||||||
|
|
||||||
return OwnerListResponse(
|
|
||||||
owners=owners_response
|
|
||||||
)
|
|
||||||
|
|
||||||
@router.get("/{id}")
|
@router.get("/{id}")
|
||||||
async def get_owner(id: str, owner_repository: Annotated[OwnerRepository, Depends()], user_repository: Annotated[UserRepository, Depends()]) -> OwnerDetailResponse:
|
async def get_owner(
|
||||||
|
id: str,
|
||||||
|
owner_repository: Annotated[OwnerRepository, Depends()],
|
||||||
|
user_repository: Annotated[UserRepository, Depends()],
|
||||||
|
) -> OwnerDetailResponse:
|
||||||
owner = await owner_repository.get_by_id(id)
|
owner = await owner_repository.get_by_id(id)
|
||||||
user = await user_repository.get_by_id(owner.user_id)
|
user = await user_repository.get_by_id(owner.user_id)
|
||||||
|
|
||||||
return OwnerDetailResponse(
|
return OwnerDetailResponse(
|
||||||
id=str(owner.id),
|
id=str(owner.id), user_id=str(owner.user_id), email=user.email
|
||||||
user_id=str(owner.user_id),
|
|
||||||
email=user.email
|
|
||||||
)
|
)
|
||||||
@ -20,7 +20,9 @@ class HousePricePredictor:
|
|||||||
# Mock initialization - in reality would load model weights
|
# Mock initialization - in reality would load model weights
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def predict(self, square_feet: float, bedrooms: int, bathrooms: float) -> Prediction:
|
def predict(
|
||||||
|
self, square_feet: float, bedrooms: int, bathrooms: float
|
||||||
|
) -> Prediction:
|
||||||
"""
|
"""
|
||||||
Mock prediction method that returns:
|
Mock prediction method that returns:
|
||||||
- predicted price
|
- predicted price
|
||||||
@ -37,8 +39,7 @@ class HousePricePredictor:
|
|||||||
# Add some randomness to make it interesting
|
# Add some randomness to make it interesting
|
||||||
confidence_score = random.uniform(0.8, 0.99)
|
confidence_score = random.uniform(0.8, 0.99)
|
||||||
similar_listings = [
|
similar_listings = [
|
||||||
predicted_price * random.uniform(0.9, 1.1)
|
predicted_price * random.uniform(0.9, 1.1) for _ in range(3)
|
||||||
for _ in range(3)
|
|
||||||
]
|
]
|
||||||
|
|
||||||
return Prediction(predicted_price, confidence_score, similar_listings)
|
return Prediction(predicted_price, confidence_score, similar_listings)
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
class InvestorPredictor():
|
|
||||||
|
class InvestorPredictor:
|
||||||
def is_investor(user: User) -> bool:
|
def is_investor(user: User) -> bool:
|
||||||
return random.random() < 0.5
|
return random.random() < 0.5
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
|
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
@ -9,12 +8,15 @@ import os
|
|||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
|
|
||||||
class _BaseConfig(BaseSettings):
|
class _BaseConfig(BaseSettings):
|
||||||
environment: str = Field(default=os.getenv("ENVIRONMENT", "development"))
|
environment: str = Field(default=os.getenv("ENVIRONMENT", "development"))
|
||||||
|
|
||||||
|
|
||||||
class _AppSettings(_BaseConfig):
|
class _AppSettings(_BaseConfig):
|
||||||
mock_user_email: str = "test@test.com"
|
mock_user_email: str = "test@test.com"
|
||||||
|
|
||||||
|
|
||||||
class _DbSettings(_BaseConfig):
|
class _DbSettings(_BaseConfig):
|
||||||
username: str = Field(default=os.getenv("PG_USER"))
|
username: str = Field(default=os.getenv("PG_USER"))
|
||||||
password: str = Field(default=os.getenv("PG_PASSWORD"))
|
password: str = Field(default=os.getenv("PG_PASSWORD"))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user