Skip to content

Commit

Permalink
Merge branch 'release/5.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
s3rius committed Jul 20, 2023
2 parents 8b1b5f1 + 4f06fdd commit 38a04b1
Show file tree
Hide file tree
Showing 74 changed files with 1,032 additions and 764 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ jobs:
git config --global user.name "fastapi_template"
git config --global user.email "fastapi_template@pytest.python"
- name: Run tests
run: poetry run pytest -vv --exitfirst -n auto
run: poetry run pytest -vv
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.9.17-alpine
FROM python:3.11.4-slim-bullseye

RUN apk add --no-cache \
curl \
Expand All @@ -11,7 +11,8 @@ RUN apk add --no-cache \
# For psycopg \
postgresql-dev \
# For mysql deps \
mariadb-connector-c-dev \
default-libmysqlclient-dev \
pkg-config \
# For UI \
ncurses \
bash
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ docker run --rm -it -v "$(pwd):/projects" s3rius/fastapi_template
One of the coolest features is that this project is extremely configurable.
You can choose between different databases and even ORMs, or
you can even generate a project without a database!
Currently SQLAlchemy1.4, TortoiseORM, Piccolo and Ormar are supported.
Currently SQLAlchemy 2.0, TortoiseORM, Piccolo and Ormar are supported.

This project can run as TUI or CLI and has excellent code documentation.

