diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..8d02c83 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,27 @@ +default_stages: [commit, push] +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - repo: https://github.com/psf/black + rev: 22.8.0 + hooks: + - id: black + # https://pylint.pycqa.org/en/latest/user_guide/installation/pre-commit-integration.html + - repo: local + hooks: + - id: pylint + name: pylint + entry: pylint + language: system + types: [python] + args: [ + '-rn', # Only display messages + '-sn', # Don't display the score + '--disable=C,R,W0511', # Disable C and R type messages, and TODO fixme warning + ] + # TODO add https://pre-commit.com/#docker hook for bash linting diff --git a/README.md b/README.md index 06428eb..82e0679 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# fastapi_celery +# FastAPI and Celery -FastAPI and Celery +Learning distributed task queues by doing. Since it's a greenfield project this also uses a newer async web framework. diff --git a/dev-requirements.in b/dev-requirements.in new file mode 100644 index 0000000..b399c9f --- /dev/null +++ b/dev-requirements.in @@ -0,0 +1,7 @@ +black==22.8.0 +flake8==5.0.4 +invoke==1.7.1 +pip-tools==6.8.0 +pre-commit==2.20.0 +pylint==2.15.2 +pytest==7.1.3 diff --git a/dev-requirements.txt b/dev-requirements.txt new file mode 100644 index 0000000..982c292 --- /dev/null +++ b/dev-requirements.txt @@ -0,0 +1,104 @@ +# +# This file is autogenerated by pip-compile with python 3.8 +# To update, run: +# +# pip-compile dev-requirements.in +# +astroid==2.12.10 + # via pylint +attrs==22.1.0 + # via pytest +black==22.8.0 + # via -r dev-requirements.in +build==0.8.0 + # via pip-tools +cfgv==3.3.1 + # via pre-commit +click==8.1.3 + # via + # black + # pip-tools +dill==0.3.5.1 + # via pylint +distlib==0.3.6 + # via virtualenv +filelock==3.8.0 + # via virtualenv +flake8==5.0.4 + # via -r dev-requirements.in +identify==2.5.5 + # via pre-commit +iniconfig==1.1.1 + # via pytest +invoke==1.7.1 + # via -r dev-requirements.in +isort==5.10.1 + # via pylint +lazy-object-proxy==1.7.1 + # via astroid +mccabe==0.7.0 + # via + # flake8 + # pylint +mypy-extensions==0.4.3 + # via black +nodeenv==1.7.0 + # via pre-commit +packaging==21.3 + # via + # build + # pytest +pathspec==0.10.1 + # via black +pep517==0.13.0 + # via build +pip-tools==6.8.0 + # via -r dev-requirements.in +platformdirs==2.5.2 + # via + # black + # pylint + # virtualenv +pluggy==1.0.0 + # via pytest +pre-commit==2.20.0 + # via -r dev-requirements.in +py==1.11.0 + # via pytest +pycodestyle==2.9.1 + # via flake8 +pyflakes==2.5.0 + # via flake8 +pylint==2.15.2 + # via -r dev-requirements.in +pyparsing==3.0.9 + # via packaging +pytest==7.1.3 + # via -r dev-requirements.in +pyyaml==6.0 + # via pre-commit +toml==0.10.2 + # via pre-commit +tomli==2.0.1 + # via + # black + # build + # pylint + # pytest +tomlkit==0.11.4 + # via pylint +typing-extensions==4.3.0 + # via + # astroid + # black + # pylint +virtualenv==20.16.5 + # via pre-commit +wheel==0.37.1 + # via pip-tools +wrapt==1.14.1 + # via astroid + +# The following packages are considered to be unsafe in a requirements file: +# pip +# setuptools diff --git a/docker-compose-redis.yml b/docker-compose-redis.yml new file mode 100644 index 0000000..5fd2d0e --- /dev/null +++ b/docker-compose-redis.yml @@ -0,0 +1,9 @@ +version: '3.8' + +services: + + redis: + image: redis:7.0.4-alpine + restart: always + ports: + - 6379:6379 diff --git a/main.py b/main.py new file mode 100644 index 0000000..ee60be1 --- /dev/null +++ b/main.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def root(): + return {"message": "Hello World"} diff --git a/requirements.in b/requirements.in new file mode 100644 index 0000000..5514de0 --- /dev/null +++ b/requirements.in @@ -0,0 +1,4 @@ +celery==5.2.7 +fastapi==0.79.0 +redis==4.3.4 +uvicorn[standard]==0.18.2 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c2f0b94 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,86 @@ +# +# This file is autogenerated by pip-compile with python 3.8 +# To update, run: +# +# pip-compile requirements.in +# +amqp==5.1.1 + # via kombu +anyio==3.6.1 + # via + # starlette + # watchfiles +async-timeout==4.0.2 + # via redis +billiard==3.6.4.0 + # via celery +celery==5.2.7 + # via -r requirements.in +click==8.1.3 + # via + # celery + # click-didyoumean + # click-plugins + # click-repl + # uvicorn +click-didyoumean==0.3.0 + # via celery +click-plugins==1.1.1 + # via celery +click-repl==0.2.0 + # via celery +deprecated==1.2.13 + # via redis +fastapi==0.79.0 + # via -r requirements.in +h11==0.13.0 + # via uvicorn +httptools==0.5.0 + # via uvicorn +idna==3.4 + # via anyio +kombu==5.2.4 + # via celery +packaging==21.3 + # via redis +prompt-toolkit==3.0.31 + # via click-repl +pydantic==1.10.2 + # via fastapi +pyparsing==3.0.9 + # via packaging +python-dotenv==0.21.0 + # via uvicorn +pytz==2022.2.1 + # via celery +pyyaml==6.0 + # via uvicorn +redis==4.3.4 + # via -r requirements.in +six==1.16.0 + # via click-repl +sniffio==1.3.0 + # via anyio +starlette==0.19.1 + # via fastapi +typing-extensions==4.3.0 + # via + # pydantic + # starlette +uvicorn[standard]==0.18.2 + # via -r requirements.in +uvloop==0.17.0 + # via uvicorn +vine==5.0.0 + # via + # amqp + # celery + # kombu +watchfiles==0.17.0 + # via uvicorn +wcwidth==0.2.5 + # via prompt-toolkit +websockets==10.3 + # via uvicorn +wrapt==1.14.1 + # via deprecated diff --git a/tasks.py b/tasks.py new file mode 100644 index 0000000..bcff483 --- /dev/null +++ b/tasks.py @@ -0,0 +1,39 @@ +""" +A set of `invoke` helper commands used for this project. +""" +from invoke import task + + +@task +def start_app(c): + """Starts the app.""" + print("Start the app") + c.run("uvicorn main:app --reload", pty=True) + + +@task +def run_unit_tests(c): + """Triggers a local unittest run for the app.""" + # Pytest will hide color output when it thinks it's running + # outside of a terminal therefore pty=True is used. + c.run("python3 -m pytest -vvv tests/", pty=True) + + +@task +def fix_eof(c): + """Fixes any missing newlines for end of files.""" + c.run("pre-commit run end-of-file-fixer --all-files", pty=True) + + +@task +def start_redis(c): + """Runs the Redis integration environment.""" + print("Starting Redis") + c.run("docker compose -f docker-compose-redis.yml up -d") + + +@task +def stop_redis(c): + """Stops the Redis integration environent.""" + print("Stopping Redis") + c.run("docker compose -f docker-compose-redis.yml down")