-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use Flask custom CLI commands for custom scripts (#138)
## Changes * Use Flask custom CLI commands for custom scripts * Remove main() entry point from create_user_csv service * Remove script_utils * Rename api.route package to api.api, and organize all things related to blueprints together: * X_blueprint.py * X_commands.py * X_routes.py * X_schemas.py * Rewrite test_create_user_csv to use test_cli_runner rather than only test the service * Add migration to cascade on delete * Rewrite test_create_user_csv to truncate the user table rather than requiring an isolated db schema * Remove now unused isolated_db fixture * Remove unused transaction rollback functionality in db_session test fixture * Rename /user REST resource to /users Other changes * Organize Makefile commands: * move setup-local to top * group openapi-spec with other CLI commands) * Install pytest-lazy-fixture dev dependency * Move empty_schema fixture to test_migrations, the only place it's used ## Context This PR consolidates the way we run the API server and the way we run background scripts to both use Flask's create_app factory. This removes the need to have two separate main() entrypoints, two separate ways to initialize the database, logger, etc. To do this, we leverage [Flask's built-in method of creating custom CLI commands](https://flask.palletsprojects.com/en/2.2.x/cli/#custom-commands) which itself is based on the [click library](https://click.palletsprojects.com/en/8.1.x/arguments/), a popular library for building Python command line applications that's more powerful than `argparse`. This allows us to remove the script_utils file. This PR also renames the `api.route` package to `api.api` since we want to add "commands" to the user blueprint, so "route" is no longer an appropriate name that applies to everything in the blueprint. We could also consider other names like `api.components` or `api.blueprints`, and/or we could consider renaming the top level source code folder to something like `src` rather than `api`. Finally, we made test_create_user_csv test things at using the test_cli_runner to be closer to the way we test routes using the test_client. This approach has more end-to-end test coverage. Other tangential changes include making REST resources use plural names to follow REST resource naming conventions.
- Loading branch information
Showing
39 changed files
with
277 additions
and
548 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion
2
app/api/route/schemas/response_schema.py → app/api/api/schemas/response_schema.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from api.api.users.user_blueprint import user_blueprint | ||
|
||
# import user_commands module to register the CLI commands on the user_blueprint | ||
import api.api.users.user_commands # noqa: F401 E402 isort:skip | ||
|
||
# import user_commands module to register the API routes on the user_blueprint | ||
import api.api.users.user_routes # noqa: F401 E402 isort:skip | ||
|
||
|
||
__all__ = ["user_blueprint"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from apiflask import APIBlueprint | ||
|
||
user_blueprint = APIBlueprint("user", __name__, tag="User", cli_group="user") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import logging | ||
import os.path as path | ||
from typing import Optional | ||
|
||
import click | ||
|
||
import api.adapters.db as db | ||
import api.adapters.db.flask_db as flask_db | ||
import api.services.users as user_service | ||
from api.api.users.user_blueprint import user_blueprint | ||
from api.util.datetime_util import utcnow | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
user_blueprint.cli.help = "User commands" | ||
|
||
|
||
@user_blueprint.cli.command("create-csv", help="Create a CSV of all users and their roles") | ||
@flask_db.with_db_session | ||
@click.option( | ||
"--dir", | ||
default=".", | ||
help="Directory to save output file in. Can be an S3 path (e.g. 's3://bucketname/folder/') Defaults to current directory ('.').", | ||
) | ||
@click.option( | ||
"--filename", | ||
default=None, | ||
help="Filename to save output file as. Defaults to '[timestamp]-user-roles.csv.", | ||
) | ||
def create_csv(db_session: db.Session, dir: str, filename: Optional[str]) -> None: | ||
if filename is None: | ||
filename = utcnow().strftime("%Y-%m-%d-%H-%M-%S") + "-user-roles.csv" | ||
filepath = path.join(dir, filename) | ||
user_service.create_user_csv(db_session, filepath) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
app/api/db/migrations/versions/2023_02_21_cascade_on_delete.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
"""cascade on delete | ||
Revision ID: 9fe657340f70 | ||
Revises: 4ff1160282d1 | ||
Create Date: 2023-02-21 18:16:56.052679 | ||
""" | ||
from alembic import op | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = "9fe657340f70" | ||
down_revision = "4ff1160282d1" | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade(): | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_constraint("role_user_id_user_fkey", "role", type_="foreignkey") | ||
op.create_foreign_key( | ||
op.f("role_user_id_user_fkey"), "role", "user", ["user_id"], ["id"], ondelete="CASCADE" | ||
) | ||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade(): | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_constraint(op.f("role_user_id_user_fkey"), "role", type_="foreignkey") | ||
op.create_foreign_key("role_user_id_user_fkey", "role", "user", ["user_id"], ["id"]) | ||
# ### end Alembic commands ### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Empty file.
Empty file.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.