Skip to content

Release 5.0 #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Nov 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build_docker_image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.11"
python-version: "3.12"

- name: Generate projects from templates using cookiecutter
# minimal_project folder
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/manual_build_docker_image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.11"
python-version: "3.12"

- name: Generate projects from templates using cookiecutter
# minimal_project folder
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.11"
python-version: "3.12"

# Below will create fresh template in path: minimal_project
- name: Generate project from template using cookiecutter
Expand Down Expand Up @@ -61,5 +61,5 @@ jobs:
TEST_DATABASE_DB: postgres
run: |
cd minimal_project
poetry run flake8 app --count --exit-zero --statistics
poetry run ruff app
poetry run coverage run -m pytest
33 changes: 12 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
<a href="https://minimal-fastapi-postgres-template.rafsaf.pl/" target="_blank">
<img src="https://img.shields.io/badge/live%20example-https%3A%2F%2Fminimal--fastapi--postgres--template.rafsaf.pl-blueviolet" alt="Live example">
</a>
<a href="https://github.com/rafsaf/minimal-fastapi-postgres-template/blob/main/LICENSE" target="_blank">
<img src="https://img.shields.io/github/license/rafsaf/minimal-fastapi-postgres-template" alt="License">
</a>
<a href="https://docs.python.org/3/whatsnew/3.11.html" target="_blank">
<img src="https://img.shields.io/badge/python-3.11-blue" alt="Python">
</a>
<a href="https://github.com/psf/black" target="_blank">
<img src="https://img.shields.io/badge/code%20style-black-lightgrey" alt="Black">
</a>
<a href="https://github.com/rafsaf/minimal-fastapi-postgres-template/actions/workflows/tests.yml" target="_blank">
<img src="https://github.com/rafsaf/minimal-fastapi-postgres-template/workflows/tests/badge.svg" alt="Tests">
</a>
[![Live example](https://img.shields.io/badge/live%20example-https%3A%2F%2Fminimal--fastapi--postgres--template.rafsaf.pl-blueviolet)](https://minimal-fastapi-postgres-template.rafsaf.pl/)
[![License](https://img.shields.io/github/license/rafsaf/minimal-fastapi-postgres-template)](https://github.com/rafsaf/minimal-fastapi-postgres-template/blob/main/LICENSE)
[![Python 3.12](https://img.shields.io/badge/python-3.12-blue)](https://docs.python.org/3/whatsnew/3.12.html)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![Black](https://img.shields.io/badge/code%20style-black-lightgrey)](https://github.com/psf/black)
[![Tests](https://github.com/rafsaf/minimal-fastapi-postgres-template/actions/workflows/tests.yml/badge.svg)](https://github.com/rafsaf/minimal-fastapi-postgres-template/actions/workflows/tests.yml)

# Minimal async FastAPI + PostgreSQL template

Expand Down Expand Up @@ -42,9 +33,9 @@
- [x] [Alembic](https://alembic.sqlalchemy.org/en/latest/) migrations
- [x] Very minimal project structure yet ready for quick start building new apps
- [x] Refresh token endpoint (not only access like in official template)
- [x] Two databases in docker-compose.yml (second one for tests) and ready to go Dockerfile with [Uvicorn](https://www.uvicorn.org/) webserver
- [x] [Poetry](https://python-poetry.org/docs/) and Python 3.11 based
- [x] `pre-commit` with poetry export, autoflake, black, isort and flake8
- [x] Two databases in docker-compose.yml (second one for tests) and ready to go Dockerfile with [uvicorn](https://www.uvicorn.org/) webserver
- [x] [Poetry](https://python-poetry.org/docs/) and Python 3.12 based
- [x] `pre-commit` with poetry export and [ruff](https://github.com/astral-sh/ruff)
- [x] Rich setup for pytest async tests with few included and extensible `conftest.py`

<br>
Expand All @@ -69,16 +60,16 @@ cookiecutter https://github.com/rafsaf/minimal-fastapi-postgres-template

```bash
cd project_name
### Poetry install (python3.11)
### Poetry install (python3.12)
poetry install

### Optionally there is also `requirements-dev.txt` file
python3.11 -m venv venv
python3.12 -m venv venv
source venv/bin/activate
pip install -r requirements-dev.txt
```

Note, be sure to use `python3.11` with this template with either poetry or standard venv & pip, if you need to stick to some earlier python version, you should adapt it yourself (remove new versions specific syntax for example `str | int` for python < 3.10 or `tomllib` for python < 3.11)
Note, be sure to use `python3.12` with this template with either poetry or standard venv & pip, if you need to stick to some earlier python version, you should adapt it yourself (remove new versions specific syntax for example `str | int` for python < 3.10 or `tomllib` for python < 3.11)

### 3. Setup databases

Expand Down
11 changes: 0 additions & 11 deletions {{cookiecutter.project_name}}/.flake8

This file was deleted.

53 changes: 9 additions & 44 deletions {{cookiecutter.project_name}}/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,63 +1,28 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: check-yaml
- id: trailing-whitespace

- repo: https://github.com/myint/autoflake
rev: "v2.0.1"
hooks:
- id: autoflake
args:
[
"--recursive",
"--in-place",
"--remove-unused-variables",
"--remove-all-unused-imports",
"--ignore-init-module-imports",
]

- repo: https://github.com/asottile/pyupgrade
rev: v3.3.1
hooks:
- id: pyupgrade
args:
[
"--py3-plus",
"--py36-plus",
"--py37-plus",
"--py38-plus",
"--py39-plus",
"--py310-plus",
"--py311-plus",
]
files: ".*"

- repo: https://github.com/psf/black
rev: "23.1.0"
rev: "23.10.1"
hooks:
- id: black

- repo: https://github.com/pycqa/isort
rev: "5.12.0"
hooks:
- id: isort

- repo: https://github.com/PyCQA/flake8
rev: "6.0.0"
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.4
hooks:
- id: flake8
- id: ruff
args: [--fix]

- repo: https://github.com/python-poetry/poetry
rev: "1.3.0"
rev: "1.7.0"
hooks:
- id: poetry-export
args: ["-o", "requirements.txt", "--without-hashes"]

- repo: https://github.com/python-poetry/poetry
rev: "1.3.0"
rev: "1.7.0"
hooks:
- id: poetry-export
args:
["-o", "requirements-dev.txt", "--without-hashes", "--with", "dev"]
args: ["-o", "requirements-dev.txt", "--without-hashes", "--with=dev"]
2 changes: 1 addition & 1 deletion {{cookiecutter.project_name}}/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.11.1-slim-bullseye
FROM python:3.12.0-slim-bullseye

ENV PYTHONUNBUFFERED 1
WORKDIR /build
Expand Down
2 changes: 1 addition & 1 deletion {{cookiecutter.project_name}}/app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
Note, complex types like lists are read as json-encoded strings.
"""

import tomllib
from functools import cached_property
from pathlib import Path
from typing import Literal

import tomllib
from pydantic import AnyHttpUrl, EmailStr, PostgresDsn, computed_field
from pydantic_settings import BaseSettings, SettingsConfigDict

Expand Down
8 changes: 4 additions & 4 deletions {{cookiecutter.project_name}}/app/tests/test_auth.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from httpx import AsyncClient
from httpx import AsyncClient, codes

from app.main import app
from app.models import User
Expand All @@ -14,7 +14,7 @@ async def test_auth_access_token(client: AsyncClient, default_user: User):
},
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
assert response.status_code == 200
assert response.status_code == codes.OK
token = response.json()
assert token["token_type"] == "Bearer"
assert "access_token" in token
Expand All @@ -35,7 +35,7 @@ async def test_auth_access_token_fail_no_user(client: AsyncClient):
headers={"Content-Type": "application/x-www-form-urlencoded"},
)

assert response.status_code == 400
assert response.status_code == codes.BAD_REQUEST
assert response.json() == {"detail": "Incorrect email or password"}


Expand All @@ -53,7 +53,7 @@ async def test_auth_refresh_token(client: AsyncClient, default_user: User):
new_token_response = await client.post(
app.url_path_for("refresh_token"), json={"refresh_token": refresh_token}
)
assert new_token_response.status_code == 200
assert new_token_response.status_code == codes.OK
token = new_token_response.json()
assert token["token_type"] == "Bearer"
assert "access_token" in token
Expand Down
10 changes: 5 additions & 5 deletions {{cookiecutter.project_name}}/app/tests/test_users.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from httpx import AsyncClient
from httpx import AsyncClient, codes
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

Expand All @@ -15,7 +15,7 @@ async def test_read_current_user(client: AsyncClient, default_user_headers):
response = await client.get(
app.url_path_for("read_current_user"), headers=default_user_headers
)
assert response.status_code == 200
assert response.status_code == codes.OK
assert response.json() == {
"id": default_user_id,
"email": default_user_email,
Expand All @@ -28,7 +28,7 @@ async def test_delete_current_user(
response = await client.delete(
app.url_path_for("delete_current_user"), headers=default_user_headers
)
assert response.status_code == 204
assert response.status_code == codes.NO_CONTENT
result = await session.execute(select(User).where(User.id == default_user_id))
user = result.scalars().first()
assert user is None
Expand All @@ -42,7 +42,7 @@ async def test_reset_current_user_password(
headers=default_user_headers,
json={"password": "testxxxxxx"},
)
assert response.status_code == 200
assert response.status_code == codes.OK
result = await session.execute(select(User).where(User.id == default_user_id))
user = result.scalars().first()
assert user is not None
Expand All @@ -60,7 +60,7 @@ async def test_register_new_user(
"password": "asdasdasd",
},
)
assert response.status_code == 200
assert response.status_code == codes.OK
result = await session.execute(select(User).where(User.email == "qwe@example.com"))
user = result.scalars().first()
assert user is not None
Empty file modified {{cookiecutter.project_name}}/init.sh
100644 → 100755
Empty file.
Loading