Skip to content
Closed
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
1 change: 1 addition & 0 deletions cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"machine_learn_model_path": "./ml/model/",
"machine_learn_model_name": "model.pkl",
"input_example_path": "./ml/model/examples/example.json",
"database_url": "sqlite:///./app.db",
"full_name": "Your name",
"email": "[email protected]",
"release_date": "{% now 'local' %}",
Expand Down
4 changes: 3 additions & 1 deletion sample/pregnancy-model/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
SECRET_KEY=secret
DEBUG=True
MODEL_PATH=/Users/arthur.dasilva/repos/arthurhenrique/n
MODEL_NAME=pregnancy_model_local.joblib
MODEL_NAME=pregnancy_model_local.joblib
MEMOIZATION_FLAG=False
DATABASE_URL=sqlite:///./app.db
22 changes: 22 additions & 0 deletions sample/pregnancy-model/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,28 @@ MODEL_PATH=./ml/model/
MODEL_NAME=model.pkl
```

### Database Configuration

Set your database url in `.env` using `DATABASE_URL`. The default uses SQLite:

```sh
DATABASE_URL=sqlite:///./app.db
```

### Migrations

Create a new migration with:

```sh
alembic revision --autogenerate -m "message"
```

Apply migrations with:

```sh
alembic upgrade head
```

### Update `/predict`

To update your machine learning model, add your `load` and `method` [change here](app/api/routes/predictor.py#L19) at `predictor.py`
Expand Down
36 changes: 36 additions & 0 deletions sample/pregnancy-model/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[alembic]
script_location = migrations
sqlalchemy.url = sqlite:///./app.db

[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
3 changes: 2 additions & 1 deletion sample/pregnancy-model/app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from starlette.config import Config
from starlette.datastructures import Secret

from core.logging import InterceptHandler
from .logging import InterceptHandler

config = Config(".env")

Expand All @@ -29,3 +29,4 @@
MODEL_PATH = config("MODEL_PATH", default="/Users/arthur.dasilva/repos/arthurhenrique/cookiecutter-fastapi/sample/pregnancy-model")
MODEL_NAME = config("MODEL_NAME", default="pregnancy_model_local.joblib")
INPUT_EXAMPLE = config("INPUT_EXAMPLE", default="./ml/model/examples/example.json")
DATABASE_URL = config("DATABASE_URL", default="sqlite:///./app.db")
20 changes: 20 additions & 0 deletions sample/pregnancy-model/app/core/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base

from .config import DATABASE_URL

connect_args = {}
if DATABASE_URL.startswith("sqlite"):
connect_args["check_same_thread"] = False

engine = create_engine(DATABASE_URL, connect_args=connect_args)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
10 changes: 10 additions & 0 deletions sample/pregnancy-model/app/models/item.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from sqlalchemy import Column, Integer, String

from app.core.database import Base


class Item(Base):
__tablename__ = "items"

id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
51 changes: 51 additions & 0 deletions sample/pregnancy-model/migrations/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from logging.config import fileConfig

from sqlalchemy import engine_from_config
from sqlalchemy import pool

from alembic import context

from core.database import Base
from models import item
from core.config import DATABASE_URL

config = context.config

if config.get_main_option("sqlalchemy.url") is None:
config.set_main_option("sqlalchemy.url", DATABASE_URL)

fileConfig(config.config_file_name)

target_metadata = Base.metadata


def run_migrations_offline() -> None:
context.configure(
url=config.get_main_option("sqlalchemy.url"),
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)

with context.begin_transaction():
context.run_migrations()


def run_migrations_online() -> None:
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)

with connectable.connect() as connection:
context.configure(connection=connection, target_metadata=target_metadata)

with context.begin_transaction():
context.run_migrations()


if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""create items table

Revision ID: 0001
Revises:
Create Date: 2020-01-01 00:00:00.000000
"""
from alembic import op
import sqlalchemy as sa

revision = "0001"
down_revision = None
branch_labels = None
depends_on = None


def upgrade() -> None:
op.create_table(
"items",
sa.Column("id", sa.Integer(), primary_key=True),
sa.Column("name", sa.String(), nullable=True),
)


def downgrade() -> None:
op.drop_table("items")
2 changes: 2 additions & 0 deletions sample/pregnancy-model/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ dependencies = [
"loguru>=0.7.0",
"joblib>=1.2.0",
"scikit-learn>=1.1.3",
"SQLAlchemy>=2.0.0",
"alembic>=1.12.0",
"pandas>=2.2.3",
]

Expand Down
10 changes: 10 additions & 0 deletions sample/pregnancy-model/tests/test_database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from sqlalchemy import inspect

from app.core.database import Base, engine
from app.models import item # noqa: F401


def test_items_table_exists():
Base.metadata.create_all(bind=engine)
inspector = inspect(engine)
assert "items" in inspector.get_table_names()
1 change: 1 addition & 0 deletions {{cookiecutter.project_slug}}/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ DEBUG=True
MODEL_PATH={{cookiecutter.machine_learn_model_path}}
MODEL_NAME={{cookiecutter.machine_learn_model_name}}
MEMOIZATION_FLAG=False
DATABASE_URL={{cookiecutter.database_url}}
22 changes: 22 additions & 0 deletions {{cookiecutter.project_slug}}/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,28 @@ MODEL_PATH=./ml/model/
MODEL_NAME=model.pkl
```

