Skip to content

Commit

Permalink
Merge pull request #13 from leosussan/leo/pre-commit
Browse files Browse the repository at this point in the history
Pre-Commit
  • Loading branch information
leosussan committed May 13, 2020
2 parents 0cb613a + ba68eb4 commit c19017a
Show file tree
Hide file tree
Showing 16 changed files with 276 additions and 41 deletions.
9 changes: 9 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[flake8]
ignore = E203, E266, E501, W503, F403, F401
max-line-length = 79
max-complexity = 18
select = B,C,E,F,W,T4,B9
per-file-ignores =
app/models/orm/migrations/env.py:E402
app/main.py:E402
app/worker.py:E402
25 changes: 25 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
repos:
- repo: https://github.com/asottile/seed-isort-config
rev: v2.1.1
hooks:
- id: seed-isort-config
args: [--application-directories, "./app:./"]
- repo: https://github.com/pre-commit/mirrors-isort
rev: v4.3.21
hooks:
- id: isort
additional_dependencies: ["toml"]
- repo: https://github.com/ambv/black
rev: stable
hooks:
- id: black
- repo: https://gitlab.com/pycqa/flake8
rev: 3.7.9
hooks:
- id: flake8
additional_dependencies: [
"git+https://github.com/PyCQA/pyflakes#egg=pyflakes",
"git+https://gitlab.com/PyCQA/pycodestyle#egg=pycodestyle",
]
default_language_version:
python: python3.8
52 changes: 38 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,52 @@
# fastapi-gino-arq-uvicorn
High-performance Async REST API, in Python. FastAPI + GINO + Arq + Uvicorn (powered by Redis & PostgreSQL).

