Python - kdevkr/mambo-box GitHub Wiki
ํ์ด์ฌ ๊ฐ์ํ๊ฒฝ
- Colab: ๊ตฌ๊ธ์ด ๋ฌด๋ฃ๋ก ์ ๊ณตํ๋ ์ฃผํผํฐ ๋ ธํธ๋ถ(Jupyter Notebook) ํ๊ฒฝ
- Anaconda: ์ฃผํผํฐ ๋ ธํธ๋ถ ํ๊ฒฝ์ ๋ก์ปฌ์ ์คํํ๊ธฐ ์ํ ํ๋ก๊ทธ๋จ
- virtualenv, pip, venv, pyenv, pipenv...
- Poetry: Python packaging and dependency management made easy
- PDM, Rye...
- uv: Python packaging in Rust
# Install uv on macOS.
$ curl -LsSf https://astral.sh/uv/install.sh | sh
# Use a specific Python version in the current directory:
$ uv python pin 3.12
Pinned `.python-version` to `3.12`
$ echo 'eval "$(uv generate-shell-completion zsh)"' >> ~/.zshrc
ํ์ด์ฌ SQL
uv add databases aiosqlite sqlalchemy
- databases
- aiosqlite
- sqlalchemy
db.py
import sqlalchemy
from sqlalchemy import MetaData
from databases import Database
database = Database('sqlite+aiosqlite:///local.db')
engine = sqlalchemy.create_engine(str(database.url).replace("+aiosqlite", ''), echo=True)
metadata = MetaData()
metadata.create_all(engine)
models.py
import sqlalchemy
from sqlalchemy import Table, Column, Integer, String, DateTime, Text
from db import metadata
request_logs = Table(
"request_logs",
metadata,
Column("id", Integer, primary_key=True),
Column("method", String, nullable=False),
Column("path", String, nullable=False),
Column("request_headers", Text, nullable=False),
Column("request_params", Text, nullable=True),
Column("request_body", Text, nullable=True),
Column("client_ip", String, nullable=False),
Column("server_ip", String, nullable=False),
Column("response_status", Integer, nullable=False),
Column("response_headers", Text, nullable=False),
Column("response_body", Text, nullable=True),
Column("created_at", DateTime, server_default=sqlalchemy.text("CURRENT_TIMESTAMP")),
)
main.py
from fastapi import FastAPI, Request, Response
from contextlib import asynccontextmanager
from db import database
from models import request_logs
import json
import socket
server_ip = socket.gethostbyname(socket.gethostname())
@asynccontextmanager
async def lifespan(app: FastAPI):
await database.connect()
yield
await database.disconnect()
app = FastAPI(lifespan=lifespan)
@app.middleware("http")
async def log_request(request: Request, call_next):
try:
request_params = await request.json()
except Exception:
request_params = dict(request.query_params)
request_body = await request.body()
response = await call_next(request)
chunks = []
async for chunk in response.body_iterator:
chunks.append(chunk)
response_body = b"".join(chunks)
log_data = {
"method": request.method,
"path": request.url.path,
"request_headers": json.dumps(dict(request.headers)),
"request_params": json.dumps(request_params),
"request_body": request_body.decode("utf-8", errors="ignore"),
"client_ip": request.client.host,
"server_ip": server_ip,
"response_status": response.status_code,
"response_headers": json.dumps(dict(response.headers)),
"response_body": response_body.decode("utf-8", errors="ignore"),
}
await database.execute(request_logs.insert().values(**log_data))
return Response(
content=response_body,
status_code=response.status_code,
headers=dict(response.headers),
media_type=response.media_type,
)
@app.get("/")
async def root():
return {"message": "Hello World"}
db_async.py
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker, declarative_base
DB_URL = 'sqlite+aiosqlite:///local.db'
Base = declarative_base()
engine = create_async_engine(DB_URL, echo=True)
SessionLocal = sessionmaker(
bind=engine,
autocommit=False,
autoflush=False,
expire_on_commit=False,
class_=AsyncSession,
)
async def init_db():
async with engine.connect() as conn:
await conn.run_sync(Base.metadata.create_all) # NOTE: ๋๊ธฐ์ ํธ์ถ
ํ ์ด๋ธ์ ์ ์ํ ๋๋ databases๋ฅผ ์ด์ฉํ ์ ์์ผ๋ฏ๋ก SQLAlchemy๋ฅผ ์ง์ ์ฌ์ฉํด์ผํ๋ค. ๋ค๋ง, create_all ํจ์๋ ๋๊ธฐ์ ํธ์ถ์ ์๊ตฌํ๋ฏ๋ก create_async_engine ์ sessionmaker ๋ฅผ ์ฌ์ฉํ๋ ์ฝ๋๋ฅผ ๊ตณ์ด ์์ฑํ ํ์๋ ์๋ค.