### Database Configuration

Set your database url in `.env` using `DATABASE_URL`. The default uses SQLite:

```sh
DATABASE_URL=sqlite:///./app.db
```

### Migrations

Create a new migration with:

```sh
alembic revision --autogenerate -m "message"
```

Apply migrations with:

```sh
alembic upgrade head
```

### Update `/predict`

To update your machine learning model, add your `load` and `method` [change here](app/api/routes/predictor.py#L19) at `predictor.py`
Expand Down
36 changes: 36 additions & 0 deletions {{cookiecutter.project_slug}}/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[alembic]
script_location = migrations
sqlalchemy.url = {{cookiecutter.database_url}}

[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
1 change: 1 addition & 0 deletions {{cookiecutter.project_slug}}/app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@
MODEL_PATH = config("MODEL_PATH", default="{{cookiecutter.machine_learn_model_path}}")
MODEL_NAME = config("MODEL_NAME", default="{{cookiecutter.machine_learn_model_name}}")
INPUT_EXAMPLE = config("INPUT_EXAMPLE", default="{{cookiecutter.input_example_path}}")
DATABASE_URL = config("DATABASE_URL", default="{{cookiecutter.database_url}}")
20 changes: 20 additions & 0 deletions {{cookiecutter.project_slug}}/app/core/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base

from .config import DATABASE_URL

connect_args = {}
if DATABASE_URL.startswith("sqlite"):
connect_args["check_same_thread"] = False

engine = create_engine(DATABASE_URL, connect_args=connect_args)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
10 changes: 10 additions & 0 deletions {{cookiecutter.project_slug}}/app/models/item.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from sqlalchemy import Column, Integer, String

from app.core.database import Base


class Item(Base):
__tablename__ = "items"

id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
51 changes: 51 additions & 0 deletions {{cookiecutter.project_slug}}/migrations/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from logging.config import fileConfig

from sqlalchemy import engine_from_config
from sqlalchemy import pool

from alembic import context

from core.database import Base
from models import item
from core.config import DATABASE_URL

config = context.config

if config.get_main_option("sqlalchemy.url") is None:
config.set_main_option("sqlalchemy.url", DATABASE_URL)

fileConfig(config.config_file_name)

target_metadata = Base.metadata


def run_migrations_offline() -> None:
context.configure(
url=config.get_main_option("sqlalchemy.url"),
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)

with context.begin_transaction():
context.run_migrations()


def run_migrations_online() -> None:
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)

with connectable.connect() as connection:
context.configure(connection=connection, target_metadata=target_metadata)

with context.begin_transaction():
context.run_migrations()


if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
Loading
Loading