Generator features:
- Pydantic V2 (Where it's possible. Some libs doesn't have support);
- You can choose between GraphQL and REST api;
- Uvicorn and gunicorn;
- Different databases support;
- Different ORMs support;
- Optional migrations for each ORM except raw drivers;
Expand Down Expand Up @@ -101,5 +103,6 @@ Options:
--opentelemetry Add opentelemetry integration
--traefik Adds traefik labels to docker container
--kafka Add Kafka support
--gunicorn Add gunicorn server
--help Show this message and exit.
```
3 changes: 2 additions & 1 deletion fastapi_template/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pathlib import Path

from cookiecutter.exceptions import FailedHookException, OutputDirExistsException
from cookiecutter.exceptions import (FailedHookException,
OutputDirExistsException)
from cookiecutter.main import cookiecutter
from termcolor import cprint

Expand Down
41 changes: 28 additions & 13 deletions fastapi_template/cli.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import re
import shutil
from fastapi_template.input_model import (
BuilderContext,
MenuEntry,
SingularMenuModel,
MultiselectMenuModel,
BaseMenuModel,
Database,
SKIP_ENTRY,
)
from importlib.metadata import version
from typing import Callable, List, Optional
from click import Command, Option
import re
from typing import Any, Callable, List, Optional

from click import Command, Option
from prompt_toolkit import prompt
from prompt_toolkit.document import Document
from prompt_toolkit.validation import ValidationError, Validator
from typing import Any
from termcolor import colored

from fastapi_template.input_model import (
SKIP_ENTRY,
BaseMenuModel,
BuilderContext,
Database,
MenuEntry,
MultiselectMenuModel,
SingularMenuModel,
)


class SnakeCaseValidator(Validator):
def validate(self, document: Document):
Expand Down Expand Up @@ -81,6 +81,7 @@ def checker(ctx: BuilderContext) -> bool:
MenuEntry(
code="graphql",
user_view="GrapQL API",
pydantic_v1=True,
description=(
"Choose this option if you want to create a service with {name}.\n"
"It's more suitable for services with {reason} and deep nesting.".format(
Expand Down Expand Up @@ -245,6 +246,7 @@ def checker(ctx: BuilderContext) -> bool:
MenuEntry(
code="ormar",
user_view="Ormar",
pydantic_v1=True,
description=(
"{what} is a great {feature} ORM.\n"
"It's compatible with pydantic models and alembic migrator.".format(
Expand Down Expand Up @@ -290,6 +292,7 @@ def checker(ctx: BuilderContext) -> bool:
MenuEntry(
code="piccolo",
user_view="Piccolo",
pydantic_v1=True,
is_hidden=check_db(["postgresql", "sqlite"]),
description=(
"{what} is a great ORM for Postgresql and SQLite.\n"
Expand Down Expand Up @@ -382,6 +385,7 @@ def checker(ctx: BuilderContext) -> bool:
code="add_dummy",
cli_name="dummy",
user_view="Add dummy model",
is_hidden=lambda ctx: ctx.orm == "none",
description=(
"This option creates {what} as an example of how to use chosen ORM.\n"
"Also this option will generate you an example of {dao}.".format(
Expand Down Expand Up @@ -510,6 +514,17 @@ def checker(ctx: BuilderContext) -> bool:
)
),
),
MenuEntry(
code="gunicorn",
cli_name="gunicorn",
user_view="Add gunicorn server",
description=(
"This option adds {what} server for running application.\n"
"It's more performant than uvicorn, and recommended for production.".format(
what=colored("gunicorn", color="green")
)
),
),
],
)

Expand Down
39 changes: 23 additions & 16 deletions fastapi_template/input_model.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import abc
import enum
from typing import List, Optional, Callable, Any
from collections import UserDict
from typing import Any, Callable, List, Optional

from pydantic import BaseModel
import click
import abc
from collections import UserDict
from prompt_toolkit.shortcuts import checkboxlist_dialog, radiolist_dialog
from pydantic import BaseModel

try:
from simple_term_menu import TerminalMenu
Expand All @@ -15,20 +15,21 @@

class Database(BaseModel):
name: str
image: Optional[str]
driver: Optional[str]
async_driver: Optional[str]
port: Optional[int]
driver_short: Optional[str]
image: Optional[str] = None
driver: Optional[str] = None
async_driver: Optional[str] = None
port: Optional[int] = None
driver_short: Optional[str] = None


class MenuEntry(BaseModel):
code: str
cli_name: Optional[str]
cli_name: Optional[str] = None
user_view: str
description: str
is_hidden: Optional[Callable[["BuilderContext"], bool]]
additional_info: Any
is_hidden: Optional[Callable[["BuilderContext"], bool]] = None
additional_info: Any = None
pydantic_v1: bool = False

@property
def generated_name(self) -> str:
Expand Down Expand Up @@ -83,13 +84,13 @@ def after_ask(self, context: "BuilderContext") -> "BuilderContext":

class SingularMenuModel(BaseMenuModel):
code: str
cli_name: Optional[str]
cli_name: Optional[str] = None
description: str
before_ask_fun: Optional[Callable[["BuilderContext"], Optional[MenuEntry]]]
before_ask_fun: Optional[Callable[["BuilderContext"], Optional[MenuEntry]]] = None
after_ask_fun: Optional[
Callable[["BuilderContext", "SingularMenuModel"], "BuilderContext"]
]
parser: Optional[Callable[[str], Any]]
] = None
parser: Optional[Callable[[str], Any]] = None

def get_cli_options(self) -> List[click.Option]:
cli_name = self.code
Expand Down Expand Up @@ -158,6 +159,8 @@ def ask(self, context: "BuilderContext") -> Optional["BuilderContext"]:
return

setattr(context, self.code, chosen_entry.code)
if chosen_entry.pydantic_v1:
context.pydanticv1 = True

return context

Expand Down Expand Up @@ -236,6 +239,10 @@ def ask(self, context: "BuilderContext") -> Optional["BuilderContext"]:

for entry in chosen_entries:
setattr(context, entry.code, True)

for ch_entry in chosen_entries:
if ch_entry.pydantic_v1:
context.pydanticv1 = True

return context

Expand Down
6 changes: 6 additions & 0 deletions fastapi_template/template/cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
"otlp_enabled": {
"type": "bool"
},
"pydanticv1": {
"type": "bool"
},
"gunicorn": {
"type": "bool"
},
"_extensions": [
"cookiecutter.extensions.RandomStringExtension"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ ignore =
WPS407,
; Found too many empty lines in `def`
WPS473,
; too many no-cover comments.
WPS403,

per-file-ignores =
; all tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@ repos:

- repo: local
hooks:
- id: black
name: Format with Black
entry: poetry run black
language: system
types: [python]

- id: autoflake
name: autoflake
entry: poetry run autoflake
language: system
types: [python]
args: [--in-place, --remove-all-unused-imports, --remove-duplicate-keys]

- id: black
name: Format with Black
entry: poetry run black
language: system
types: [python]

- id: isort
name: isort
entry: poetry run isort
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,5 +215,11 @@
"resources": [
"{{cookiecutter.project_name}}/tkq.py"
]
},
"Gunicorn support":{
"enabled": "{{cookiecutter.gunicorn}}",
"resources": [
"{{cookiecutter.project_name}}/gunicorn_runner.py"
]
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
FROM python:3.9.6-slim-buster as prod
FROM python:3.11.4-slim-bullseye as prod

{%- if cookiecutter.db_info.name == "mysql" %}
RUN apt-get update && apt-get install -y \
default-libmysqlclient-dev \
gcc \
pkg-config \
&& rm -rf /var/lib/apt/lists/*
{%- endif %}

Expand Down
Loading

0 comments on commit 38a04b1

Please sign in to comment.