Skip to content

Instantly share code, notes, and snippets.

@polyrand
Created November 3, 2020 16:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save polyrand/501d76cae0c06d5ba275183e93636127 to your computer and use it in GitHub Desktop.
Save polyrand/501d76cae0c06d5ba275183e93636127 to your computer and use it in GitHub Desktop.
Example structure of putting a whole app in a single file.
import asyncio
import smtplib
import ssl
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from socket import gaierror
import base64
import datetime as dt
import imghdr
import json
import logging
import os
import secrets
# import datetime as dt
import socket
import sys
import tempfile
import time
import traceback
import uuid
import warnings
from collections import defaultdict
from datetime import datetime, timedelta
from enum import Enum
from functools import partial
from imghdr import what
from os import utime
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
from urllib.parse import quote
from uuid import uuid4
import aiofiles
import databases
import httpx
import numpy as np
import requests
import shortuuid
import sqlalchemy
import telegram
from fastapi import (
APIRouter,
BackgroundTasks,
Depends,
FastAPI,
File,
Form,
HTTPException,
Request,
Response,
Security,
UploadFile,
status,
)
from fastapi.responses import PlainTextResponse, RedirectResponse
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi.security.api_key import APIKey, APIKeyCookie, APIKeyHeader
from fastapi.staticfiles import StaticFiles
from itsdangerous import (
Signer,
TimestampSigner,
URLSafeSerializer,
URLSafeTimedSerializer,
)
from itsdangerous.exc import BadSignature
from jose import JWTError, jwt
from passlib.context import CryptContext
from PIL import Image
from pydantic import (
AnyHttpUrl,
BaseModel,
BaseSettings,
EmailStr,
HttpUrl,
IPvAnyInterface,
PostgresDsn,
validator,
)
from sqlalchemy import (
JSON,
Column,
DateTime,
ForeignKey,
Integer,
String,
Table,
create_engine,
)
from starlette.middleware.cors import CORSMiddleware
from starlette.templating import Jinja2Templates
## ¡¡SETTINGS
class Settings(BaseSettings):
PROJECT_NAME: str
API_V1_STR: str
SECRET_KEY: str
# current module's path
BASE_DIR: Path = Path(__file__).parent
FILES_DIR: Path = BASE_DIR / "files"
TEMPLATES_DIR: Path = FILES_DIR / "templates"
STATIC_DIR: Path = FILES_DIR / "static"
DOCS_DIR: Path = FILES_DIR / "documentation"
# folder that contains the app folder itself (outside)
PARENT_DIR: Optional[Path] = BASE_DIR.parent
# URLS not add in the CORS middleware
BACKEND_CORS_ORIGINS: List[str] = ["localhost", "localhost2"]
SENTRY_DSN: Optional[str] = None
settings = Settings()
## ¡¡LOGGING
FORMAT = "%(levelname)s -- %(message)s"
logging.basicConfig(format=FORMAT)
# main logger
log = logging.getLogger("app")
log.setLevel(logging.INFO)
## ¡¡UTILS
def generate_confirmation_token(email: str) -> str:
return timed_serializer.dumps(email, salt=settings.SALT)
## ¡¡RESOURCES
templates = Jinja2Templates(directory=str(settings.TEMPLATES_DIR))
static = StaticFiles(directory=str(settings.STATIC_DIR))
timed_serializer = URLSafeTimedSerializer(settings.SECRET_KEY)
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def verify_hash(plain_password: str, hashed_password: str) -> bool:
return pwd_context.verify(plain_password, hashed_password)
def get_hash(password: str) -> str:
return pwd_context.hash(password)
## ¡¡DB
metadata = sqlalchemy.MetaData()
users = Table(
"users",
metadata,
Column("user_id", String, primary_key=True, index=True, unique=True),
Column("password", String, nullable=False),
Column("email", String, unique=True, index=True, nullable=False),
Column("website", String, nullable=True),
Column("is_active", Integer, default=1, nullable=False),
Column("is_validated", Integer, default=0, nullable=False),
Column("status", String, default=0, nullable=False),
)
## ¡¡SCHEMAS
class UserBase(BaseModel):
email: Optional[EmailStr] = None
password: str
is_active: Union[bool, int]
level: int
class UserUpdate(UserBase):
password: Optional[str] = None
## ¡¡CRUD
# all the functions that touch the databse directly
## ¡¡EXCEPTIONS
class RequiresLoginException(Exception):
pass
class WrongCredentials(Exception):
pass
## ¡¡DEPS (for dependency injection)
## ¡¡APP
app = FastAPI(
title=settings.PROJECT_NAME,
openapi_url=f"{settings.API_V1_STR}/openapi.json",
docs_url="/docs",
redoc_url="/redoc",
)
if settings.SENTRY_DSN:
import sentry_sdk
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
sentry_sdk.init(dsn=settings.SENTRY_DSN)
app.add_middleware(SentryAsgiMiddleware)
# Set all CORS enabled origins
if settings.BACKEND_CORS_ORIGINS:
app.add_middleware(
CORSMiddleware,
allow_origins=[str(origin) for origin in settings.BACKEND_CORS_ORIGINS],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# mount the static files, in order to access them inside the templates, use
# url_for and the correct path.
# For more info: https://www.starlette.io/templates/
app.mount("/static", StaticFiles(directory=settings.STATIC_DIR), name="static")
app.mount(
"/documentation",
StaticFiles(directory=settings.DOCS_DIR, html=True),
name="documentation",
)
@app.get("/")
async def index(request: Request):
# redirect to documentation while landing page is being set up
return RedirectResponse("/documentation")
@app.get("/documentation")
async def index(request: Request):
return templates.TemplateResponse("documentation.html", {"request": request})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment