Created
November 3, 2020 16:22
-
-
Save polyrand/501d76cae0c06d5ba275183e93636127 to your computer and use it in GitHub Desktop.
Example structure of putting a whole app in a single file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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