## Get Started
### Run Locally
_NOTE: You must have PostgreSQL & Redis running locally._
## Contents
* [Get Started](#get-started)
* [Setup](#setup)
* [Run](#run)
* [Run Locally](#run-locally)
* [Run Locally with Docker-Compose](#run-locally-with-docker-compose)
* [Build Your Application](#build-your-application)
* [Features](#features)
* [Core Dependencies](#core-dependencies)
* [Additional Dependencies](#additional-dependencies)

## Get Started
### Setup
1. Clone this Repository. `git clone https://github.com/leosussan/fastapi-gino-arq-uvicorn.git`
2. Install `Python 3.8` and `poetry`.
* _RECOMMENDED_: use `asdf`, which is like `pyenv` / `nvm` / `gvm` for everything.
* [Install](https://asdf-vm.com/#/core-manage-asdf-vm?id=install-asdf-vm), then run `asdf plugin add python`, `asdf plugin add poetry`, and `asdf install`
3. Run `poetry install` from root.
4. Make a copy of `.dist.env`, rename to `.env`. Fill in PostgreSQL, Redis connection vars.
5. Generate DB Migrations: `alembic revision --autogenerate`. It will be applied when the application starts. You can trigger manually with `alembic upgrade head`.
6. Run:
* Recommended Method: `asdf` - a universal version manager (think `nvm` or `pyenv`)
* Follow [these instructions](https://asdf-vm.com/#/core-manage-asdf-vm?id=install-asdf-vm) to install `asdf`.
* Run the following commands from the project root:
* `asdf plugin add python`
* `asdf plugin add poetry`
* `asdf install` -- will download & configure this project's `Python` + `poetry` setup
* If you have `Python 3.8` and `poetry` installed already, please feel free to skip.
3. Install dependencies (`poetry install`).
4. Activate pre-commit hooks (in `poetry shell`, run `pre-commit install`).
5. Make a copy of `.dist.env`, rename to `.env`. Fill in PostgreSQL, Redis, Sentry (optional) variables.
6. Generate DB Migrations: in `poetry shell`, run `alembic revision --autogenerate`.
* Apply migrations manually with `alembic upgrade head`.
* If using the Dockerfile, migrations are applied at startup.

### Run

#### Run Locally
_NOTE: You must have PostgreSQL & Redis running locally._

1. Make sure PostgreSQL & Redis are running locally.
2. Run:
- FastAPI Application:
* _For Active Development (w/ auto-reload):_ Run locally with `poetry run task app`
* _For Debugging (compatible w/ debuggers, no auto-reload):_ Configure debugger to run `python app/main.py`.
- Background Task Worker:
* _For Active Development:_ Run `poetry run task worker`

### Run Locally with Docker-Compose
1. Clone this Repository. `git clone https://github.com/leosussan/fastapi-gino-arq-uvicorn.git`
2. Generate a DB Migration: `alembic revision --autogenerate`.*
3. Run locally using docker-compose. `poetry run task compose-up`.
* Run `poetry run task compose-down` to spin down, clean up.
#### Run Locally with Docker-Compose.
1. Make sure `Docker` is running locally.
2. Run `poetry run task compose-up`*.
- Run `poetry run task compose-down` to spin down, clean up.

*`app/settings/prestart.sh` will run migrations for you before the app starts.

Expand Down Expand Up @@ -53,4 +76,5 @@ _NOTE: You must have PostgreSQL & Redis running locally._
* **Alembic:** Handles database migrations. Compatible with GINO.
* **SQLAlchemy_Utils:** Provides essential handles & datatypes. Compatible with GINO.
* **Sentry:** Open-source, cloud-hosted error + event monitoring.
* **Pre-Commit:** automatic formatting (`black` + `isort`) and linting (`flake8`).
* **Taskipy:** Small, flexible task runner for Poetry.
5 changes: 2 additions & 3 deletions app/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
from gino.ext.starlette import Gino
from sentry_sdk import init as initialize_sentry
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
from starlette.datastructures import Secret
from sqlalchemy.schema import MetaData
from starlette.datastructures import Secret

from .settings.globals import DATABASE_CONFIG, SENTRY_DSN

if isinstance(SENTRY_DSN, Secret) and SENTRY_DSN.__str__() not in ("None", ""):
initialize_sentry(
dsn=SENTRY_DSN.__str__(),
integrations=[SqlalchemyIntegration()]
dsn=SENTRY_DSN.__str__(), integrations=[SqlalchemyIntegration()]
)

app: FastAPI = FastAPI()
Expand Down
2 changes: 2 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# isort:skip_file

import sys

sys.path.extend(["./"])
Expand Down
10 changes: 8 additions & 2 deletions app/models/orm/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@
@generic_repr
class Base(db.Model):
__abstract__ = True
created_on = db.Column(db.DateTime, default=datetime.utcnow, server_default=db.func.now())
created_on = db.Column(
db.DateTime, default=datetime.utcnow, server_default=db.func.now()
)
updated_on = db.Column(
db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, server_default=db.func.now())
db.DateTime,
default=datetime.utcnow,
onupdate=datetime.utcnow,
server_default=db.func.now(),
)
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
32 changes: 20 additions & 12 deletions app/models/orm/migrations/env.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
# Native libraries
# isort:skip_file

import sys
sys.path.extend(['./'])

sys.path.extend(["./"])

from logging.config import fileConfig

from sqlalchemy import engine_from_config, pool
from alembic import context

from app.settings.globals import ALEMBIC_CONFIG

######################## --- MODELS FOR MIGRATIONS --- ########################
from app.application import db
from app.models.orm.user import User

# To include a model in migrations, add a line here.
# from app.models.orm.person import Person

###############################################################################

# Third party packages
from sqlalchemy import engine_from_config, pool
from alembic import context
from logging.config import fileConfig

# App imports
from app.settings.globals import ALEMBIC_CONFIG

config = context.config
fileConfig(config.config_file_name)
target_metadata = db
Expand All @@ -36,7 +38,9 @@ def run_migrations_offline():
"""
context.configure(
url=ALEMBIC_CONFIG.url.__to_string__(hide_password=False), target_metadata=target_metadata, literal_binds=True
url=ALEMBIC_CONFIG.url.__to_string__(hide_password=False),
target_metadata=target_metadata,
literal_binds=True,
)

with context.begin_transaction():
Expand All @@ -51,7 +55,11 @@ def run_migrations_online():
"""
connectable = engine_from_config(
{"sqlalchemy.url": ALEMBIC_CONFIG.url.__to_string__(hide_password=False)},
{
"sqlalchemy.url": ALEMBIC_CONFIG.url.__to_string__(
hide_password=False
)
},
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
Expand Down
2 changes: 1 addition & 1 deletion app/models/orm/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


class User(Base):
__tablename__ = 'users'
__tablename__ = "users"
name = db.Column(db.String(255))
email = db.Column(db.EmailType)
phone_number = db.Column(db.Unicode(20))
Expand Down
3 changes: 2 additions & 1 deletion app/models/pydantic/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pydantic import BaseModel
from datetime import datetime

from pydantic import BaseModel


class Base(BaseModel):
id: int
Expand Down
3 changes: 2 additions & 1 deletion app/models/pydantic/user.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pydantic import EmailStr, BaseModel
from typing import Optional

from pydantic import BaseModel, EmailStr

from .base import Base


Expand Down
2 changes: 1 addition & 1 deletion app/routes/users.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from arq.connections import create_pool, ArqRedis
from arq.connections import ArqRedis, create_pool
from fastapi import APIRouter

from ..models.orm.user import User as ORMUser
Expand Down
2 changes: 1 addition & 1 deletion app/settings/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Optional

from starlette.config import Config
from starlette.datastructures import Secret, CommaSeparatedStrings
from starlette.datastructures import CommaSeparatedStrings, Secret

from ..models.pydantic.database import DatabaseURL

Expand Down
2 changes: 1 addition & 1 deletion app/tasks/messaging.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from ..application import db
from ..models.pydantic.user import User
from ..models.orm.user import User as ORMUser
from ..models.pydantic.user import User


async def send_message(ctx: dict, user_id: int, message: str):
Expand Down
9 changes: 7 additions & 2 deletions app/worker.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# isort:skip_file

import sys

sys.path.extend(["./"])

from pydantic.utils import import_string

from .application import db
from .settings.arq import settings
from .settings.globals import DATABASE_CONFIG, ARQ_BACKGROUND_FUNCTIONS

from .settings.globals import ARQ_BACKGROUND_FUNCTIONS, DATABASE_CONFIG

FUNCTIONS: list = [
import_string(background_function)
Expand Down
Loading

0 comments on commit c19017a

Please sign in to comment.