From 9828c999894aa6d94f264cc44a08759a4993635c Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 25 Sep 2024 17:45:33 +0530 Subject: [PATCH 01/63] feat: added simple/structured scaffolding --- robyn/cli.py | 56 ++++++++++++++----- robyn/scaffold/{ => simple}/mongo/Dockerfile | 0 robyn/scaffold/{ => simple}/mongo/app.py | 0 .../{ => simple}/mongo/requirements.txt | 0 robyn/scaffold/{ => simple}/no-db/Dockerfile | 0 robyn/scaffold/{ => simple}/no-db/app.py | 0 .../{ => simple}/no-db/requirements.txt | 0 .../scaffold/{ => simple}/postgres/Dockerfile | 0 robyn/scaffold/{ => simple}/postgres/app.py | 0 .../{ => simple}/postgres/requirements.txt | 0 .../{ => simple}/postgres/supervisord.conf | 0 robyn/scaffold/{ => simple}/prisma/Dockerfile | 0 robyn/scaffold/{ => simple}/prisma/app.py | 0 .../{ => simple}/prisma/requirements.txt | 0 .../{ => simple}/prisma/schema.prisma | 0 .../{ => simple}/sqlalchemy/Dockerfile | 0 .../{ => simple}/sqlalchemy/__init__.py | 0 robyn/scaffold/{ => simple}/sqlalchemy/app.py | 0 .../{ => simple}/sqlalchemy/models.py | 0 .../{ => simple}/sqlalchemy/requirements.txt | 0 robyn/scaffold/{ => simple}/sqlite/Dockerfile | 0 robyn/scaffold/{ => simple}/sqlite/app.py | 0 .../{ => simple}/sqlite/requirements.txt | 0 .../scaffold/{ => simple}/sqlmodel/Dockerfile | 0 robyn/scaffold/{ => simple}/sqlmodel/app.py | 0 .../scaffold/{ => simple}/sqlmodel/models.py | 0 .../{ => simple}/sqlmodel/requirements.txt | 0 .../structured/no-db/api/handlers/__init__.py | 0 .../no-db/api/middlewares/__init__.py | 0 robyn/scaffold/structured/no-db/conf.py | 0 robyn/scaffold/structured/no-db/router.py | 0 robyn/scaffold/structured/no-db/server.py | 0 .../structured/no-db/utils/__init__.py | 0 .../structured/sqlalchemy/adaptors/models.py | 0 .../sqlalchemy/adaptors/mutators/__init__.py | 0 .../sqlalchemy/adaptors/selectors/__init__.py | 0 .../sqlalchemy/api/handlers/__init__.py | 0 .../sqlalchemy/api/middlewares/__init__.py | 0 robyn/scaffold/structured/sqlalchemy/conf.py | 0 .../scaffold/structured/sqlalchemy/router.py | 0 .../scaffold/structured/sqlalchemy/server.py | 0 .../structured/sqlalchemy/utils/__init__.py | 0 42 files changed, 42 insertions(+), 14 deletions(-) rename robyn/scaffold/{ => simple}/mongo/Dockerfile (100%) rename robyn/scaffold/{ => simple}/mongo/app.py (100%) rename robyn/scaffold/{ => simple}/mongo/requirements.txt (100%) rename robyn/scaffold/{ => simple}/no-db/Dockerfile (100%) rename robyn/scaffold/{ => simple}/no-db/app.py (100%) rename robyn/scaffold/{ => simple}/no-db/requirements.txt (100%) rename robyn/scaffold/{ => simple}/postgres/Dockerfile (100%) rename robyn/scaffold/{ => simple}/postgres/app.py (100%) rename robyn/scaffold/{ => simple}/postgres/requirements.txt (100%) rename robyn/scaffold/{ => simple}/postgres/supervisord.conf (100%) rename robyn/scaffold/{ => simple}/prisma/Dockerfile (100%) rename robyn/scaffold/{ => simple}/prisma/app.py (100%) rename robyn/scaffold/{ => simple}/prisma/requirements.txt (100%) rename robyn/scaffold/{ => simple}/prisma/schema.prisma (100%) rename robyn/scaffold/{ => simple}/sqlalchemy/Dockerfile (100%) rename robyn/scaffold/{ => simple}/sqlalchemy/__init__.py (100%) rename robyn/scaffold/{ => simple}/sqlalchemy/app.py (100%) rename robyn/scaffold/{ => simple}/sqlalchemy/models.py (100%) rename robyn/scaffold/{ => simple}/sqlalchemy/requirements.txt (100%) rename robyn/scaffold/{ => simple}/sqlite/Dockerfile (100%) rename robyn/scaffold/{ => simple}/sqlite/app.py (100%) rename robyn/scaffold/{ => simple}/sqlite/requirements.txt (100%) rename robyn/scaffold/{ => simple}/sqlmodel/Dockerfile (100%) rename robyn/scaffold/{ => simple}/sqlmodel/app.py (100%) rename robyn/scaffold/{ => simple}/sqlmodel/models.py (100%) rename robyn/scaffold/{ => simple}/sqlmodel/requirements.txt (100%) create mode 100644 robyn/scaffold/structured/no-db/api/handlers/__init__.py create mode 100644 robyn/scaffold/structured/no-db/api/middlewares/__init__.py create mode 100644 robyn/scaffold/structured/no-db/conf.py create mode 100644 robyn/scaffold/structured/no-db/router.py create mode 100644 robyn/scaffold/structured/no-db/server.py create mode 100644 robyn/scaffold/structured/no-db/utils/__init__.py create mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/models.py create mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py create mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py create mode 100644 robyn/scaffold/structured/sqlalchemy/api/handlers/__init__.py create mode 100644 robyn/scaffold/structured/sqlalchemy/api/middlewares/__init__.py create mode 100644 robyn/scaffold/structured/sqlalchemy/conf.py create mode 100644 robyn/scaffold/structured/sqlalchemy/router.py create mode 100644 robyn/scaffold/structured/sqlalchemy/server.py create mode 100644 robyn/scaffold/structured/sqlalchemy/utils/__init__.py diff --git a/robyn/cli.py b/robyn/cli.py index 86f925d18..ee018dbd7 100644 --- a/robyn/cli.py +++ b/robyn/cli.py @@ -36,33 +36,61 @@ def create_robyn_app(): }, { "type": "list", - "message": "Please select project type (Mongo/Postgres/Sqlalchemy/Prisma): ", + "name": "scaffold_type", "choices": [ - Choice("no-db", name="No DB"), - Choice("sqlite", name="Sqlite"), - Choice("postgres", name="Postgres"), - Choice("mongo", name="MongoDB"), - Choice("sqlalchemy", name="SqlAlchemy"), - Choice("prisma", name="Prisma"), - Choice("sqlmodel", name="SQLModel"), + Choice("simple", name="Simple"), + Choice("structured", name="Structured") ], - "default": Choice("no-db", name="No DB"), - "name": "project_type", + "message": "Please choose if you'd like the scaffold to be a simple starter kit or an opinionated structure" }, ] result = prompt(questions=questions) project_dir_path = Path(str(result["directory"])).resolve() docker = result["docker"] - project_type = str(result["project_type"]) - - final_project_dir_path = (CURRENT_WORKING_DIR / project_dir_path).resolve() + scaffold_type: str = str(result["scaffold_type"]) + if scaffold_type == "simple": + scaffold_type: str = "simple" + result = prompt(questions=[ + { + "type": "list", + "message": "Please select project type (Mongo/Postgres/Sqlalchemy/Prisma): ", + "choices": [ + Choice("no-db", name="No DB"), + Choice("sqlite", name="Sqlite"), + Choice("postgres", name="Postgres"), + Choice("mongo", name="MongoDB"), + Choice("sqlalchemy", name="SqlAlchemy"), + Choice("prisma", name="Prisma"), + Choice("sqlmodel", name="SQLModel"), + ], + "default": Choice("no-db", name="No DB"), + "name": "project_type", + } + ]) + project_type = str(result["project_type"]) + else: + result = prompt(questions=[ + { + "type": "list", + "message": "Please select project type (Mongo/Postgres/Sqlalchemy/Prisma): ", + "choices": [ + Choice("no-db", name="No DB"), + Choice("sqlalchemy", name="SqlAlchemy"), + ], + "default": Choice("no-db", name="No DB"), + "name": "project_type", + } + ]) + project_type = str(result["project_type"]) + + final_project_dir_path = (CURRENT_WORKING_DIR/project_dir_path).resolve() print(f"Creating a new Robyn project '{final_project_dir_path}'...") # Create a new directory for the project os.makedirs(final_project_dir_path, exist_ok=True) - selected_project_template = (SCAFFOLD_DIR / Path(project_type)).resolve() + selected_project_template = (SCAFFOLD_DIR / Path(scaffold_type) / Path(project_type)).resolve() shutil.copytree(str(selected_project_template), str(final_project_dir_path), dirs_exist_ok=True) # If docker is not needed, delete the docker file diff --git a/robyn/scaffold/mongo/Dockerfile b/robyn/scaffold/simple/mongo/Dockerfile similarity index 100% rename from robyn/scaffold/mongo/Dockerfile rename to robyn/scaffold/simple/mongo/Dockerfile diff --git a/robyn/scaffold/mongo/app.py b/robyn/scaffold/simple/mongo/app.py similarity index 100% rename from robyn/scaffold/mongo/app.py rename to robyn/scaffold/simple/mongo/app.py diff --git a/robyn/scaffold/mongo/requirements.txt b/robyn/scaffold/simple/mongo/requirements.txt similarity index 100% rename from robyn/scaffold/mongo/requirements.txt rename to robyn/scaffold/simple/mongo/requirements.txt diff --git a/robyn/scaffold/no-db/Dockerfile b/robyn/scaffold/simple/no-db/Dockerfile similarity index 100% rename from robyn/scaffold/no-db/Dockerfile rename to robyn/scaffold/simple/no-db/Dockerfile diff --git a/robyn/scaffold/no-db/app.py b/robyn/scaffold/simple/no-db/app.py similarity index 100% rename from robyn/scaffold/no-db/app.py rename to robyn/scaffold/simple/no-db/app.py diff --git a/robyn/scaffold/no-db/requirements.txt b/robyn/scaffold/simple/no-db/requirements.txt similarity index 100% rename from robyn/scaffold/no-db/requirements.txt rename to robyn/scaffold/simple/no-db/requirements.txt diff --git a/robyn/scaffold/postgres/Dockerfile b/robyn/scaffold/simple/postgres/Dockerfile similarity index 100% rename from robyn/scaffold/postgres/Dockerfile rename to robyn/scaffold/simple/postgres/Dockerfile diff --git a/robyn/scaffold/postgres/app.py b/robyn/scaffold/simple/postgres/app.py similarity index 100% rename from robyn/scaffold/postgres/app.py rename to robyn/scaffold/simple/postgres/app.py diff --git a/robyn/scaffold/postgres/requirements.txt b/robyn/scaffold/simple/postgres/requirements.txt similarity index 100% rename from robyn/scaffold/postgres/requirements.txt rename to robyn/scaffold/simple/postgres/requirements.txt diff --git a/robyn/scaffold/postgres/supervisord.conf b/robyn/scaffold/simple/postgres/supervisord.conf similarity index 100% rename from robyn/scaffold/postgres/supervisord.conf rename to robyn/scaffold/simple/postgres/supervisord.conf diff --git a/robyn/scaffold/prisma/Dockerfile b/robyn/scaffold/simple/prisma/Dockerfile similarity index 100% rename from robyn/scaffold/prisma/Dockerfile rename to robyn/scaffold/simple/prisma/Dockerfile diff --git a/robyn/scaffold/prisma/app.py b/robyn/scaffold/simple/prisma/app.py similarity index 100% rename from robyn/scaffold/prisma/app.py rename to robyn/scaffold/simple/prisma/app.py diff --git a/robyn/scaffold/prisma/requirements.txt b/robyn/scaffold/simple/prisma/requirements.txt similarity index 100% rename from robyn/scaffold/prisma/requirements.txt rename to robyn/scaffold/simple/prisma/requirements.txt diff --git a/robyn/scaffold/prisma/schema.prisma b/robyn/scaffold/simple/prisma/schema.prisma similarity index 100% rename from robyn/scaffold/prisma/schema.prisma rename to robyn/scaffold/simple/prisma/schema.prisma diff --git a/robyn/scaffold/sqlalchemy/Dockerfile b/robyn/scaffold/simple/sqlalchemy/Dockerfile similarity index 100% rename from robyn/scaffold/sqlalchemy/Dockerfile rename to robyn/scaffold/simple/sqlalchemy/Dockerfile diff --git a/robyn/scaffold/sqlalchemy/__init__.py b/robyn/scaffold/simple/sqlalchemy/__init__.py similarity index 100% rename from robyn/scaffold/sqlalchemy/__init__.py rename to robyn/scaffold/simple/sqlalchemy/__init__.py diff --git a/robyn/scaffold/sqlalchemy/app.py b/robyn/scaffold/simple/sqlalchemy/app.py similarity index 100% rename from robyn/scaffold/sqlalchemy/app.py rename to robyn/scaffold/simple/sqlalchemy/app.py diff --git a/robyn/scaffold/sqlalchemy/models.py b/robyn/scaffold/simple/sqlalchemy/models.py similarity index 100% rename from robyn/scaffold/sqlalchemy/models.py rename to robyn/scaffold/simple/sqlalchemy/models.py diff --git a/robyn/scaffold/sqlalchemy/requirements.txt b/robyn/scaffold/simple/sqlalchemy/requirements.txt similarity index 100% rename from robyn/scaffold/sqlalchemy/requirements.txt rename to robyn/scaffold/simple/sqlalchemy/requirements.txt diff --git a/robyn/scaffold/sqlite/Dockerfile b/robyn/scaffold/simple/sqlite/Dockerfile similarity index 100% rename from robyn/scaffold/sqlite/Dockerfile rename to robyn/scaffold/simple/sqlite/Dockerfile diff --git a/robyn/scaffold/sqlite/app.py b/robyn/scaffold/simple/sqlite/app.py similarity index 100% rename from robyn/scaffold/sqlite/app.py rename to robyn/scaffold/simple/sqlite/app.py diff --git a/robyn/scaffold/sqlite/requirements.txt b/robyn/scaffold/simple/sqlite/requirements.txt similarity index 100% rename from robyn/scaffold/sqlite/requirements.txt rename to robyn/scaffold/simple/sqlite/requirements.txt diff --git a/robyn/scaffold/sqlmodel/Dockerfile b/robyn/scaffold/simple/sqlmodel/Dockerfile similarity index 100% rename from robyn/scaffold/sqlmodel/Dockerfile rename to robyn/scaffold/simple/sqlmodel/Dockerfile diff --git a/robyn/scaffold/sqlmodel/app.py b/robyn/scaffold/simple/sqlmodel/app.py similarity index 100% rename from robyn/scaffold/sqlmodel/app.py rename to robyn/scaffold/simple/sqlmodel/app.py diff --git a/robyn/scaffold/sqlmodel/models.py b/robyn/scaffold/simple/sqlmodel/models.py similarity index 100% rename from robyn/scaffold/sqlmodel/models.py rename to robyn/scaffold/simple/sqlmodel/models.py diff --git a/robyn/scaffold/sqlmodel/requirements.txt b/robyn/scaffold/simple/sqlmodel/requirements.txt similarity index 100% rename from robyn/scaffold/sqlmodel/requirements.txt rename to robyn/scaffold/simple/sqlmodel/requirements.txt diff --git a/robyn/scaffold/structured/no-db/api/handlers/__init__.py b/robyn/scaffold/structured/no-db/api/handlers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/no-db/api/middlewares/__init__.py b/robyn/scaffold/structured/no-db/api/middlewares/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/no-db/conf.py b/robyn/scaffold/structured/no-db/conf.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/no-db/router.py b/robyn/scaffold/structured/no-db/router.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/no-db/server.py b/robyn/scaffold/structured/no-db/server.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/no-db/utils/__init__.py b/robyn/scaffold/structured/no-db/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/models.py b/robyn/scaffold/structured/sqlalchemy/adaptors/models.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/__init__.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/api/middlewares/__init__.py b/robyn/scaffold/structured/sqlalchemy/api/middlewares/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/conf.py b/robyn/scaffold/structured/sqlalchemy/conf.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/router.py b/robyn/scaffold/structured/sqlalchemy/router.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/server.py b/robyn/scaffold/structured/sqlalchemy/server.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/utils/__init__.py b/robyn/scaffold/structured/sqlalchemy/utils/__init__.py new file mode 100644 index 000000000..e69de29bb From 56e174aa80bf874b49d5f36bc693ae6e4580eb14 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 25 Sep 2024 18:35:32 +0530 Subject: [PATCH 02/63] chore: adding auto discover routes --- robyn/helpers.py | 24 +++++++++++++++++++ .../structured/no-db/api/handlers/probes.py | 14 +++++++++++ .../structured/no-db/api/handlers/sample.py | 16 +++++++++++++ robyn/scaffold/structured/no-db/router.py | 10 ++++++++ robyn/scaffold/structured/no-db/server.py | 7 ++++++ 5 files changed, 71 insertions(+) create mode 100644 robyn/helpers.py create mode 100644 robyn/scaffold/structured/no-db/api/handlers/probes.py create mode 100644 robyn/scaffold/structured/no-db/api/handlers/sample.py diff --git a/robyn/helpers.py b/robyn/helpers.py new file mode 100644 index 000000000..b5b0faedf --- /dev/null +++ b/robyn/helpers.py @@ -0,0 +1,24 @@ +import importlib +import pkgutil +from robyn import Robyn + + +def discover_routes() -> Robyn: + mux: Robyn = Robyn(__file__) + + # Specify the package where your routers are located + package_name = 'api.handlers' + + # Dynamically import routers + package = importlib.import_module(package_name) + + # Iterate through the members of the package + for _, module_name, _ in pkgutil.iter_modules(package.__path__, package.__name__ + '.'): + module = importlib.import_module(module_name) + + # Get all members of the module and filter for routers + for name, member in vars(module).items(): + if hasattr(member, 'include_router'): + mux.include_router(member) + + return mux diff --git a/robyn/scaffold/structured/no-db/api/handlers/probes.py b/robyn/scaffold/structured/no-db/api/handlers/probes.py new file mode 100644 index 000000000..43a6ee6dd --- /dev/null +++ b/robyn/scaffold/structured/no-db/api/handlers/probes.py @@ -0,0 +1,14 @@ +from robyn import SubRouter + + +router = SubRouter("/") + + +@router.get("/livez/") +def livez() -> str: + return "live" + + +@router.get("/healthz/") +def healthz() -> str: + return "healthy" diff --git a/robyn/scaffold/structured/no-db/api/handlers/sample.py b/robyn/scaffold/structured/no-db/api/handlers/sample.py new file mode 100644 index 000000000..11b23d555 --- /dev/null +++ b/robyn/scaffold/structured/no-db/api/handlers/sample.py @@ -0,0 +1,16 @@ +from robyn import SubRouter + +router = SubRouter("/sample") + + +class SampleHandlers: + + @router.get("/one") + @staticmethod + def one(): + ... + + @router.get("/two") + @staticmethod + def two(): + ... diff --git a/robyn/scaffold/structured/no-db/router.py b/robyn/scaffold/structured/no-db/router.py index e69de29bb..b209f506e 100644 --- a/robyn/scaffold/structured/no-db/router.py +++ b/robyn/scaffold/structured/no-db/router.py @@ -0,0 +1,10 @@ +from robyn import Robyn +from api.handlers.probes import router as probes +from api.handlers.sample import router as sample + + +def build_routes() -> Robyn: + mux: Robyn = Robyn(__file__) + mux.include_router(probes) + mux.include_router(sample) + return mux diff --git a/robyn/scaffold/structured/no-db/server.py b/robyn/scaffold/structured/no-db/server.py index e69de29bb..fe3d6378c 100644 --- a/robyn/scaffold/structured/no-db/server.py +++ b/robyn/scaffold/structured/no-db/server.py @@ -0,0 +1,7 @@ +from robyn import Robyn +from router import build_routes + +app: Robyn = build_routes() + +if __name__ == "__main__": + app.start(host="0.0.0.0", port=8080) From 03918ac319e092420453b808d29d263c44938a20 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 25 Sep 2024 18:45:31 +0530 Subject: [PATCH 03/63] chore: added discover routes --- robyn/helpers.py | 18 ++++++------------ robyn/scaffold/structured/no-db/server.py | 5 ++++- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/robyn/helpers.py b/robyn/helpers.py index b5b0faedf..00d591863 100644 --- a/robyn/helpers.py +++ b/robyn/helpers.py @@ -2,23 +2,17 @@ import pkgutil from robyn import Robyn +import logging +logger = logging.getLogger(__name__) -def discover_routes() -> Robyn: - mux: Robyn = Robyn(__file__) - - # Specify the package where your routers are located - package_name = 'api.handlers' - - # Dynamically import routers - package = importlib.import_module(package_name) - # Iterate through the members of the package +def discover_routes(handler_path: str = "api.handlers") -> Robyn: + mux: Robyn = Robyn(__file__) + package = importlib.import_module(handler_path) for _, module_name, _ in pkgutil.iter_modules(package.__path__, package.__name__ + '.'): module = importlib.import_module(module_name) - - # Get all members of the module and filter for routers for name, member in vars(module).items(): if hasattr(member, 'include_router'): + logger.info(f"detected route: {name}") mux.include_router(member) - return mux diff --git a/robyn/scaffold/structured/no-db/server.py b/robyn/scaffold/structured/no-db/server.py index fe3d6378c..0dee521ca 100644 --- a/robyn/scaffold/structured/no-db/server.py +++ b/robyn/scaffold/structured/no-db/server.py @@ -1,7 +1,10 @@ from robyn import Robyn +from robyn.helpers import discover_routes from router import build_routes -app: Robyn = build_routes() +# app: Robyn = build_routes() +# OR +app: Robyn = discover_routes() if __name__ == "__main__": app.start(host="0.0.0.0", port=8080) From 10d3c8310567e7e63eb92f7edf371d17968db193 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 25 Sep 2024 22:03:07 +0530 Subject: [PATCH 04/63] chore: updated server --- robyn/scaffold/structured/no-db/server.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/robyn/scaffold/structured/no-db/server.py b/robyn/scaffold/structured/no-db/server.py index 0dee521ca..0551f310c 100644 --- a/robyn/scaffold/structured/no-db/server.py +++ b/robyn/scaffold/structured/no-db/server.py @@ -1,10 +1,7 @@ from robyn import Robyn from robyn.helpers import discover_routes -from router import build_routes -# app: Robyn = build_routes() -# OR -app: Robyn = discover_routes() +app: Robyn = discover_routes("api.handlers") if __name__ == "__main__": app.start(host="0.0.0.0", port=8080) From 0baab2b69d3ccaf7286c9971115bfddae4ff82cd Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 25 Sep 2024 22:39:49 +0530 Subject: [PATCH 05/63] feat: finished no db scaffolding --- robyn/cli.py | 5 ++- robyn/helpers.py | 40 ++++++++++++++++--- .../structured/no-db/api/handlers/sample.py | 2 +- robyn/scaffold/structured/no-db/conf.py | 8 ++++ robyn/scaffold/structured/no-db/config.env | 1 + .../structured/no-db/devops/Dockerfile | 14 +++++++ .../structured/no-db/devops/Dockerfile.src | 0 .../no-db/devops/docker-compose.yaml | 11 +++++ .../structured/no-db/requirements.txt | 3 ++ robyn/scaffold/structured/no-db/router.py | 10 ----- robyn/scaffold/structured/no-db/server.py | 8 +++- 11 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 robyn/scaffold/structured/no-db/config.env create mode 100644 robyn/scaffold/structured/no-db/devops/Dockerfile create mode 100644 robyn/scaffold/structured/no-db/devops/Dockerfile.src create mode 100644 robyn/scaffold/structured/no-db/devops/docker-compose.yaml create mode 100644 robyn/scaffold/structured/no-db/requirements.txt delete mode 100644 robyn/scaffold/structured/no-db/router.py diff --git a/robyn/cli.py b/robyn/cli.py index ee018dbd7..78df036f3 100644 --- a/robyn/cli.py +++ b/robyn/cli.py @@ -95,7 +95,10 @@ def create_robyn_app(): # If docker is not needed, delete the docker file if docker == "N": - os.remove(f"{final_project_dir_path}/Dockerfile") + if scaffold_type == "simple": + os.remove(f"{final_project_dir_path}/Dockerfile") + else: + shutil.rmtree(f"{final_project_dir_path}/devops") print(f"New Robyn project created in '{final_project_dir_path}' ") diff --git a/robyn/helpers.py b/robyn/helpers.py index 00d591863..8461c0e65 100644 --- a/robyn/helpers.py +++ b/robyn/helpers.py @@ -1,8 +1,12 @@ +from typing import Any, Type, Tuple +from pydantic_settings import BaseSettings, EnvSettingsSource, PydanticBaseSettingsSource +from pydantic import ConfigDict + import importlib import pkgutil -from robyn import Robyn - import logging + +from robyn import Robyn logger = logging.getLogger(__name__) @@ -11,8 +15,32 @@ def discover_routes(handler_path: str = "api.handlers") -> Robyn: package = importlib.import_module(handler_path) for _, module_name, _ in pkgutil.iter_modules(package.__path__, package.__name__ + '.'): module = importlib.import_module(module_name) - for name, member in vars(module).items(): - if hasattr(member, 'include_router'): - logger.info(f"detected route: {name}") - mux.include_router(member) + logger.info(f"member: {module}") + mux.include_router(module.router) return mux + + + + +class AcceptArrayEnvsSource(EnvSettingsSource): + def prepare_field_value( + self, field_name: str, field: Any, value: Any, value_is_complex: bool + ) -> Any: + if isinstance(field.annotation, type) and issubclass(field.annotation, list) and isinstance(value, str): + return [x.strip() for x in value.split(",") if x] + return value + + +class BaseConfig(BaseSettings): + @classmethod + def settings_customise_sources( + cls, + settings_cls: Type[BaseSettings], + init_settings: PydanticBaseSettingsSource, + env_settings: PydanticBaseSettingsSource, + dotenv_settings: PydanticBaseSettingsSource, + file_secret_settings: PydanticBaseSettingsSource, + ) -> Tuple[PydanticBaseSettingsSource, ...]: + return (AcceptArrayEnvsSource(settings_cls),) + + model_config = ConfigDict(extra='ignore') # Ignore extra environment variables diff --git a/robyn/scaffold/structured/no-db/api/handlers/sample.py b/robyn/scaffold/structured/no-db/api/handlers/sample.py index 11b23d555..efb4a4545 100644 --- a/robyn/scaffold/structured/no-db/api/handlers/sample.py +++ b/robyn/scaffold/structured/no-db/api/handlers/sample.py @@ -5,7 +5,7 @@ class SampleHandlers: - @router.get("/one") + @router.post("/one") @staticmethod def one(): ... diff --git a/robyn/scaffold/structured/no-db/conf.py b/robyn/scaffold/structured/no-db/conf.py index e69de29bb..d2b535143 100644 --- a/robyn/scaffold/structured/no-db/conf.py +++ b/robyn/scaffold/structured/no-db/conf.py @@ -0,0 +1,8 @@ +from robyn.helpers import BaseConfig + + +class Settings(BaseConfig): + service_port: int + + +settings = Settings() diff --git a/robyn/scaffold/structured/no-db/config.env b/robyn/scaffold/structured/no-db/config.env new file mode 100644 index 000000000..92ad6152c --- /dev/null +++ b/robyn/scaffold/structured/no-db/config.env @@ -0,0 +1 @@ +SERVICE_PORT=3000 diff --git a/robyn/scaffold/structured/no-db/devops/Dockerfile b/robyn/scaffold/structured/no-db/devops/Dockerfile new file mode 100644 index 000000000..903705ca0 --- /dev/null +++ b/robyn/scaffold/structured/no-db/devops/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.11-bookworm AS builder + +WORKDIR /workspace + +COPY . . +RUN pip install --no-cache-dir --upgrade -r requirements.txt --target=/workspace/deps + +FROM gcr.io/distroless/python3-debian11 + +WORKDIR /workspace +COPY --from=builder /workspace /workspace +ENV PYTHONPATH=/workspace/deps + +CMD ["server.py", "--log-level=DEBUG"] diff --git a/robyn/scaffold/structured/no-db/devops/Dockerfile.src b/robyn/scaffold/structured/no-db/devops/Dockerfile.src new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/no-db/devops/docker-compose.yaml b/robyn/scaffold/structured/no-db/devops/docker-compose.yaml new file mode 100644 index 000000000..66ebcc9e2 --- /dev/null +++ b/robyn/scaffold/structured/no-db/devops/docker-compose.yaml @@ -0,0 +1,11 @@ +version: '3' +services: + + service: + image: service # build an image with this tag + container_name: "service" + env_file: + - ../config.env + network_mode: host + + diff --git a/robyn/scaffold/structured/no-db/requirements.txt b/robyn/scaffold/structured/no-db/requirements.txt new file mode 100644 index 000000000..4ec60ebb2 --- /dev/null +++ b/robyn/scaffold/structured/no-db/requirements.txt @@ -0,0 +1,3 @@ +robyn +pydantic~=2.7.4 +pydantic-settings~=2.2.1 diff --git a/robyn/scaffold/structured/no-db/router.py b/robyn/scaffold/structured/no-db/router.py deleted file mode 100644 index b209f506e..000000000 --- a/robyn/scaffold/structured/no-db/router.py +++ /dev/null @@ -1,10 +0,0 @@ -from robyn import Robyn -from api.handlers.probes import router as probes -from api.handlers.sample import router as sample - - -def build_routes() -> Robyn: - mux: Robyn = Robyn(__file__) - mux.include_router(probes) - mux.include_router(sample) - return mux diff --git a/robyn/scaffold/structured/no-db/server.py b/robyn/scaffold/structured/no-db/server.py index 0551f310c..057eed07e 100644 --- a/robyn/scaffold/structured/no-db/server.py +++ b/robyn/scaffold/structured/no-db/server.py @@ -1,7 +1,11 @@ -from robyn import Robyn from robyn.helpers import discover_routes +from robyn import Robyn + +from conf import settings app: Robyn = discover_routes("api.handlers") +# note: if you prefer to manuall refine routes, use your build_routes function instead + if __name__ == "__main__": - app.start(host="0.0.0.0", port=8080) + app.start(host="0.0.0.0", port=settings.service_port) From 481bed8271020d9e598de5e51cddbb3f48cc50a6 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 25 Sep 2024 22:40:27 +0530 Subject: [PATCH 06/63] chore: copied over no db stuff to db --- .../sqlalchemy/adaptors/mutators/__init__.py | 0 .../sqlalchemy/adaptors/selectors/__init__.py | 0 .../structured/sqlalchemy/api/handlers/probes.py | 14 ++++++++++++++ .../structured/sqlalchemy/api/handlers/sample.py | 16 ++++++++++++++++ robyn/scaffold/structured/sqlalchemy/conf.py | 8 ++++++++ robyn/scaffold/structured/sqlalchemy/config.env | 1 + .../structured/sqlalchemy/devops/Dockerfile | 14 ++++++++++++++ .../models.py => devops/Dockerfile.src} | 0 .../sqlalchemy/devops/docker-compose.yaml | 11 +++++++++++ .../structured/sqlalchemy/requirements.txt | 3 +++ robyn/scaffold/structured/sqlalchemy/router.py | 0 robyn/scaffold/structured/sqlalchemy/server.py | 11 +++++++++++ 12 files changed, 78 insertions(+) delete mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py delete mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py create mode 100644 robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py create mode 100644 robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py create mode 100644 robyn/scaffold/structured/sqlalchemy/config.env create mode 100644 robyn/scaffold/structured/sqlalchemy/devops/Dockerfile rename robyn/scaffold/structured/sqlalchemy/{adaptors/models.py => devops/Dockerfile.src} (100%) create mode 100644 robyn/scaffold/structured/sqlalchemy/devops/docker-compose.yaml create mode 100644 robyn/scaffold/structured/sqlalchemy/requirements.txt delete mode 100644 robyn/scaffold/structured/sqlalchemy/router.py diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py new file mode 100644 index 000000000..43a6ee6dd --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py @@ -0,0 +1,14 @@ +from robyn import SubRouter + + +router = SubRouter("/") + + +@router.get("/livez/") +def livez() -> str: + return "live" + + +@router.get("/healthz/") +def healthz() -> str: + return "healthy" diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py new file mode 100644 index 000000000..efb4a4545 --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -0,0 +1,16 @@ +from robyn import SubRouter + +router = SubRouter("/sample") + + +class SampleHandlers: + + @router.post("/one") + @staticmethod + def one(): + ... + + @router.get("/two") + @staticmethod + def two(): + ... diff --git a/robyn/scaffold/structured/sqlalchemy/conf.py b/robyn/scaffold/structured/sqlalchemy/conf.py index e69de29bb..d2b535143 100644 --- a/robyn/scaffold/structured/sqlalchemy/conf.py +++ b/robyn/scaffold/structured/sqlalchemy/conf.py @@ -0,0 +1,8 @@ +from robyn.helpers import BaseConfig + + +class Settings(BaseConfig): + service_port: int + + +settings = Settings() diff --git a/robyn/scaffold/structured/sqlalchemy/config.env b/robyn/scaffold/structured/sqlalchemy/config.env new file mode 100644 index 000000000..92ad6152c --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/config.env @@ -0,0 +1 @@ +SERVICE_PORT=3000 diff --git a/robyn/scaffold/structured/sqlalchemy/devops/Dockerfile b/robyn/scaffold/structured/sqlalchemy/devops/Dockerfile new file mode 100644 index 000000000..903705ca0 --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/devops/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.11-bookworm AS builder + +WORKDIR /workspace + +COPY . . +RUN pip install --no-cache-dir --upgrade -r requirements.txt --target=/workspace/deps + +FROM gcr.io/distroless/python3-debian11 + +WORKDIR /workspace +COPY --from=builder /workspace /workspace +ENV PYTHONPATH=/workspace/deps + +CMD ["server.py", "--log-level=DEBUG"] diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/models.py b/robyn/scaffold/structured/sqlalchemy/devops/Dockerfile.src similarity index 100% rename from robyn/scaffold/structured/sqlalchemy/adaptors/models.py rename to robyn/scaffold/structured/sqlalchemy/devops/Dockerfile.src diff --git a/robyn/scaffold/structured/sqlalchemy/devops/docker-compose.yaml b/robyn/scaffold/structured/sqlalchemy/devops/docker-compose.yaml new file mode 100644 index 000000000..66ebcc9e2 --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/devops/docker-compose.yaml @@ -0,0 +1,11 @@ +version: '3' +services: + + service: + image: service # build an image with this tag + container_name: "service" + env_file: + - ../config.env + network_mode: host + + diff --git a/robyn/scaffold/structured/sqlalchemy/requirements.txt b/robyn/scaffold/structured/sqlalchemy/requirements.txt new file mode 100644 index 000000000..4ec60ebb2 --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/requirements.txt @@ -0,0 +1,3 @@ +robyn +pydantic~=2.7.4 +pydantic-settings~=2.2.1 diff --git a/robyn/scaffold/structured/sqlalchemy/router.py b/robyn/scaffold/structured/sqlalchemy/router.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/robyn/scaffold/structured/sqlalchemy/server.py b/robyn/scaffold/structured/sqlalchemy/server.py index e69de29bb..057eed07e 100644 --- a/robyn/scaffold/structured/sqlalchemy/server.py +++ b/robyn/scaffold/structured/sqlalchemy/server.py @@ -0,0 +1,11 @@ +from robyn.helpers import discover_routes +from robyn import Robyn + +from conf import settings + +app: Robyn = discover_routes("api.handlers") +# note: if you prefer to manuall refine routes, use your build_routes function instead + + +if __name__ == "__main__": + app.start(host="0.0.0.0", port=settings.service_port) From c0c5dd46ef562f391398c5f47e65997e88116f75 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 25 Sep 2024 22:50:32 +0530 Subject: [PATCH 07/63] chore: added db connection pool and envs to sqlalchemy structured scaffolding --- .../sqlalchemy/adaptors/__init__.py | 0 robyn/scaffold/structured/sqlalchemy/conf.py | 6 ++++++ .../scaffold/structured/sqlalchemy/config.env | 7 +++++++ .../structured/sqlalchemy/utils/db.py | 19 +++++++++++++++++++ 4 files changed, 32 insertions(+) create mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/__init__.py create mode 100644 robyn/scaffold/structured/sqlalchemy/utils/db.py diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/conf.py b/robyn/scaffold/structured/sqlalchemy/conf.py index d2b535143..8b2050d67 100644 --- a/robyn/scaffold/structured/sqlalchemy/conf.py +++ b/robyn/scaffold/structured/sqlalchemy/conf.py @@ -3,6 +3,12 @@ class Settings(BaseConfig): service_port: int + database_url: str + db_pool_size: int + db_pool_max_overflow: int + db_pool_timeout: int + db_pool_recycle: int + db_pool_echo: bool settings = Settings() diff --git a/robyn/scaffold/structured/sqlalchemy/config.env b/robyn/scaffold/structured/sqlalchemy/config.env index 92ad6152c..97c3c275a 100644 --- a/robyn/scaffold/structured/sqlalchemy/config.env +++ b/robyn/scaffold/structured/sqlalchemy/config.env @@ -1 +1,8 @@ SERVICE_PORT=3000 +# change the engine as per db +DATABASE_URL=postgresql+psycopg2://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME} +DB_POOL_SIZE=10 +DB_MAX_OVERFLOW=20 +DB_POOL_TIMEOUT=30 +DB_POOL_RECYCLE=1800 +DB_POOL_ECHO=True diff --git a/robyn/scaffold/structured/sqlalchemy/utils/db.py b/robyn/scaffold/structured/sqlalchemy/utils/db.py new file mode 100644 index 000000000..aecf3c47d --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/utils/db.py @@ -0,0 +1,19 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from conf import settings + +import logging +logger = logging.getLogger(__name__) + +def get_pool(): + dsn = settings.database_url + logger.info(f"creating client db pool with dsn: {dsn}") + engine = create_engine( + dsn, + pool_size=settings.db_pool_size, + max_overflow=settings.db_pool_max_overflow, + pool_timeout=settings.db_pool_timeout, + pool_recycle=settings.db_pool_recycle, + echo=settings.db_pool_recycle + ) + return sessionmaker(bind=engine) From a4c2730846ea3da10f69d475e82ea579552399d2 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 25 Sep 2024 22:53:54 +0530 Subject: [PATCH 08/63] feat: added sqlalchemy and pydantic example models to scaffold --- .../structured/sqlalchemy/adaptors/models.py | 16 ++++++++++++++++ .../structured/sqlalchemy/adaptors/schema.py | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/models.py create mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/schema.py diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/models.py b/robyn/scaffold/structured/sqlalchemy/adaptors/models.py new file mode 100644 index 000000000..f7b310080 --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/models.py @@ -0,0 +1,16 @@ +from sqlalchemy import String, Integer, Boolean +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + +# SQLAlchemy Base class for declarative mapping +class Base(DeclarativeBase): + pass + +# SQLAlchemy 2.0 model definition +class User(Base): + __tablename__ = "users" + + id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) + username: Mapped[str] = mapped_column(String, unique=True, index=True) + hashed_password: Mapped[str] = mapped_column(String) + is_active: Mapped[bool] = mapped_column(Boolean, default=True) + is_superuser: Mapped[bool] = mapped_column(Boolean, default=False) diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/schema.py b/robyn/scaffold/structured/sqlalchemy/adaptors/schema.py new file mode 100644 index 000000000..aaec97c39 --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/schema.py @@ -0,0 +1,18 @@ +from pydantic import BaseModel + +class UserRead(BaseModel): + id: int + username: str + is_active: bool + is_superuser: bool + + class Config: + orm_mode = True + +# Pydantic model for creating/updating a user +class UserCreate(BaseModel): + username: str + password: str + + class Config: + orm_mode = True From e98ce501f0e514f5339855826c7c28a8518a6935 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:29:35 +0000 Subject: [PATCH 09/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- robyn/cli.py | 71 ++++++++++--------- robyn/helpers.py | 11 ++- .../structured/no-db/api/handlers/sample.py | 7 +- .../structured/sqlalchemy/adaptors/models.py | 2 + .../structured/sqlalchemy/adaptors/schema.py | 4 +- .../sqlalchemy/api/handlers/sample.py | 7 +- .../structured/sqlalchemy/utils/db.py | 4 +- 7 files changed, 52 insertions(+), 54 deletions(-) diff --git a/robyn/cli.py b/robyn/cli.py index 78df036f3..15b6ae09e 100644 --- a/robyn/cli.py +++ b/robyn/cli.py @@ -37,11 +37,8 @@ def create_robyn_app(): { "type": "list", "name": "scaffold_type", - "choices": [ - Choice("simple", name="Simple"), - Choice("structured", name="Structured") - ], - "message": "Please choose if you'd like the scaffold to be a simple starter kit or an opinionated structure" + "choices": [Choice("simple", name="Simple"), Choice("structured", name="Structured")], + "message": "Please choose if you'd like the scaffold to be a simple starter kit or an opinionated structure", }, ] result = prompt(questions=questions) @@ -50,40 +47,44 @@ def create_robyn_app(): scaffold_type: str = str(result["scaffold_type"]) if scaffold_type == "simple": scaffold_type: str = "simple" - result = prompt(questions=[ - { - "type": "list", - "message": "Please select project type (Mongo/Postgres/Sqlalchemy/Prisma): ", - "choices": [ - Choice("no-db", name="No DB"), - Choice("sqlite", name="Sqlite"), - Choice("postgres", name="Postgres"), - Choice("mongo", name="MongoDB"), - Choice("sqlalchemy", name="SqlAlchemy"), - Choice("prisma", name="Prisma"), - Choice("sqlmodel", name="SQLModel"), - ], - "default": Choice("no-db", name="No DB"), - "name": "project_type", - } - ]) + result = prompt( + questions=[ + { + "type": "list", + "message": "Please select project type (Mongo/Postgres/Sqlalchemy/Prisma): ", + "choices": [ + Choice("no-db", name="No DB"), + Choice("sqlite", name="Sqlite"), + Choice("postgres", name="Postgres"), + Choice("mongo", name="MongoDB"), + Choice("sqlalchemy", name="SqlAlchemy"), + Choice("prisma", name="Prisma"), + Choice("sqlmodel", name="SQLModel"), + ], + "default": Choice("no-db", name="No DB"), + "name": "project_type", + } + ] + ) project_type = str(result["project_type"]) else: - result = prompt(questions=[ - { - "type": "list", - "message": "Please select project type (Mongo/Postgres/Sqlalchemy/Prisma): ", - "choices": [ - Choice("no-db", name="No DB"), - Choice("sqlalchemy", name="SqlAlchemy"), - ], - "default": Choice("no-db", name="No DB"), - "name": "project_type", - } - ]) + result = prompt( + questions=[ + { + "type": "list", + "message": "Please select project type (Mongo/Postgres/Sqlalchemy/Prisma): ", + "choices": [ + Choice("no-db", name="No DB"), + Choice("sqlalchemy", name="SqlAlchemy"), + ], + "default": Choice("no-db", name="No DB"), + "name": "project_type", + } + ] + ) project_type = str(result["project_type"]) - final_project_dir_path = (CURRENT_WORKING_DIR/project_dir_path).resolve() + final_project_dir_path = (CURRENT_WORKING_DIR / project_dir_path).resolve() print(f"Creating a new Robyn project '{final_project_dir_path}'...") diff --git a/robyn/helpers.py b/robyn/helpers.py index 8461c0e65..2253618d9 100644 --- a/robyn/helpers.py +++ b/robyn/helpers.py @@ -7,25 +7,22 @@ import logging from robyn import Robyn + logger = logging.getLogger(__name__) def discover_routes(handler_path: str = "api.handlers") -> Robyn: mux: Robyn = Robyn(__file__) package = importlib.import_module(handler_path) - for _, module_name, _ in pkgutil.iter_modules(package.__path__, package.__name__ + '.'): + for _, module_name, _ in pkgutil.iter_modules(package.__path__, package.__name__ + "."): module = importlib.import_module(module_name) logger.info(f"member: {module}") mux.include_router(module.router) return mux - - class AcceptArrayEnvsSource(EnvSettingsSource): - def prepare_field_value( - self, field_name: str, field: Any, value: Any, value_is_complex: bool - ) -> Any: + def prepare_field_value(self, field_name: str, field: Any, value: Any, value_is_complex: bool) -> Any: if isinstance(field.annotation, type) and issubclass(field.annotation, list) and isinstance(value, str): return [x.strip() for x in value.split(",") if x] return value @@ -43,4 +40,4 @@ def settings_customise_sources( ) -> Tuple[PydanticBaseSettingsSource, ...]: return (AcceptArrayEnvsSource(settings_cls),) - model_config = ConfigDict(extra='ignore') # Ignore extra environment variables + model_config = ConfigDict(extra="ignore") # Ignore extra environment variables diff --git a/robyn/scaffold/structured/no-db/api/handlers/sample.py b/robyn/scaffold/structured/no-db/api/handlers/sample.py index efb4a4545..4df2278ca 100644 --- a/robyn/scaffold/structured/no-db/api/handlers/sample.py +++ b/robyn/scaffold/structured/no-db/api/handlers/sample.py @@ -4,13 +4,10 @@ class SampleHandlers: - @router.post("/one") @staticmethod - def one(): - ... + def one(): ... @router.get("/two") @staticmethod - def two(): - ... + def two(): ... diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/models.py b/robyn/scaffold/structured/sqlalchemy/adaptors/models.py index f7b310080..20fca3335 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/models.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/models.py @@ -1,10 +1,12 @@ from sqlalchemy import String, Integer, Boolean from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + # SQLAlchemy Base class for declarative mapping class Base(DeclarativeBase): pass + # SQLAlchemy 2.0 model definition class User(Base): __tablename__ = "users" diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/schema.py b/robyn/scaffold/structured/sqlalchemy/adaptors/schema.py index aaec97c39..698e83f00 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/schema.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/schema.py @@ -1,5 +1,6 @@ from pydantic import BaseModel + class UserRead(BaseModel): id: int username: str @@ -7,7 +8,8 @@ class UserRead(BaseModel): is_superuser: bool class Config: - orm_mode = True + orm_mode = True + # Pydantic model for creating/updating a user class UserCreate(BaseModel): diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index efb4a4545..4df2278ca 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -4,13 +4,10 @@ class SampleHandlers: - @router.post("/one") @staticmethod - def one(): - ... + def one(): ... @router.get("/two") @staticmethod - def two(): - ... + def two(): ... diff --git a/robyn/scaffold/structured/sqlalchemy/utils/db.py b/robyn/scaffold/structured/sqlalchemy/utils/db.py index aecf3c47d..f98d54668 100644 --- a/robyn/scaffold/structured/sqlalchemy/utils/db.py +++ b/robyn/scaffold/structured/sqlalchemy/utils/db.py @@ -3,8 +3,10 @@ from conf import settings import logging + logger = logging.getLogger(__name__) + def get_pool(): dsn = settings.database_url logger.info(f"creating client db pool with dsn: {dsn}") @@ -14,6 +16,6 @@ def get_pool(): max_overflow=settings.db_pool_max_overflow, pool_timeout=settings.db_pool_timeout, pool_recycle=settings.db_pool_recycle, - echo=settings.db_pool_recycle + echo=settings.db_pool_recycle, ) return sessionmaker(bind=engine) From cdcb9479366b35b764e71a5f243f842db6f4be0e Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Thu, 26 Sep 2024 08:47:45 +0530 Subject: [PATCH 10/63] feat: added alembic migration support --- .../structured/sqlalchemy/adaptors/models.py | 2 - .../sqlalchemy/adaptors/mutators/__init__.py | 0 .../sqlalchemy/adaptors/selectors/__init__.py | 0 .../structured/sqlalchemy/alembic.ini | 117 ++++++++++++++++++ .../structured/sqlalchemy/migrations/README | 1 + .../structured/sqlalchemy/migrations/env.py | 75 +++++++++++ .../sqlalchemy/migrations/script.py.mako | 26 ++++ .../structured/sqlalchemy/utils/db.py | 2 +- 8 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py create mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py create mode 100644 robyn/scaffold/structured/sqlalchemy/alembic.ini create mode 100644 robyn/scaffold/structured/sqlalchemy/migrations/README create mode 100644 robyn/scaffold/structured/sqlalchemy/migrations/env.py create mode 100644 robyn/scaffold/structured/sqlalchemy/migrations/script.py.mako diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/models.py b/robyn/scaffold/structured/sqlalchemy/adaptors/models.py index 20fca3335..5b4864fd9 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/models.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/models.py @@ -2,12 +2,10 @@ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column -# SQLAlchemy Base class for declarative mapping class Base(DeclarativeBase): pass -# SQLAlchemy 2.0 model definition class User(Base): __tablename__ = "users" diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/alembic.ini b/robyn/scaffold/structured/sqlalchemy/alembic.ini new file mode 100644 index 000000000..18f8896c7 --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/alembic.ini @@ -0,0 +1,117 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +# Use forward slashes (/) also on windows to provide an os agnostic path +script_location = migrations + +# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s +# Uncomment the line below if you want the files to be prepended with date and time +# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file +# for all available tokens +# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s + +# sys.path path, will be prepended to sys.path if present. +# defaults to the current working directory. +prepend_sys_path = . + +# timezone to use when rendering the date within the migration file +# as well as the filename. +# If specified, requires the python>=3.9 or backports.zoneinfo library. +# Any required deps can installed by adding `alembic[tz]` to the pip requirements +# string value is passed to ZoneInfo() +# leave blank for localtime +# timezone = + +# max length of characters to apply to the "slug" field +# truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# version location specification; This defaults +# to migrations/versions. When using multiple version +# directories, initial revisions must be specified with --version-path. +# The path separator used here should be the separator specified by "version_path_separator" below. +# version_locations = %(here)s/bar:%(here)s/bat:migrations/versions + +# version path separator; As mentioned above, this is the character used to split +# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep. +# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas. +# Valid values for version_path_separator are: +# +# version_path_separator = : +# version_path_separator = ; +# version_path_separator = space +# version_path_separator = newline +version_path_separator = os # Use os.pathsep. Default configuration used for new projects. + +# set to 'true' to search source files recursively +# in each "version_locations" directory +# new in Alembic version 1.10 +# recursive_version_locations = false + +# the output encoding used when revision files +# are written from script.py.mako +# output_encoding = utf-8 + +sqlalchemy.url = driver://user:pass@localhost/dbname + + +[post_write_hooks] +# post_write_hooks defines scripts or Python functions that are run +# on newly generated revision scripts. See the documentation for further +# detail and examples + +# format using "black" - use the console_scripts runner, against the "black" entrypoint +# hooks = black +# black.type = console_scripts +# black.entrypoint = black +# black.options = -l 79 REVISION_SCRIPT_FILENAME + +# lint with attempts to fix using "ruff" - use the exec runner, execute a binary +# hooks = ruff +# ruff.type = exec +# ruff.executable = %(here)s/.venv/bin/ruff +# ruff.options = --fix REVISION_SCRIPT_FILENAME + +# Logging configuration +[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 +datefmt = %H:%M:%S diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/README b/robyn/scaffold/structured/sqlalchemy/migrations/README new file mode 100644 index 000000000..98e4f9c44 --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/migrations/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py new file mode 100644 index 000000000..784a5014d --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -0,0 +1,75 @@ +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool + +from alembic import context + +from utils.db import get_pool + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +if config.config_file_name is not None: + fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +from adaptors import models +target_metadata = models.Base.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline() -> None: + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online() -> None: + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + session = get_pool() + with session.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() diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/script.py.mako b/robyn/scaffold/structured/sqlalchemy/migrations/script.py.mako new file mode 100644 index 000000000..fbc4b07dc --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/migrations/script.py.mako @@ -0,0 +1,26 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision: str = ${repr(up_revision)} +down_revision: Union[str, None] = ${repr(down_revision)} +branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)} +depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)} + + +def upgrade() -> None: + ${upgrades if upgrades else "pass"} + + +def downgrade() -> None: + ${downgrades if downgrades else "pass"} diff --git a/robyn/scaffold/structured/sqlalchemy/utils/db.py b/robyn/scaffold/structured/sqlalchemy/utils/db.py index f98d54668..30d689886 100644 --- a/robyn/scaffold/structured/sqlalchemy/utils/db.py +++ b/robyn/scaffold/structured/sqlalchemy/utils/db.py @@ -18,4 +18,4 @@ def get_pool(): pool_recycle=settings.db_pool_recycle, echo=settings.db_pool_recycle, ) - return sessionmaker(bind=engine) + return sessionmaker(bind=engine)() From 6005967b2ea464e75e8ecf7d7bb4eed86f4b6284 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 03:18:00 +0000 Subject: [PATCH 11/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- robyn/scaffold/structured/sqlalchemy/migrations/env.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 784a5014d..cddca7c7f 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -1,7 +1,5 @@ from logging.config import fileConfig -from sqlalchemy import engine_from_config -from sqlalchemy import pool from alembic import context @@ -21,7 +19,8 @@ # from myapp import mymodel # target_metadata = mymodel.Base.metadata from adaptors import models -target_metadata = models.Base.metadata + +target_metadata = models.Base.metadata # other values from the config, defined by the needs of env.py, # can be acquired: @@ -62,9 +61,7 @@ def run_migrations_online() -> None: """ session = get_pool() with session.connect() as connection: - context.configure( - connection=connection, target_metadata=target_metadata - ) + context.configure(connection=connection, target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations() From 832bd8f3d4084aa6f12ad0384ee37d521fe98800 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Thu, 26 Sep 2024 09:01:44 +0530 Subject: [PATCH 12/63] feat: added alembic migration setup to sqlalchemy structured scaffold --- robyn/scaffold/structured/sqlalchemy/config.env | 2 +- .../scaffold/structured/sqlalchemy/migrations/env.py | 12 +++++++----- .../sqlalchemy/migrations/versions/__init__.py | 0 robyn/scaffold/structured/sqlalchemy/utils/db.py | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 robyn/scaffold/structured/sqlalchemy/migrations/versions/__init__.py diff --git a/robyn/scaffold/structured/sqlalchemy/config.env b/robyn/scaffold/structured/sqlalchemy/config.env index 97c3c275a..6057fe1cc 100644 --- a/robyn/scaffold/structured/sqlalchemy/config.env +++ b/robyn/scaffold/structured/sqlalchemy/config.env @@ -2,7 +2,7 @@ SERVICE_PORT=3000 # change the engine as per db DATABASE_URL=postgresql+psycopg2://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME} DB_POOL_SIZE=10 -DB_MAX_OVERFLOW=20 +DB_POOL_MAX_OVERFLOW=20 DB_POOL_TIMEOUT=30 DB_POOL_RECYCLE=1800 DB_POOL_ECHO=True diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index cddca7c7f..1e0277f56 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -1,5 +1,7 @@ from logging.config import fileConfig +from sqlalchemy import engine_from_config +from sqlalchemy import pool from alembic import context @@ -19,8 +21,7 @@ # from myapp import mymodel # target_metadata = mymodel.Base.metadata from adaptors import models - -target_metadata = models.Base.metadata +target_metadata = models.Base.metadata # other values from the config, defined by the needs of env.py, # can be acquired: @@ -59,9 +60,10 @@ def run_migrations_online() -> None: and associate a connection with the context. """ - session = get_pool() - with session.connect() as connection: - context.configure(connection=connection, target_metadata=target_metadata) + with get_pool() as session: + context.configure( + connection=session.connection(), target_metadata=target_metadata + ) with context.begin_transaction(): context.run_migrations() diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/versions/__init__.py b/robyn/scaffold/structured/sqlalchemy/migrations/versions/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/robyn/scaffold/structured/sqlalchemy/utils/db.py b/robyn/scaffold/structured/sqlalchemy/utils/db.py index 30d689886..1d54c4349 100644 --- a/robyn/scaffold/structured/sqlalchemy/utils/db.py +++ b/robyn/scaffold/structured/sqlalchemy/utils/db.py @@ -16,6 +16,6 @@ def get_pool(): max_overflow=settings.db_pool_max_overflow, pool_timeout=settings.db_pool_timeout, pool_recycle=settings.db_pool_recycle, - echo=settings.db_pool_recycle, + echo=settings.db_pool_echo, ) return sessionmaker(bind=engine)() From 09b9262da4303c14a61b043742f140f0135cd1bf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 03:32:11 +0000 Subject: [PATCH 13/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- robyn/scaffold/structured/sqlalchemy/migrations/env.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 1e0277f56..3268fe83c 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -1,7 +1,5 @@ from logging.config import fileConfig -from sqlalchemy import engine_from_config -from sqlalchemy import pool from alembic import context @@ -21,7 +19,8 @@ # from myapp import mymodel # target_metadata = mymodel.Base.metadata from adaptors import models -target_metadata = models.Base.metadata + +target_metadata = models.Base.metadata # other values from the config, defined by the needs of env.py, # can be acquired: @@ -61,9 +60,7 @@ def run_migrations_online() -> None: """ with get_pool() as session: - context.configure( - connection=session.connection(), target_metadata=target_metadata - ) + context.configure(connection=session.connection(), target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations() From 2a16aff0e42a7d204e6d0f310a84e2acf43c8cb6 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Thu, 26 Sep 2024 09:07:00 +0530 Subject: [PATCH 14/63] style: formatted scaffold and helper code --- robyn/helpers.py | 20 +++++++++++++++---- robyn/scaffold/simple/postgres/app.py | 4 +++- .../structured/no-db/api/handlers/sample.py | 6 ++++-- .../sqlalchemy/api/handlers/sample.py | 6 ++++-- .../structured/sqlalchemy/migrations/env.py | 4 +++- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/robyn/helpers.py b/robyn/helpers.py index 2253618d9..969140255 100644 --- a/robyn/helpers.py +++ b/robyn/helpers.py @@ -1,5 +1,9 @@ from typing import Any, Type, Tuple -from pydantic_settings import BaseSettings, EnvSettingsSource, PydanticBaseSettingsSource +from pydantic_settings import ( + BaseSettings, + EnvSettingsSource, + PydanticBaseSettingsSource, +) from pydantic import ConfigDict import importlib @@ -14,7 +18,9 @@ def discover_routes(handler_path: str = "api.handlers") -> Robyn: mux: Robyn = Robyn(__file__) package = importlib.import_module(handler_path) - for _, module_name, _ in pkgutil.iter_modules(package.__path__, package.__name__ + "."): + for _, module_name, _ in pkgutil.iter_modules( + package.__path__, package.__name__ + "." + ): module = importlib.import_module(module_name) logger.info(f"member: {module}") mux.include_router(module.router) @@ -22,8 +28,14 @@ def discover_routes(handler_path: str = "api.handlers") -> Robyn: class AcceptArrayEnvsSource(EnvSettingsSource): - def prepare_field_value(self, field_name: str, field: Any, value: Any, value_is_complex: bool) -> Any: - if isinstance(field.annotation, type) and issubclass(field.annotation, list) and isinstance(value, str): + def prepare_field_value( + self, field_name: str, field: Any, value: Any, value_is_complex: bool + ) -> Any: + if ( + isinstance(field.annotation, type) + and issubclass(field.annotation, list) + and isinstance(value, str) + ): return [x.strip() for x in value.split(",") if x] return value diff --git a/robyn/scaffold/simple/postgres/app.py b/robyn/scaffold/simple/postgres/app.py index 6a61c992f..883c1ed70 100644 --- a/robyn/scaffold/simple/postgres/app.py +++ b/robyn/scaffold/simple/postgres/app.py @@ -7,7 +7,9 @@ DB_PASS = "password" DB_PORT = "5455" -conn = psycopg2.connect(database=DB_NAME, host=DB_HOST, user=DB_USER, password=DB_PASS, port=DB_PORT) +conn = psycopg2.connect( + database=DB_NAME, host=DB_HOST, user=DB_USER, password=DB_PASS, port=DB_PORT +) app = Robyn(__file__) diff --git a/robyn/scaffold/structured/no-db/api/handlers/sample.py b/robyn/scaffold/structured/no-db/api/handlers/sample.py index 4df2278ca..ecc7f27a4 100644 --- a/robyn/scaffold/structured/no-db/api/handlers/sample.py +++ b/robyn/scaffold/structured/no-db/api/handlers/sample.py @@ -6,8 +6,10 @@ class SampleHandlers: @router.post("/one") @staticmethod - def one(): ... + def one(): + ... @router.get("/two") @staticmethod - def two(): ... + def two(): + ... diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index 4df2278ca..ecc7f27a4 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -6,8 +6,10 @@ class SampleHandlers: @router.post("/one") @staticmethod - def one(): ... + def one(): + ... @router.get("/two") @staticmethod - def two(): ... + def two(): + ... diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 3268fe83c..46cc2397c 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -60,7 +60,9 @@ def run_migrations_online() -> None: """ with get_pool() as session: - context.configure(connection=session.connection(), target_metadata=target_metadata) + context.configure( + connection=session.connection(), target_metadata=target_metadata + ) with context.begin_transaction(): context.run_migrations() From a4b49b1b458ebb64822a55238e98bdf2c1054866 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 03:37:09 +0000 Subject: [PATCH 15/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- robyn/helpers.py | 14 +++----------- robyn/scaffold/simple/postgres/app.py | 4 +--- .../structured/no-db/api/handlers/sample.py | 6 ++---- .../structured/sqlalchemy/api/handlers/sample.py | 6 ++---- .../structured/sqlalchemy/migrations/env.py | 4 +--- 5 files changed, 9 insertions(+), 25 deletions(-) diff --git a/robyn/helpers.py b/robyn/helpers.py index 969140255..ebcc6adb5 100644 --- a/robyn/helpers.py +++ b/robyn/helpers.py @@ -18,9 +18,7 @@ def discover_routes(handler_path: str = "api.handlers") -> Robyn: mux: Robyn = Robyn(__file__) package = importlib.import_module(handler_path) - for _, module_name, _ in pkgutil.iter_modules( - package.__path__, package.__name__ + "." - ): + for _, module_name, _ in pkgutil.iter_modules(package.__path__, package.__name__ + "."): module = importlib.import_module(module_name) logger.info(f"member: {module}") mux.include_router(module.router) @@ -28,14 +26,8 @@ def discover_routes(handler_path: str = "api.handlers") -> Robyn: class AcceptArrayEnvsSource(EnvSettingsSource): - def prepare_field_value( - self, field_name: str, field: Any, value: Any, value_is_complex: bool - ) -> Any: - if ( - isinstance(field.annotation, type) - and issubclass(field.annotation, list) - and isinstance(value, str) - ): + def prepare_field_value(self, field_name: str, field: Any, value: Any, value_is_complex: bool) -> Any: + if isinstance(field.annotation, type) and issubclass(field.annotation, list) and isinstance(value, str): return [x.strip() for x in value.split(",") if x] return value diff --git a/robyn/scaffold/simple/postgres/app.py b/robyn/scaffold/simple/postgres/app.py index 883c1ed70..6a61c992f 100644 --- a/robyn/scaffold/simple/postgres/app.py +++ b/robyn/scaffold/simple/postgres/app.py @@ -7,9 +7,7 @@ DB_PASS = "password" DB_PORT = "5455" -conn = psycopg2.connect( - database=DB_NAME, host=DB_HOST, user=DB_USER, password=DB_PASS, port=DB_PORT -) +conn = psycopg2.connect(database=DB_NAME, host=DB_HOST, user=DB_USER, password=DB_PASS, port=DB_PORT) app = Robyn(__file__) diff --git a/robyn/scaffold/structured/no-db/api/handlers/sample.py b/robyn/scaffold/structured/no-db/api/handlers/sample.py index ecc7f27a4..4df2278ca 100644 --- a/robyn/scaffold/structured/no-db/api/handlers/sample.py +++ b/robyn/scaffold/structured/no-db/api/handlers/sample.py @@ -6,10 +6,8 @@ class SampleHandlers: @router.post("/one") @staticmethod - def one(): - ... + def one(): ... @router.get("/two") @staticmethod - def two(): - ... + def two(): ... diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index ecc7f27a4..4df2278ca 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -6,10 +6,8 @@ class SampleHandlers: @router.post("/one") @staticmethod - def one(): - ... + def one(): ... @router.get("/two") @staticmethod - def two(): - ... + def two(): ... diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 46cc2397c..3268fe83c 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -60,9 +60,7 @@ def run_migrations_online() -> None: """ with get_pool() as session: - context.configure( - connection=session.connection(), target_metadata=target_metadata - ) + context.configure(connection=session.connection(), target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations() From 25840fa419c2ca28fe4570e2e3dfc49288e0551c Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Thu, 26 Sep 2024 12:05:43 +0530 Subject: [PATCH 16/63] dep: added sqlalchemy dep to scaffolding --- robyn/scaffold/structured/sqlalchemy/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/robyn/scaffold/structured/sqlalchemy/requirements.txt b/robyn/scaffold/structured/sqlalchemy/requirements.txt index 4ec60ebb2..ff335d16c 100644 --- a/robyn/scaffold/structured/sqlalchemy/requirements.txt +++ b/robyn/scaffold/structured/sqlalchemy/requirements.txt @@ -1,3 +1,4 @@ robyn +SQLAlchemy==2.0.35 pydantic~=2.7.4 pydantic-settings~=2.2.1 From 6f2e58c150de4fefac91b104b508cb487ab9bad8 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Thu, 26 Sep 2024 12:12:04 +0530 Subject: [PATCH 17/63] dep: added alembic to req in scaffold --- robyn/scaffold/structured/sqlalchemy/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/robyn/scaffold/structured/sqlalchemy/requirements.txt b/robyn/scaffold/structured/sqlalchemy/requirements.txt index ff335d16c..e0304417f 100644 --- a/robyn/scaffold/structured/sqlalchemy/requirements.txt +++ b/robyn/scaffold/structured/sqlalchemy/requirements.txt @@ -1,4 +1,5 @@ robyn -SQLAlchemy==2.0.35 +SQLAlchemy~=2.0.35 +alembic~=1.13.3 pydantic~=2.7.4 pydantic-settings~=2.2.1 From 4922b1a0e9d1b6ef56158429d80bcecba4e9aa44 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Thu, 26 Sep 2024 12:13:11 +0530 Subject: [PATCH 18/63] dep: added psycopg2 binary to dep in scaffolding --- robyn/scaffold/structured/sqlalchemy/requirements.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/robyn/scaffold/structured/sqlalchemy/requirements.txt b/robyn/scaffold/structured/sqlalchemy/requirements.txt index e0304417f..b2555c374 100644 --- a/robyn/scaffold/structured/sqlalchemy/requirements.txt +++ b/robyn/scaffold/structured/sqlalchemy/requirements.txt @@ -1,5 +1,8 @@ robyn +#DB SQLAlchemy~=2.0.35 alembic~=1.13.3 +psycopg2-binary~=2.9.9 +#schema pydantic~=2.7.4 pydantic-settings~=2.2.1 From f2ae1f7707ebabcd6c277b14f1f658197eb3f575 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Thu, 26 Sep 2024 12:51:55 +0530 Subject: [PATCH 19/63] chore: updated sqlalchemy scaffold structure --- robyn/scaffold/simple/sqlalchemy/models.py | 2 -- .../sqlalchemy/adaptors/models/__init__.py | 5 +++++ .../adaptors/{models.py => models/user.py} | 21 ++++++++++++++++++- .../structured/sqlalchemy/adaptors/schema.py | 20 ------------------ .../structured/sqlalchemy/migrations/env.py | 3 +-- 5 files changed, 26 insertions(+), 25 deletions(-) create mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/models/__init__.py rename robyn/scaffold/structured/sqlalchemy/adaptors/{models.py => models/user.py} (62%) delete mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/schema.py diff --git a/robyn/scaffold/simple/sqlalchemy/models.py b/robyn/scaffold/simple/sqlalchemy/models.py index ce1373cbb..a9aea7298 100644 --- a/robyn/scaffold/simple/sqlalchemy/models.py +++ b/robyn/scaffold/simple/sqlalchemy/models.py @@ -17,5 +17,3 @@ class User(Base): is_superuser = Column(Boolean, default=False) -if __name__ == "__main__": - Base.metadata.create_all(bind=engine) diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/models/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/models/__init__.py new file mode 100644 index 000000000..290c261b7 --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/models/__init__.py @@ -0,0 +1,5 @@ +from user import Base as user + +metadata = [ + user.metadata +] diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/models.py b/robyn/scaffold/structured/sqlalchemy/adaptors/models/user.py similarity index 62% rename from robyn/scaffold/structured/sqlalchemy/adaptors/models.py rename to robyn/scaffold/structured/sqlalchemy/adaptors/models/user.py index 5b4864fd9..47b49f292 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/models.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/models/user.py @@ -1,6 +1,6 @@ from sqlalchemy import String, Integer, Boolean from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column - +from pydantic import BaseModel class Base(DeclarativeBase): pass @@ -14,3 +14,22 @@ class User(Base): hashed_password: Mapped[str] = mapped_column(String) is_active: Mapped[bool] = mapped_column(Boolean, default=True) is_superuser: Mapped[bool] = mapped_column(Boolean, default=False) + + +class UserRead(BaseModel): + id: int + username: str + is_active: bool + is_superuser: bool + + class Config: + orm_mode = True + + +# Pydantic model for creating/updating a user +class UserCreate(BaseModel): + username: str + password: str + + class Config: + orm_mode = True diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/schema.py b/robyn/scaffold/structured/sqlalchemy/adaptors/schema.py deleted file mode 100644 index 698e83f00..000000000 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/schema.py +++ /dev/null @@ -1,20 +0,0 @@ -from pydantic import BaseModel - - -class UserRead(BaseModel): - id: int - username: str - is_active: bool - is_superuser: bool - - class Config: - orm_mode = True - - -# Pydantic model for creating/updating a user -class UserCreate(BaseModel): - username: str - password: str - - class Config: - orm_mode = True diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 3268fe83c..37fba2e18 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -20,8 +20,7 @@ # target_metadata = mymodel.Base.metadata from adaptors import models -target_metadata = models.Base.metadata - +target_metadata = models.metadata # other values from the config, defined by the needs of env.py, # can be acquired: # my_important_option = config.get_main_option("my_important_option") From c964335a58486c73fb9549c8c3684426ff3c2076 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 07:22:46 +0000 Subject: [PATCH 20/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- robyn/scaffold/simple/sqlalchemy/models.py | 2 -- .../structured/sqlalchemy/adaptors/models/__init__.py | 4 +--- robyn/scaffold/structured/sqlalchemy/adaptors/models/user.py | 1 + robyn/scaffold/structured/sqlalchemy/migrations/env.py | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/robyn/scaffold/simple/sqlalchemy/models.py b/robyn/scaffold/simple/sqlalchemy/models.py index a9aea7298..5cfef182b 100644 --- a/robyn/scaffold/simple/sqlalchemy/models.py +++ b/robyn/scaffold/simple/sqlalchemy/models.py @@ -15,5 +15,3 @@ class User(Base): hashed_password = Column(String) is_active = Column(Boolean, default=True) is_superuser = Column(Boolean, default=False) - - diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/models/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/models/__init__.py index 290c261b7..7b891fb29 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/models/__init__.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/models/__init__.py @@ -1,5 +1,3 @@ from user import Base as user -metadata = [ - user.metadata -] +metadata = [user.metadata] diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/models/user.py b/robyn/scaffold/structured/sqlalchemy/adaptors/models/user.py index 47b49f292..88ae1f390 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/models/user.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/models/user.py @@ -2,6 +2,7 @@ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from pydantic import BaseModel + class Base(DeclarativeBase): pass diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 37fba2e18..932ac0d83 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -20,7 +20,7 @@ # target_metadata = mymodel.Base.metadata from adaptors import models -target_metadata = models.metadata +target_metadata = models.metadata # other values from the config, defined by the needs of env.py, # can be acquired: # my_important_option = config.get_main_option("my_important_option") From 4391a39e36a3761f822f1790f2eccce168eb605b Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Thu, 26 Sep 2024 12:55:18 +0530 Subject: [PATCH 21/63] fix: updated import in models init in sqlalchemy scaffold --- .../scaffold/structured/sqlalchemy/adaptors/models/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/models/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/models/__init__.py index 7b891fb29..11a6a00d9 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/models/__init__.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/models/__init__.py @@ -1,3 +1,3 @@ -from user import Base as user +from .user import Base as user metadata = [user.metadata] From 9d66596ba8a1b127f54661f9fd498534087475d3 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Thu, 26 Sep 2024 13:25:55 +0530 Subject: [PATCH 22/63] chore: reverted accidental change to simple sqlalchemy scaffold --- robyn/scaffold/simple/sqlalchemy/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/robyn/scaffold/simple/sqlalchemy/models.py b/robyn/scaffold/simple/sqlalchemy/models.py index 5cfef182b..ce1373cbb 100644 --- a/robyn/scaffold/simple/sqlalchemy/models.py +++ b/robyn/scaffold/simple/sqlalchemy/models.py @@ -15,3 +15,7 @@ class User(Base): hashed_password = Column(String) is_active = Column(Boolean, default=True) is_superuser = Column(Boolean, default=False) + + +if __name__ == "__main__": + Base.metadata.create_all(bind=engine) From 43726fb27ac439476e5b9e7e758474b943e4b467 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Thu, 26 Sep 2024 13:31:44 +0530 Subject: [PATCH 23/63] chore: added mutator/selector abc classes to sqlalchemy structured scaffold --- .../sqlalchemy/adaptors/mutators/__init__.py | 17 +++++++++++++++++ .../sqlalchemy/adaptors/selectors/__init__.py | 16 ++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py index e69de29bb..6ba5e022e 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py @@ -0,0 +1,17 @@ +from abc import ABC, abstractmethod + +from pydantic import BaseModel + + +class Mutator(ABC): + @abstractmethod + def create(self, model: BaseModel): + ... + + @abstractmethod + def update(self, **kwargs): + ... + + @abstractmethod + def delete(self, **kwargs): + ... diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py index e69de29bb..dcbd8c41b 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py @@ -0,0 +1,16 @@ +from abc import ABC, abstractmethod + +from pydantic import BaseModel + + +class Mutator(ABC): + @abstractmethod + def retrieve(self, **kwargs): + ... + + @abstractmethod + def list(self, **kwargs): + ... + + + From 9159a716ae2f647b1de32834ad85c69c3727742a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:01:54 +0000 Subject: [PATCH 24/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../structured/sqlalchemy/adaptors/mutators/__init__.py | 9 +++------ .../structured/sqlalchemy/adaptors/selectors/__init__.py | 9 ++------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py index 6ba5e022e..558aa5e9c 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/mutators/__init__.py @@ -5,13 +5,10 @@ class Mutator(ABC): @abstractmethod - def create(self, model: BaseModel): - ... + def create(self, model: BaseModel): ... @abstractmethod - def update(self, **kwargs): - ... + def update(self, **kwargs): ... @abstractmethod - def delete(self, **kwargs): - ... + def delete(self, **kwargs): ... diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py index dcbd8c41b..e5d518c12 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py @@ -5,12 +5,7 @@ class Mutator(ABC): @abstractmethod - def retrieve(self, **kwargs): - ... + def retrieve(self, **kwargs): ... @abstractmethod - def list(self, **kwargs): - ... - - - + def list(self, **kwargs): ... From b5895dd8ffd6f8d63c7bf13d8c5c34260c6020c9 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Sat, 28 Sep 2024 09:13:59 +0530 Subject: [PATCH 25/63] chore: updated test for create_app, added additional test --- integration_tests/test_cli.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/integration_tests/test_cli.py b/integration_tests/test_cli.py index 2ee94204b..804f2e439 100644 --- a/integration_tests/test_cli.py +++ b/integration_tests/test_cli.py @@ -4,11 +4,12 @@ # Unit tests -def test_create_robyn_app(): +def test_create_robyn_app_simple(): with patch("robyn.cli.prompt") as mock_prompt: mock_prompt.return_value = { "directory": "test_dir", "docker": "N", + "scaffold_type": "simple", "project_type": "no-db", } with patch("robyn.cli.os.makedirs") as mock_makedirs: @@ -17,6 +18,21 @@ def test_create_robyn_app(): mock_makedirs.assert_called_once() mock_copytree.assert_called_once() +def test_create_robyn_app_structured(): + with patch("robyn.cli.prompt") as mock_prompt: + mock_prompt.return_value = { + "directory": "test_dir", + "docker": "N", + "scaffold_type": "structured", + "project_type": "no-db", + } + with patch("robyn.cli.os.makedirs") as mock_makedirs: + with patch("robyn.cli.shutil.copytree") as mock_copytree, patch("robyn.os.remove") as _mock_remove: + create_robyn_app() + mock_makedirs.assert_called_once() + mock_copytree.assert_called_once() + + def test_docs(): with patch("robyn.cli.webbrowser.open") as mock_open: From f155900bc750b27bd9ecb704963d26d03127188e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 03:44:13 +0000 Subject: [PATCH 26/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- integration_tests/test_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration_tests/test_cli.py b/integration_tests/test_cli.py index 804f2e439..7c369d5ee 100644 --- a/integration_tests/test_cli.py +++ b/integration_tests/test_cli.py @@ -18,6 +18,7 @@ def test_create_robyn_app_simple(): mock_makedirs.assert_called_once() mock_copytree.assert_called_once() + def test_create_robyn_app_structured(): with patch("robyn.cli.prompt") as mock_prompt: mock_prompt.return_value = { @@ -33,7 +34,6 @@ def test_create_robyn_app_structured(): mock_copytree.assert_called_once() - def test_docs(): with patch("robyn.cli.webbrowser.open") as mock_open: docs() From 182f9cf2b9e5e924553a6d2ce30ba3cdba5c3ecb Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Sat, 28 Sep 2024 10:25:07 +0530 Subject: [PATCH 27/63] chore: ignoring errors in case of docker N, if devops directory doesn't exist --- robyn/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/robyn/cli.py b/robyn/cli.py index 15b6ae09e..f8be0f90d 100644 --- a/robyn/cli.py +++ b/robyn/cli.py @@ -99,7 +99,7 @@ def create_robyn_app(): if scaffold_type == "simple": os.remove(f"{final_project_dir_path}/Dockerfile") else: - shutil.rmtree(f"{final_project_dir_path}/devops") + shutil.rmtree(f"{final_project_dir_path}/devops", ignore_errors=True) print(f"New Robyn project created in '{final_project_dir_path}' ") From 054570b2cd73395af98c9076632305b705fbca0c Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Sat, 28 Sep 2024 10:29:20 +0530 Subject: [PATCH 28/63] chore: udpated ruff suggestions --- .../structured/sqlalchemy/adaptors/selectors/__init__.py | 2 -- robyn/scaffold/structured/sqlalchemy/migrations/env.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py index e5d518c12..8cc4c497e 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/__init__.py @@ -1,7 +1,5 @@ from abc import ABC, abstractmethod -from pydantic import BaseModel - class Mutator(ABC): @abstractmethod diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 932ac0d83..03303208c 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -2,6 +2,7 @@ from alembic import context +from adaptors import models from utils.db import get_pool @@ -18,7 +19,6 @@ # for 'autogenerate' support # from myapp import mymodel # target_metadata = mymodel.Base.metadata -from adaptors import models target_metadata = models.metadata # other values from the config, defined by the needs of env.py, From 155acd7dde68c5e4e8328449f3cc35d4f2e1de9c Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Tue, 1 Oct 2024 15:22:58 +0530 Subject: [PATCH 29/63] fix: updated subrouter initializations in scaffold --- robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py | 6 +++--- robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py index 43a6ee6dd..d232352f8 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py @@ -1,14 +1,14 @@ from robyn import SubRouter -router = SubRouter("/") +router = SubRouter(__name__, prefix="/") -@router.get("/livez/") +@router.get("livez/") def livez() -> str: return "live" -@router.get("/healthz/") +@router.get("healthz/") def healthz() -> str: return "healthy" diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index 4df2278ca..a15fc54cd 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -1,13 +1,13 @@ from robyn import SubRouter -router = SubRouter("/sample") +router = SubRouter(__name__, prefix="/sample/") class SampleHandlers: - @router.post("/one") + @router.post("one/") @staticmethod def one(): ... - @router.get("/two") + @router.get("two/") @staticmethod def two(): ... From d2ddba88fbeac1f2dccfafdf54f8d53c515d5934 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Tue, 1 Oct 2024 15:23:38 +0530 Subject: [PATCH 30/63] chore: upadated scaffold --- robyn/scaffold/structured/no-db/api/handlers/probes.py | 2 +- robyn/scaffold/structured/no-db/api/handlers/sample.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/robyn/scaffold/structured/no-db/api/handlers/probes.py b/robyn/scaffold/structured/no-db/api/handlers/probes.py index 43a6ee6dd..b0cbc6583 100644 --- a/robyn/scaffold/structured/no-db/api/handlers/probes.py +++ b/robyn/scaffold/structured/no-db/api/handlers/probes.py @@ -1,7 +1,7 @@ from robyn import SubRouter -router = SubRouter("/") +router = SubRouter(__name__, prefix="/") @router.get("/livez/") diff --git a/robyn/scaffold/structured/no-db/api/handlers/sample.py b/robyn/scaffold/structured/no-db/api/handlers/sample.py index 4df2278ca..8130ae303 100644 --- a/robyn/scaffold/structured/no-db/api/handlers/sample.py +++ b/robyn/scaffold/structured/no-db/api/handlers/sample.py @@ -1,6 +1,6 @@ from robyn import SubRouter -router = SubRouter("/sample") +router = SubRouter(__name__, "/sample") class SampleHandlers: From d282b36e14a035a0bdb832de84d70de9bc5e491b Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Tue, 1 Oct 2024 22:22:58 +0530 Subject: [PATCH 31/63] chore: updated handler to include pool from a global dependency --- robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py | 5 ++++- robyn/scaffold/structured/sqlalchemy/server.py | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index a15fc54cd..4d246648b 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -6,7 +6,10 @@ class SampleHandlers: @router.post("one/") @staticmethod - def one(): ... + def one(): + with global_dependencies.get("pool") as session: + # invoke your mutators/selectors here + ... @router.get("two/") @staticmethod diff --git a/robyn/scaffold/structured/sqlalchemy/server.py b/robyn/scaffold/structured/sqlalchemy/server.py index 057eed07e..8a3b402ac 100644 --- a/robyn/scaffold/structured/sqlalchemy/server.py +++ b/robyn/scaffold/structured/sqlalchemy/server.py @@ -1,11 +1,14 @@ from robyn.helpers import discover_routes from robyn import Robyn +from utils.db import get_pool from conf import settings app: Robyn = discover_routes("api.handlers") # note: if you prefer to manuall refine routes, use your build_routes function instead +app.inject_global(pool=get_pool()) + if __name__ == "__main__": app.start(host="0.0.0.0", port=settings.service_port) From 9d7fcf03034ae38ef65024b78d269ce4ac4a845b Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Tue, 1 Oct 2024 22:23:30 +0530 Subject: [PATCH 32/63] chore: added missing arg --- robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index 4d246648b..06e9c557a 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -6,7 +6,7 @@ class SampleHandlers: @router.post("one/") @staticmethod - def one(): + def one(global_dependencies): with global_dependencies.get("pool") as session: # invoke your mutators/selectors here ... From 8a3c2ab81cadfeeccd414ea725767382de4ee472 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:54:57 +0000 Subject: [PATCH 33/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index 06e9c557a..e2e504da8 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -6,7 +6,7 @@ class SampleHandlers: @router.post("one/") @staticmethod - def one(global_dependencies): + def one(global_dependencies): with global_dependencies.get("pool") as session: # invoke your mutators/selectors here ... From 8ce075300c0a2a986063694cd76a702f62ce3f60 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 2 Oct 2024 08:13:08 +0530 Subject: [PATCH 34/63] style: ruff formatting on structured directory --- robyn/scaffold/structured/sqlalchemy/migrations/env.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 03303208c..bb2191d4b 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -59,7 +59,9 @@ def run_migrations_online() -> None: """ with get_pool() as session: - context.configure(connection=session.connection(), target_metadata=target_metadata) + context.configure( + connection=session.connection(), target_metadata=target_metadata + ) with context.begin_transaction(): context.run_migrations() From 0a9cbb6e47d97ce6437716a69a898530de64ea7e Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 2 Oct 2024 08:21:16 +0530 Subject: [PATCH 35/63] chore: added sample selector and used "session" in sample handler in scaffold (for ruff xP) --- .../scaffold/structured/sqlalchemy/adaptors/selectors/misc.py | 4 ++++ robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 robyn/scaffold/structured/sqlalchemy/adaptors/selectors/misc.py diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/misc.py b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/misc.py new file mode 100644 index 000000000..6ba860be8 --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/misc.py @@ -0,0 +1,4 @@ +from sqlalchemy import text + +def sample_selector(session): + session.execute(text("select * from sample;")) diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index e2e504da8..90cd097cc 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -1,4 +1,5 @@ from robyn import SubRouter +from adaptors.selectors.misc import sample_selector router = SubRouter(__name__, prefix="/sample/") @@ -9,7 +10,7 @@ class SampleHandlers: def one(global_dependencies): with global_dependencies.get("pool") as session: # invoke your mutators/selectors here - ... + sample_selector(session) @router.get("two/") @staticmethod From 42c61fcfb375c94572922e9c32619090fd1ca27d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 02:51:33 +0000 Subject: [PATCH 36/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../scaffold/structured/sqlalchemy/adaptors/selectors/misc.py | 1 + robyn/scaffold/structured/sqlalchemy/migrations/env.py | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/misc.py b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/misc.py index 6ba860be8..f33beb4c0 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/misc.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/misc.py @@ -1,4 +1,5 @@ from sqlalchemy import text + def sample_selector(session): session.execute(text("select * from sample;")) diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index bb2191d4b..03303208c 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -59,9 +59,7 @@ def run_migrations_online() -> None: """ with get_pool() as session: - context.configure( - connection=session.connection(), target_metadata=target_metadata - ) + context.configure(connection=session.connection(), target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations() From ffe6629d84b66f20d5d818764d461ef977692a64 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Sat, 5 Oct 2024 09:18:52 +0530 Subject: [PATCH 37/63] feat: switched to sqlalchemy async --- .../sqlalchemy/adaptors/selectors/misc.py | 4 +-- .../sqlalchemy/api/handlers/sample.py | 8 +++--- .../structured/sqlalchemy/utils/db.py | 25 ++++++++++--------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/misc.py b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/misc.py index f33beb4c0..d45e51aa2 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/misc.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/selectors/misc.py @@ -1,5 +1,5 @@ from sqlalchemy import text -def sample_selector(session): - session.execute(text("select * from sample;")) +async def sample_selector(conn): + await conn.execute(text("select * from sample;")) diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index 90cd097cc..af16bfc83 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -1,5 +1,6 @@ from robyn import SubRouter from adaptors.selectors.misc import sample_selector +from utils.db import get_db_connection router = SubRouter(__name__, prefix="/sample/") @@ -7,10 +8,11 @@ class SampleHandlers: @router.post("one/") @staticmethod - def one(global_dependencies): - with global_dependencies.get("pool") as session: + async def one(global_dependencies): + pool = global_dependencies.get("pool") + async with get_db_connection(pool) as conn: # invoke your mutators/selectors here - sample_selector(session) + await sample_selector(conn) @router.get("two/") @staticmethod diff --git a/robyn/scaffold/structured/sqlalchemy/utils/db.py b/robyn/scaffold/structured/sqlalchemy/utils/db.py index 1d54c4349..bedbb2c28 100644 --- a/robyn/scaffold/structured/sqlalchemy/utils/db.py +++ b/robyn/scaffold/structured/sqlalchemy/utils/db.py @@ -1,21 +1,22 @@ -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker -from conf import settings - -import logging - -logger = logging.getLogger(__name__) +from contextlib import asynccontextmanager +from sqlalchemy.ext.asyncio import create_async_engine +from conf import settings def get_pool(): - dsn = settings.database_url - logger.info(f"creating client db pool with dsn: {dsn}") - engine = create_engine( - dsn, + return create_async_engine( + settings.database_url, pool_size=settings.db_pool_size, max_overflow=settings.db_pool_max_overflow, pool_timeout=settings.db_pool_timeout, pool_recycle=settings.db_pool_recycle, echo=settings.db_pool_echo, + query_cache_size=0, ) - return sessionmaker(bind=engine)() + +@asynccontextmanager +async def get_db_connection(engine): + async with engine.connect() as conn: + yield conn + + From 138e530260e0e74112ecb13df633214db781d8ec Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Sat, 5 Oct 2024 09:31:07 +0530 Subject: [PATCH 38/63] fix: updated handler to await async selectors appropriately --- .../structured/sqlalchemy/api/handlers/sample.py | 12 ++++++++---- robyn/scaffold/structured/sqlalchemy/config.env | 2 +- .../scaffold/structured/sqlalchemy/requirements.txt | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index af16bfc83..3926edef1 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -6,14 +6,18 @@ class SampleHandlers: - @router.post("one/") + @staticmethod + @router.post("one/") async def one(global_dependencies): pool = global_dependencies.get("pool") async with get_db_connection(pool) as conn: # invoke your mutators/selectors here - await sample_selector(conn) + res = await sample_selector(conn) + print(res) + return {} - @router.get("two/") @staticmethod - def two(): ... + @router.get("two/") + def two(): + return {} diff --git a/robyn/scaffold/structured/sqlalchemy/config.env b/robyn/scaffold/structured/sqlalchemy/config.env index 6057fe1cc..469ae898c 100644 --- a/robyn/scaffold/structured/sqlalchemy/config.env +++ b/robyn/scaffold/structured/sqlalchemy/config.env @@ -1,6 +1,6 @@ SERVICE_PORT=3000 # change the engine as per db -DATABASE_URL=postgresql+psycopg2://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME} +DATABASE_URL=postgresql+asyncpg://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME} DB_POOL_SIZE=10 DB_POOL_MAX_OVERFLOW=20 DB_POOL_TIMEOUT=30 diff --git a/robyn/scaffold/structured/sqlalchemy/requirements.txt b/robyn/scaffold/structured/sqlalchemy/requirements.txt index b2555c374..4a28cedcb 100644 --- a/robyn/scaffold/structured/sqlalchemy/requirements.txt +++ b/robyn/scaffold/structured/sqlalchemy/requirements.txt @@ -2,7 +2,7 @@ robyn #DB SQLAlchemy~=2.0.35 alembic~=1.13.3 -psycopg2-binary~=2.9.9 +asyncpg==0.29.0 #schema pydantic~=2.7.4 pydantic-settings~=2.2.1 From 646b58b31229627f0ce4f823f6cee394b176e066 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 5 Oct 2024 04:01:18 +0000 Subject: [PATCH 39/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py | 1 - robyn/scaffold/structured/sqlalchemy/utils/db.py | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index 3926edef1..8fe71cf3d 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -6,7 +6,6 @@ class SampleHandlers: - @staticmethod @router.post("one/") async def one(global_dependencies): diff --git a/robyn/scaffold/structured/sqlalchemy/utils/db.py b/robyn/scaffold/structured/sqlalchemy/utils/db.py index bedbb2c28..fca8a9e6c 100644 --- a/robyn/scaffold/structured/sqlalchemy/utils/db.py +++ b/robyn/scaffold/structured/sqlalchemy/utils/db.py @@ -1,8 +1,8 @@ - from contextlib import asynccontextmanager from sqlalchemy.ext.asyncio import create_async_engine from conf import settings + def get_pool(): return create_async_engine( settings.database_url, @@ -14,9 +14,8 @@ def get_pool(): query_cache_size=0, ) + @asynccontextmanager async def get_db_connection(engine): async with engine.connect() as conn: yield conn - - From a6c6e13f907bb074b4e6810159ea184799d41537 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Tue, 8 Oct 2024 18:36:00 +0530 Subject: [PATCH 40/63] doc: updated example app docs to include scaffold type --- .../pages/documentation/example_app/index.mdx | 15 ++++- requirements.txt | 56 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 requirements.txt diff --git a/docs_src/src/pages/documentation/example_app/index.mdx b/docs_src/src/pages/documentation/example_app/index.mdx index aa23ad606..a20b05460 100644 --- a/docs_src/src/pages/documentation/example_app/index.mdx +++ b/docs_src/src/pages/documentation/example_app/index.mdx @@ -25,12 +25,25 @@ Batman wanted to create a Robyn app and was about to create an `src/app.py` befo $ python -m robyn --create ``` -This, would result in the following output. +You can choose to have a simple starter format or an opinionated scaffold ike so... + +```bash +$ python -m robyn --create +? Directory Path: myproject +? Need Docker? (Y/N) Y +? Please choose if you'd like the scaffold to be a simple starter kit or an opinionated structure + Simple +❯ Structured +``` + + +This, would result in the following output if you choose scaffold type as `simple` ```bash $ python3 -m robyn --create ? Directory Path: . ? Need Docker? (Y/N) Y +? Please choose if you'd like the scaffold to be a simple starter kit or an opinionated structure ? Please select project type (Mongo/Postgres/Sqlalchemy/Prisma): ❯ No DB Sqlite diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..924e51a7d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,56 @@ +argcomplete==2.0.6 ; python_version >= "3.8" and python_version < "4.0" +attrs==24.2.0 ; python_version >= "3.8" and python_version < "4.0" +black==23.1.0 ; python_version >= "3.8" and python_version < "4.0" +certifi==2024.8.30 ; python_version >= "3.8" and python_version < "4" +cffi==1.15.1 ; python_version >= "3.8" and python_version < "4.0" +cfgv==3.4.0 ; python_version >= "3.8" and python_version < "4.0" +charset-normalizer==2.1.1 ; python_version >= "3.8" and python_version < "4.0" +click==8.1.7 ; python_version >= "3.8" and python_version < "4.0" +colorama==0.4.6 ; python_version >= "3.8" and python_version < "4.0" +colorlog==6.8.2 ; python_version >= "3.8" and python_version < "4.0" +commitizen==2.40.0 ; python_version >= "3.8" and python_version < "4.0" +decli==0.5.2 ; python_version >= "3.8" and python_version < "4.0" +dill==0.3.8 ; python_version >= "3.8" and python_version < "4.0" +distlib==0.3.8 ; python_version >= "3.8" and python_version < "4.0" +exceptiongroup==1.2.2 ; python_version >= "3.8" and python_version < "3.11" +filelock==3.16.1 ; python_version >= "3.8" and python_version < "4.0" +identify==2.6.1 ; python_version >= "3.8" and python_version < "4.0" +idna==3.10 ; python_version >= "3.8" and python_version < "4" +iniconfig==2.0.0 ; python_version >= "3.8" and python_version < "4.0" +inquirerpy==0.3.4 ; python_version >= "3.8" and python_version < "4.0" +isort==5.11.5 ; python_version >= "3.8" and python_version < "4.0" +jinja2==3.0.1 ; python_version >= "3.8" and python_version < "4.0" +markupsafe==2.1.5 ; python_version >= "3.8" and python_version < "4.0" +maturin==0.14.12 ; python_version >= "3.8" and python_version < "4.0" +multiprocess==0.70.14 ; python_version >= "3.8" and python_version < "4.0" +mypy-extensions==1.0.0 ; python_version >= "3.8" and python_version < "4.0" +nestd==0.3.1 ; python_version >= "3.8" and python_version < "4.0" +nodeenv==1.9.1 ; python_version >= "3.8" and python_version < "4.0" +nox==2023.4.22 ; python_version >= "3.8" and python_version < "4.0" +orjson==3.10.7 ; python_version >= "3.8" and python_version < "4.0" +packaging==24.1 ; python_version >= "3.8" and python_version < "4.0" +pathspec==0.12.1 ; python_version >= "3.8" and python_version < "4.0" +pfzy==0.3.4 ; python_version >= "3.8" and python_version < "4.0" +platformdirs==4.3.6 ; python_version >= "3.8" and python_version < "4.0" +pluggy==1.5.0 ; python_version >= "3.8" and python_version < "4.0" +pre-commit==2.21.0 ; python_version >= "3.8" and python_version < "4.0" +prompt-toolkit==3.0.48 ; python_version >= "3.8" and python_version < "4.0" +pycparser==2.22 ; python_version >= "3.8" and python_version < "4.0" +pytest-codspeed==1.2.2 ; python_version >= "3.8" and python_version < "4.0" +pytest==7.2.1 ; python_version >= "3.8" and python_version < "4.0" +pyyaml==6.0.2 ; python_version >= "3.8" and python_version < "4.0" +questionary==1.10.0 ; python_version >= "3.8" and python_version < "4.0" +requests==2.28.2 ; python_version >= "3.8" and python_version < "4" +ruff==0.1.3 ; python_version >= "3.8" and python_version < "4.0" +rustimport==1.5.0 ; python_version >= "3.8" and python_version < "4.0" +termcolor==2.4.0 ; python_version >= "3.8" and python_version < "4.0" +toml==0.10.2 ; python_version >= "3.8" and python_version < "4.0" +tomli==2.0.1 ; python_version >= "3.8" and python_version < "3.11" +tomlkit==0.13.2 ; python_version >= "3.8" and python_version < "4.0" +typing-extensions==4.12.2 ; python_version >= "3.8" and python_version < "4.0" +urllib3==1.26.20 ; python_version >= "3.8" and python_version < "4" +uvloop==0.19.0 ; sys_platform != "win32" and sys_platform != "cygwin" and platform_python_implementation != "PyPy" and python_version >= "3.8" and python_version < "4.0" +virtualenv==20.26.6 ; python_version >= "3.8" and python_version < "4.0" +watchdog==4.0.1 ; python_version >= "3.8" and python_version < "4.0" +wcwidth==0.2.13 ; python_version >= "3.8" and python_version < "4.0" +websocket-client==1.5.0 ; python_version >= "3.8" and python_version < "4.0" From 4eeab6d78bfb9d75d71bfd643fa1d50b1f00c227 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Tue, 8 Oct 2024 20:16:33 +0530 Subject: [PATCH 41/63] doc: updated getting started docs as per structured scaffold --- .../pages/documentation/example_app/index.mdx | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/docs_src/src/pages/documentation/example_app/index.mdx b/docs_src/src/pages/documentation/example_app/index.mdx index a20b05460..3005cf8cd 100644 --- a/docs_src/src/pages/documentation/example_app/index.mdx +++ b/docs_src/src/pages/documentation/example_app/index.mdx @@ -78,3 +78,85 @@ And he was done! The Robyn CLI created a new application with the following stru /> +If you choose to go with the structured scaffold, this is how your project will look like + +> note: at the moment, only no-db and sqlalchemy are supported here, you can always plug in other integrations as you see fit + +```bash +├── adaptors +│   ├── __init__.py +│   ├── models +│   │   ├── __init__.py +│   │   └── user.py +│   ├── mutators +│   │   └── __init__.py +│   └── selectors +│   ├── __init__.py +│   └── misc.py +├── alembic.ini +├── api +│   ├── handlers +│   │   ├── __init__.py +│   │   ├── probes.py +│   │   └── sample.py +│   └── middlewares +│   └── __init__.py +├── conf.py +├── config.env +├── devops +│   ├── Dockerfile +│   ├── Dockerfile.src +│   └── docker-compose.yaml +├── migrations +│   ├── README +│   ├── env.py +│   ├── script.py.mako +│   └── versions +│   └── __init__.py +├── requirements.txt +├── server.py +└── utils + ├── __init__.py + └── db.py + +12 directories, 24 files +``` + +Here's what each of these stand for + +- server.py + +This is where you instantiate your robyn server and inject global dependencies + +```python +from robyn.helpers import discover_routes +from robyn import Robyn + +from utils.db import get_pool +from conf import settings + +app: Robyn = discover_routes("api.handlers") +# note: if you prefer to manuall refine routes, use your build_routes function instead + +app.inject_global(pool=get_pool()) + + +if __name__ == "__main__": + app.start(host="0.0.0.0", port=settings.service_port) +``` + +- conf.py/config.env + +Comes with initial settings you need to work with the database. The `BaseConfig` class slight enhancement on pydantic-settings's `BaseSettings` class + +- Your endpoint and middleware handlers live under the api package + +- It also comes pre-configured with alembic for database migrations + +- The database mutations and queries will be living under the adataptors package where you would do the following + - define your sqlalchemy and pydantic models + - define selectors for reusable query functions + - define mutators for any mutations over the model along with related functionality, usually in a transaction block + +> note: by default, we include sqlalchemy async pool, you can always change it as per your requirements + From 72b66f03befc768150b492aebfef1161ab8ad923 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Tue, 8 Oct 2024 20:19:29 +0530 Subject: [PATCH 42/63] doc: added note about endpoints in class as static methos --- docs_src/src/pages/documentation/example_app/index.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs_src/src/pages/documentation/example_app/index.mdx b/docs_src/src/pages/documentation/example_app/index.mdx index 3005cf8cd..b67a8d61b 100644 --- a/docs_src/src/pages/documentation/example_app/index.mdx +++ b/docs_src/src/pages/documentation/example_app/index.mdx @@ -149,7 +149,8 @@ if __name__ == "__main__": Comes with initial settings you need to work with the database. The `BaseConfig` class slight enhancement on pydantic-settings's `BaseSettings` class -- Your endpoint and middleware handlers live under the api package +- Your endpoint and middleware handlers live under the api package. +> note: the example where the handlers are in a class as static methods is completely up to the developer preference and doesn't impact the actual routing in any way - It also comes pre-configured with alembic for database migrations From af42e44a2c39b7a13f9c1214c02b8f2c1d446f6f Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Tue, 8 Oct 2024 20:21:58 +0530 Subject: [PATCH 43/63] chore: added example handler outside class --- robyn/scaffold/structured/no-db/api/handlers/sample.py | 8 ++++++++ .../scaffold/structured/sqlalchemy/api/handlers/sample.py | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/robyn/scaffold/structured/no-db/api/handlers/sample.py b/robyn/scaffold/structured/no-db/api/handlers/sample.py index 8130ae303..af40c3e8e 100644 --- a/robyn/scaffold/structured/no-db/api/handlers/sample.py +++ b/robyn/scaffold/structured/no-db/api/handlers/sample.py @@ -4,6 +4,9 @@ class SampleHandlers: + """ + note: the handles being grouped in a class like this is complete optional, and doesn't have any impact on routing + """ @router.post("/one") @staticmethod def one(): ... @@ -11,3 +14,8 @@ def one(): ... @router.get("/two") @staticmethod def two(): ... + + +@router.get("three/") +def three(): + return {} diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index 8fe71cf3d..ece71142e 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -6,6 +6,10 @@ class SampleHandlers: + """ + note: the handles being grouped in a class like this is complete optional, and doesn't have any impact on routing + """ + @staticmethod @router.post("one/") async def one(global_dependencies): @@ -20,3 +24,7 @@ async def one(global_dependencies): @router.get("two/") def two(): return {} + +@router.get("three/") +def three(): + return {} From da669360022bb1a46e0018deae79ccd45a8e68d9 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Tue, 8 Oct 2024 20:25:19 +0530 Subject: [PATCH 44/63] chore: added comments on what alembic is --- robyn/scaffold/structured/sqlalchemy/alembic.ini | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/robyn/scaffold/structured/sqlalchemy/alembic.ini b/robyn/scaffold/structured/sqlalchemy/alembic.ini index 18f8896c7..44f7f6428 100644 --- a/robyn/scaffold/structured/sqlalchemy/alembic.ini +++ b/robyn/scaffold/structured/sqlalchemy/alembic.ini @@ -1,3 +1,17 @@ +# Alembic helps manage database schema changes over time, offering: + +# 1. Schema Versioning: +# # Tracks different versions of the schema, allowing easy upgrades and rollbacks. + +# 2. Migration Creation & Execution: +# # Enables creation of migration scripts to define changes and applies them to the database. + +# 3. Rollback Capabilities: +# # Supports rolling back to previous schema versions in case of issues. + +# 4. SQLAlchemy Integration: +# # Works seamlessly with SQLAlchemy ORM for automatic migration generation based on model changes. + # A generic, single database configuration. [alembic] From 2a8209e6cbe21acd76714d9bf3a80df021b61509 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Tue, 8 Oct 2024 20:31:11 +0530 Subject: [PATCH 45/63] chore: re-triggering pre-commit ci --- docs_src/src/pages/documentation/example_app/index.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs_src/src/pages/documentation/example_app/index.mdx b/docs_src/src/pages/documentation/example_app/index.mdx index b67a8d61b..ec4e291c1 100644 --- a/docs_src/src/pages/documentation/example_app/index.mdx +++ b/docs_src/src/pages/documentation/example_app/index.mdx @@ -161,3 +161,4 @@ Comes with initial settings you need to work with the database. The `BaseConfig` > note: by default, we include sqlalchemy async pool, you can always change it as per your requirements + From 61bac98b4ed3b39beb70351e22dfe1a30f65038e Mon Sep 17 00:00:00 2001 From: Ashu Pednekar Date: Tue, 8 Oct 2024 20:56:32 +0530 Subject: [PATCH 46/63] doc: typo fix in scaffold docs --- docs_src/src/pages/documentation/example_app/index.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs_src/src/pages/documentation/example_app/index.mdx b/docs_src/src/pages/documentation/example_app/index.mdx index ec4e291c1..243501159 100644 --- a/docs_src/src/pages/documentation/example_app/index.mdx +++ b/docs_src/src/pages/documentation/example_app/index.mdx @@ -149,12 +149,12 @@ if __name__ == "__main__": Comes with initial settings you need to work with the database. The `BaseConfig` class slight enhancement on pydantic-settings's `BaseSettings` class -- Your endpoint and middleware handlers live under the api package. +- Your endpoint and middleware handlers live under the `api` package. > note: the example where the handlers are in a class as static methods is completely up to the developer preference and doesn't impact the actual routing in any way - It also comes pre-configured with alembic for database migrations -- The database mutations and queries will be living under the adataptors package where you would do the following +- The database mutations and queries will be living under the `adaptors` package where you would do the following - define your sqlalchemy and pydantic models - define selectors for reusable query functions - define mutators for any mutations over the model along with related functionality, usually in a transaction block From 785dc1de6e6d99b6b91256cd77e72a9576d11687 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 19:53:10 +0000 Subject: [PATCH 47/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- robyn/scaffold/structured/no-db/api/handlers/sample.py | 1 + robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py | 1 + 2 files changed, 2 insertions(+) diff --git a/robyn/scaffold/structured/no-db/api/handlers/sample.py b/robyn/scaffold/structured/no-db/api/handlers/sample.py index af40c3e8e..a1aefd5e6 100644 --- a/robyn/scaffold/structured/no-db/api/handlers/sample.py +++ b/robyn/scaffold/structured/no-db/api/handlers/sample.py @@ -7,6 +7,7 @@ class SampleHandlers: """ note: the handles being grouped in a class like this is complete optional, and doesn't have any impact on routing """ + @router.post("/one") @staticmethod def one(): ... diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index ece71142e..dd8350f2a 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -25,6 +25,7 @@ async def one(global_dependencies): def two(): return {} + @router.get("three/") def three(): return {} From 793f8828eba0be2ea16cca50ffb123c624765117 Mon Sep 17 00:00:00 2001 From: Ashu Pednekar Date: Thu, 10 Oct 2024 08:01:38 +0530 Subject: [PATCH 48/63] style: formatted scaffold directory with ruff --- robyn/scaffold/simple/postgres/app.py | 4 +++- robyn/scaffold/structured/sqlalchemy/migrations/env.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/robyn/scaffold/simple/postgres/app.py b/robyn/scaffold/simple/postgres/app.py index 8c1362335..499c0d9a8 100644 --- a/robyn/scaffold/simple/postgres/app.py +++ b/robyn/scaffold/simple/postgres/app.py @@ -8,7 +8,9 @@ DB_PASS = "password" DB_PORT = "5455" -conn = psycopg2.connect(database=DB_NAME, host=DB_HOST, user=DB_USER, password=DB_PASS, port=DB_PORT) +conn = psycopg2.connect( + database=DB_NAME, host=DB_HOST, user=DB_USER, password=DB_PASS, port=DB_PORT +) app = Robyn(__file__) diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 03303208c..bb2191d4b 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -59,7 +59,9 @@ def run_migrations_online() -> None: """ with get_pool() as session: - context.configure(connection=session.connection(), target_metadata=target_metadata) + context.configure( + connection=session.connection(), target_metadata=target_metadata + ) with context.begin_transaction(): context.run_migrations() From 7b981479359db7a6d5588803d636df1545878936 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 02:31:49 +0000 Subject: [PATCH 49/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- robyn/scaffold/simple/postgres/app.py | 4 +--- robyn/scaffold/structured/sqlalchemy/migrations/env.py | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/robyn/scaffold/simple/postgres/app.py b/robyn/scaffold/simple/postgres/app.py index 499c0d9a8..8c1362335 100644 --- a/robyn/scaffold/simple/postgres/app.py +++ b/robyn/scaffold/simple/postgres/app.py @@ -8,9 +8,7 @@ DB_PASS = "password" DB_PORT = "5455" -conn = psycopg2.connect( - database=DB_NAME, host=DB_HOST, user=DB_USER, password=DB_PASS, port=DB_PORT -) +conn = psycopg2.connect(database=DB_NAME, host=DB_HOST, user=DB_USER, password=DB_PASS, port=DB_PORT) app = Robyn(__file__) diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index bb2191d4b..03303208c 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -59,9 +59,7 @@ def run_migrations_online() -> None: """ with get_pool() as session: - context.configure( - connection=session.connection(), target_metadata=target_metadata - ) + context.configure(connection=session.connection(), target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations() From 3f014bd3f6c217eff04ad5c111e7caf5a09b4150 Mon Sep 17 00:00:00 2001 From: Ashu Pednekar Date: Thu, 10 Oct 2024 08:20:02 +0530 Subject: [PATCH 50/63] style: ran isort to sort imports --- robyn/helpers.py | 14 +++++--------- .../structured/no-db/api/handlers/probes.py | 1 - robyn/scaffold/structured/no-db/server.py | 6 +++--- .../structured/sqlalchemy/adaptors/models/user.py | 4 ++-- .../structured/sqlalchemy/api/handlers/probes.py | 1 - .../structured/sqlalchemy/api/handlers/sample.py | 3 ++- .../structured/sqlalchemy/migrations/env.py | 4 +--- robyn/scaffold/structured/sqlalchemy/server.py | 8 ++++---- robyn/scaffold/structured/sqlalchemy/utils/db.py | 3 ++- 9 files changed, 19 insertions(+), 25 deletions(-) diff --git a/robyn/helpers.py b/robyn/helpers.py index ebcc6adb5..f0459cf95 100644 --- a/robyn/helpers.py +++ b/robyn/helpers.py @@ -1,14 +1,10 @@ -from typing import Any, Type, Tuple -from pydantic_settings import ( - BaseSettings, - EnvSettingsSource, - PydanticBaseSettingsSource, -) -from pydantic import ConfigDict - import importlib -import pkgutil import logging +import pkgutil +from typing import Any, Tuple, Type + +from pydantic import ConfigDict +from pydantic_settings import BaseSettings, EnvSettingsSource, PydanticBaseSettingsSource from robyn import Robyn diff --git a/robyn/scaffold/structured/no-db/api/handlers/probes.py b/robyn/scaffold/structured/no-db/api/handlers/probes.py index b0cbc6583..898c18f99 100644 --- a/robyn/scaffold/structured/no-db/api/handlers/probes.py +++ b/robyn/scaffold/structured/no-db/api/handlers/probes.py @@ -1,6 +1,5 @@ from robyn import SubRouter - router = SubRouter(__name__, prefix="/") diff --git a/robyn/scaffold/structured/no-db/server.py b/robyn/scaffold/structured/no-db/server.py index 057eed07e..b3f391b14 100644 --- a/robyn/scaffold/structured/no-db/server.py +++ b/robyn/scaffold/structured/no-db/server.py @@ -1,8 +1,8 @@ -from robyn.helpers import discover_routes -from robyn import Robyn - from conf import settings +from robyn import Robyn +from robyn.helpers import discover_routes + app: Robyn = discover_routes("api.handlers") # note: if you prefer to manuall refine routes, use your build_routes function instead diff --git a/robyn/scaffold/structured/sqlalchemy/adaptors/models/user.py b/robyn/scaffold/structured/sqlalchemy/adaptors/models/user.py index 88ae1f390..48d651359 100644 --- a/robyn/scaffold/structured/sqlalchemy/adaptors/models/user.py +++ b/robyn/scaffold/structured/sqlalchemy/adaptors/models/user.py @@ -1,6 +1,6 @@ -from sqlalchemy import String, Integer, Boolean -from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from pydantic import BaseModel +from sqlalchemy import Boolean, Integer, String +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column class Base(DeclarativeBase): diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py index d232352f8..6311e7ee8 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/probes.py @@ -1,6 +1,5 @@ from robyn import SubRouter - router = SubRouter(__name__, prefix="/") diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index dd8350f2a..336d44e85 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -1,7 +1,8 @@ -from robyn import SubRouter from adaptors.selectors.misc import sample_selector from utils.db import get_db_connection +from robyn import SubRouter + router = SubRouter(__name__, prefix="/sample/") diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 03303208c..0731356dd 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -1,9 +1,7 @@ from logging.config import fileConfig - -from alembic import context from adaptors import models - +from alembic import context from utils.db import get_pool # this is the Alembic Config object, which provides diff --git a/robyn/scaffold/structured/sqlalchemy/server.py b/robyn/scaffold/structured/sqlalchemy/server.py index 8a3b402ac..edf37ac90 100644 --- a/robyn/scaffold/structured/sqlalchemy/server.py +++ b/robyn/scaffold/structured/sqlalchemy/server.py @@ -1,8 +1,8 @@ -from robyn.helpers import discover_routes -from robyn import Robyn - -from utils.db import get_pool from conf import settings +from utils.db import get_pool + +from robyn import Robyn +from robyn.helpers import discover_routes app: Robyn = discover_routes("api.handlers") # note: if you prefer to manuall refine routes, use your build_routes function instead diff --git a/robyn/scaffold/structured/sqlalchemy/utils/db.py b/robyn/scaffold/structured/sqlalchemy/utils/db.py index fca8a9e6c..64b8f44ca 100644 --- a/robyn/scaffold/structured/sqlalchemy/utils/db.py +++ b/robyn/scaffold/structured/sqlalchemy/utils/db.py @@ -1,6 +1,7 @@ from contextlib import asynccontextmanager -from sqlalchemy.ext.asyncio import create_async_engine + from conf import settings +from sqlalchemy.ext.asyncio import create_async_engine def get_pool(): From d8552502257b3fc741f86b605e2b70593b57ca12 Mon Sep 17 00:00:00 2001 From: Ashu Pednekar Date: Fri, 11 Oct 2024 22:54:51 +0530 Subject: [PATCH 51/63] Update index.mdx Co-authored-by: Sanskar Jethi <29942790+sansyrox@users.noreply.github.com> --- docs_src/src/pages/documentation/example_app/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs_src/src/pages/documentation/example_app/index.mdx b/docs_src/src/pages/documentation/example_app/index.mdx index 243501159..a851ee468 100644 --- a/docs_src/src/pages/documentation/example_app/index.mdx +++ b/docs_src/src/pages/documentation/example_app/index.mdx @@ -43,7 +43,7 @@ This, would result in the following output if you choose scaffold type as `simpl $ python3 -m robyn --create ? Directory Path: . ? Need Docker? (Y/N) Y -? Please choose if you'd like the scaffold to be a simple starter kit or an opinionated structure +? Please choose if you would like the scaffold to be a barebones starter kit or a recommended structure ? Please select project type (Mongo/Postgres/Sqlalchemy/Prisma): ❯ No DB Sqlite From 5a890cb26c88a75d071c471eec036796a7fa7e16 Mon Sep 17 00:00:00 2001 From: Ashu Pednekar Date: Fri, 11 Oct 2024 23:28:35 +0530 Subject: [PATCH 52/63] doc: udpated example app index.md --- docs_src/src/pages/documentation/example_app/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs_src/src/pages/documentation/example_app/index.mdx b/docs_src/src/pages/documentation/example_app/index.mdx index a851ee468..0f217988b 100644 --- a/docs_src/src/pages/documentation/example_app/index.mdx +++ b/docs_src/src/pages/documentation/example_app/index.mdx @@ -25,7 +25,7 @@ Batman wanted to create a Robyn app and was about to create an `src/app.py` befo $ python -m robyn --create ``` -You can choose to have a simple starter format or an opinionated scaffold ike so... +You can choose to have a simple barebones format or an structured scaffold (recommended) ike so... ```bash $ python -m robyn --create From e627b598900fbb79e6e6ae5de00d9e982af1081e Mon Sep 17 00:00:00 2001 From: Ashu Pednekar Date: Fri, 11 Oct 2024 23:31:20 +0530 Subject: [PATCH 53/63] chore: added aiosqlite dependency and commented env --- robyn/scaffold/structured/sqlalchemy/config.env | 1 + robyn/scaffold/structured/sqlalchemy/requirements.txt | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/robyn/scaffold/structured/sqlalchemy/config.env b/robyn/scaffold/structured/sqlalchemy/config.env index 469ae898c..5fa8db65e 100644 --- a/robyn/scaffold/structured/sqlalchemy/config.env +++ b/robyn/scaffold/structured/sqlalchemy/config.env @@ -1,6 +1,7 @@ SERVICE_PORT=3000 # change the engine as per db DATABASE_URL=postgresql+asyncpg://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME} +#DATABASE_URL=sqlite+aiosqlite:// DB_POOL_SIZE=10 DB_POOL_MAX_OVERFLOW=20 DB_POOL_TIMEOUT=30 diff --git a/robyn/scaffold/structured/sqlalchemy/requirements.txt b/robyn/scaffold/structured/sqlalchemy/requirements.txt index 4a28cedcb..a73591bab 100644 --- a/robyn/scaffold/structured/sqlalchemy/requirements.txt +++ b/robyn/scaffold/structured/sqlalchemy/requirements.txt @@ -2,7 +2,9 @@ robyn #DB SQLAlchemy~=2.0.35 alembic~=1.13.3 -asyncpg==0.29.0 +#drivers +asyncpg~=0.29.0 +aiosqlite~=0.20.0 #schema pydantic~=2.7.4 pydantic-settings~=2.2.1 From c716a849d9e041b769334c1c81690d1cd11c080a Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 16 Oct 2024 14:06:39 +0530 Subject: [PATCH 54/63] fix: updated alembic env.py to use sync connection and sessionmaker --- robyn/scaffold/structured/sqlalchemy/alembic.ini | 2 ++ robyn/scaffold/structured/sqlalchemy/migrations/env.py | 9 +++++++-- robyn/scaffold/structured/sqlalchemy/utils/db.py | 9 +++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/alembic.ini b/robyn/scaffold/structured/sqlalchemy/alembic.ini index 44f7f6428..f8a3d8518 100644 --- a/robyn/scaffold/structured/sqlalchemy/alembic.ini +++ b/robyn/scaffold/structured/sqlalchemy/alembic.ini @@ -75,6 +75,8 @@ version_path_separator = os # Use os.pathsep. Default configuration used for ne # are written from script.py.mako # output_encoding = utf-8 +# If you need to run offline migrations, please change this databsae url accordingly +# note: not relevant for online migrations since that's taken care in env.py sqlalchemy.url = driver://user:pass@localhost/dbname diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 0731356dd..ca37709d1 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -1,8 +1,10 @@ from logging.config import fileConfig +from sqlalchemy.orm import sessionmaker + from adaptors import models from alembic import context -from utils.db import get_pool +from utils.db import get_sync_pool # this is the Alembic Config object, which provides # access to the values within the .ini file in use. @@ -56,7 +58,10 @@ def run_migrations_online() -> None: and associate a connection with the context. """ - with get_pool() as session: + engine = get_sync_pool() + Session = sessionmaker(bind=engine) + + with Session() as session: context.configure(connection=session.connection(), target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations() diff --git a/robyn/scaffold/structured/sqlalchemy/utils/db.py b/robyn/scaffold/structured/sqlalchemy/utils/db.py index 64b8f44ca..6fb2e5020 100644 --- a/robyn/scaffold/structured/sqlalchemy/utils/db.py +++ b/robyn/scaffold/structured/sqlalchemy/utils/db.py @@ -1,9 +1,18 @@ from contextlib import asynccontextmanager from conf import settings +from sqlalchemy import create_engine from sqlalchemy.ext.asyncio import create_async_engine +def get_sync_pool(): + # for databsae migrations + return create_engine( + settings.database_url, + echo=settings.db_pool_echo, + ) + + def get_pool(): return create_async_engine( settings.database_url, From 20e139034c5aaaa7301197f653e2af3a55fb8552 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 16 Oct 2024 14:17:35 +0530 Subject: [PATCH 55/63] fix: updated alembic env.py to refer ini file --- robyn/scaffold/structured/sqlalchemy/alembic.ini | 5 ++--- robyn/scaffold/structured/sqlalchemy/migrations/env.py | 4 ++-- robyn/scaffold/structured/sqlalchemy/utils/db.py | 9 --------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/alembic.ini b/robyn/scaffold/structured/sqlalchemy/alembic.ini index f8a3d8518..723353d5c 100644 --- a/robyn/scaffold/structured/sqlalchemy/alembic.ini +++ b/robyn/scaffold/structured/sqlalchemy/alembic.ini @@ -75,10 +75,9 @@ version_path_separator = os # Use os.pathsep. Default configuration used for ne # are written from script.py.mako # output_encoding = utf-8 -# If you need to run offline migrations, please change this databsae url accordingly -# note: not relevant for online migrations since that's taken care in env.py +# Before running alembic commands... please change this databsae url accordingly sqlalchemy.url = driver://user:pass@localhost/dbname - +# sqlalchemy.url = postgresql+psycopg://user:password@localhost:5432/yourdb [post_write_hooks] # post_write_hooks defines scripts or Python functions that are run diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index ca37709d1..081d4c80f 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -1,10 +1,10 @@ from logging.config import fileConfig +from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from adaptors import models from alembic import context -from utils.db import get_sync_pool # this is the Alembic Config object, which provides # access to the values within the .ini file in use. @@ -58,7 +58,7 @@ def run_migrations_online() -> None: and associate a connection with the context. """ - engine = get_sync_pool() + engine = create_engine(config.get_main_option("sqlalchemy.url")) Session = sessionmaker(bind=engine) with Session() as session: diff --git a/robyn/scaffold/structured/sqlalchemy/utils/db.py b/robyn/scaffold/structured/sqlalchemy/utils/db.py index 6fb2e5020..64b8f44ca 100644 --- a/robyn/scaffold/structured/sqlalchemy/utils/db.py +++ b/robyn/scaffold/structured/sqlalchemy/utils/db.py @@ -1,18 +1,9 @@ from contextlib import asynccontextmanager from conf import settings -from sqlalchemy import create_engine from sqlalchemy.ext.asyncio import create_async_engine -def get_sync_pool(): - # for databsae migrations - return create_engine( - settings.database_url, - echo=settings.db_pool_echo, - ) - - def get_pool(): return create_async_engine( settings.database_url, From 8939695480b47f266ce81b6bfb64e5bb6c118c35 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 16 Oct 2024 14:23:27 +0530 Subject: [PATCH 56/63] doc: updated example app docs for migrations --- .../pages/documentation/example_app/index.mdx | 54 ++++++++++++++++--- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/docs_src/src/pages/documentation/example_app/index.mdx b/docs_src/src/pages/documentation/example_app/index.mdx index 0f217988b..12ffe8e0c 100644 --- a/docs_src/src/pages/documentation/example_app/index.mdx +++ b/docs_src/src/pages/documentation/example_app/index.mdx @@ -53,12 +53,7 @@ $ python3 -m robyn --create Prisma ``` -and the following directory structure. - - -Batman was asked a set of questions to configure the application. He chose to use the default values for most of the questions. - -And he was done! The Robyn CLI created a new application with the following structure. +and the following directory structure ```bash @@ -161,4 +156,51 @@ Comes with initial settings you need to work with the database. The `BaseConfig` > note: by default, we include sqlalchemy async pool, you can always change it as per your requirements +Once you have set up your project like so, make sure to update the `sqlalchemy.url` field in your `alembic.ini`file to point to your DB like so... + +``` +sqlalchemy.url = postgresql+psycopg://consoleuser:buddy123@localhost:5432/console +``` + +Then, once you are done writing your sqlalchemy model classes, you can go ahead and generate your migration files like so + +```bash +alembic revision --autogenerate -m initial +``` +You should see an output like so +``` +/home/batman/.virtualenvs/base/lib/python3.12/site-packages/pydantic/_internal/_config.py:334: UserWarning: Valid config keys have changed in V2: +* 'orm_mode' has been renamed to 'from_attributes' + warnings.warn(message, UserWarning) +INFO [alembic.runtime.migration] Context impl PostgresqlImpl. +INFO [alembic.runtime.migration] Will assume transactional DDL. +INFO [alembic.autogenerate.compare] Detected added table 'users' +INFO [alembic.autogenerate.compare] Detected added index ''ix_users_id'' on '('id',)' +INFO [alembic.autogenerate.compare] Detected added index ''ix_users_username'' on '('username',)' +INFO [alembic.ddl.postgresql] Detected sequence named 'transactions_id_seq' as owned by integer column 'transactions(id)', assuming SERIAL and omitting +INFO [alembic.autogenerate.compare] Detected removed index 'idx_user_id' on 'transactions' +INFO [alembic.autogenerate.compare] Detected removed table 'transactions' + Generating /home/ashu/Desktop/aaa/migrations/versions/cefc632435c7_initial.py ... done +``` + +This will generate the migration files like so + +```bash +$ tree migrations/ +migrations/ +├── env.py +├── README +├── script.py.mako +└── versions + ├── cefc632435c7_initial.py + └── __init__.py + +2 directories, 5 files +``` + +Now you can apply the migrations with `alembic upgrade head` + +Batman was asked a set of questions to configure the application. He chose to use the default values for most of the questions. + +And he was done! The Robyn CLI created a new application with the following structure. From 128942149cb8958c426f0be58c40dfb1fbf3ee4b Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 16 Oct 2024 14:26:35 +0530 Subject: [PATCH 57/63] chore: removed class groups on handlers in favour of straigtforward handler functions --- .../structured/no-db/api/handlers/sample.py | 14 +++----- .../sqlalchemy/api/handlers/sample.py | 32 ++++++++----------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/robyn/scaffold/structured/no-db/api/handlers/sample.py b/robyn/scaffold/structured/no-db/api/handlers/sample.py index a1aefd5e6..f4bce023e 100644 --- a/robyn/scaffold/structured/no-db/api/handlers/sample.py +++ b/robyn/scaffold/structured/no-db/api/handlers/sample.py @@ -3,18 +3,12 @@ router = SubRouter(__name__, "/sample") -class SampleHandlers: - """ - note: the handles being grouped in a class like this is complete optional, and doesn't have any impact on routing - """ +@router.post("/one") +def one(): ... - @router.post("/one") - @staticmethod - def one(): ... - @router.get("/two") - @staticmethod - def two(): ... +@router.get("/two") +def two(): ... @router.get("three/") diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index 336d44e85..77c0632e2 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -6,25 +6,19 @@ router = SubRouter(__name__, prefix="/sample/") -class SampleHandlers: - """ - note: the handles being grouped in a class like this is complete optional, and doesn't have any impact on routing - """ - - @staticmethod - @router.post("one/") - async def one(global_dependencies): - pool = global_dependencies.get("pool") - async with get_db_connection(pool) as conn: - # invoke your mutators/selectors here - res = await sample_selector(conn) - print(res) - return {} - - @staticmethod - @router.get("two/") - def two(): - return {} +@router.post("one/") +async def one(global_dependencies): + pool = global_dependencies.get("pool") + async with get_db_connection(pool) as conn: + # invoke your mutators/selectors here + res = await sample_selector(conn) + print(res) + return {} + + +@router.get("two/") +def two(): + return {} @router.get("three/") From 0d848b53b6ed344135f83d57ec3e7b58aebd5a64 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 16 Oct 2024 14:28:34 +0530 Subject: [PATCH 58/63] chore: deleted readme in migrations directory in sqlalchemy scaffold --- robyn/scaffold/structured/sqlalchemy/migrations/README | 1 - 1 file changed, 1 deletion(-) delete mode 100644 robyn/scaffold/structured/sqlalchemy/migrations/README diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/README b/robyn/scaffold/structured/sqlalchemy/migrations/README deleted file mode 100644 index 98e4f9c44..000000000 --- a/robyn/scaffold/structured/sqlalchemy/migrations/README +++ /dev/null @@ -1 +0,0 @@ -Generic single-database configuration. \ No newline at end of file From 3b3a51e53a9a652973227fb2c14b8ae5406e79d2 Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 16 Oct 2024 14:30:12 +0530 Subject: [PATCH 59/63] chore: changed global dependency name to db_connection_pool --- robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py | 2 +- robyn/scaffold/structured/sqlalchemy/server.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py index 77c0632e2..3b668fb70 100644 --- a/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py +++ b/robyn/scaffold/structured/sqlalchemy/api/handlers/sample.py @@ -8,7 +8,7 @@ @router.post("one/") async def one(global_dependencies): - pool = global_dependencies.get("pool") + pool = global_dependencies.get("db_connection_pool") async with get_db_connection(pool) as conn: # invoke your mutators/selectors here res = await sample_selector(conn) diff --git a/robyn/scaffold/structured/sqlalchemy/server.py b/robyn/scaffold/structured/sqlalchemy/server.py index edf37ac90..ecce9dbe6 100644 --- a/robyn/scaffold/structured/sqlalchemy/server.py +++ b/robyn/scaffold/structured/sqlalchemy/server.py @@ -7,7 +7,7 @@ app: Robyn = discover_routes("api.handlers") # note: if you prefer to manuall refine routes, use your build_routes function instead -app.inject_global(pool=get_pool()) +app.inject_global(db_connection_pool=get_pool()) if __name__ == "__main__": From f348cacd7d67a47d2bf3f671c769d29c7e9f0a0f Mon Sep 17 00:00:00 2001 From: ashupednekar Date: Wed, 16 Oct 2024 14:31:21 +0530 Subject: [PATCH 60/63] chore: renamed db pool function to be more descriptive --- robyn/scaffold/structured/sqlalchemy/server.py | 4 ++-- robyn/scaffold/structured/sqlalchemy/utils/db.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/robyn/scaffold/structured/sqlalchemy/server.py b/robyn/scaffold/structured/sqlalchemy/server.py index ecce9dbe6..6c2cc7cec 100644 --- a/robyn/scaffold/structured/sqlalchemy/server.py +++ b/robyn/scaffold/structured/sqlalchemy/server.py @@ -1,5 +1,5 @@ from conf import settings -from utils.db import get_pool +from utils.db import get_database_connection_pool from robyn import Robyn from robyn.helpers import discover_routes @@ -7,7 +7,7 @@ app: Robyn = discover_routes("api.handlers") # note: if you prefer to manuall refine routes, use your build_routes function instead -app.inject_global(db_connection_pool=get_pool()) +app.inject_global(db_connection_pool=get_database_connection_pool()) if __name__ == "__main__": diff --git a/robyn/scaffold/structured/sqlalchemy/utils/db.py b/robyn/scaffold/structured/sqlalchemy/utils/db.py index 64b8f44ca..14f80c9b1 100644 --- a/robyn/scaffold/structured/sqlalchemy/utils/db.py +++ b/robyn/scaffold/structured/sqlalchemy/utils/db.py @@ -4,7 +4,7 @@ from sqlalchemy.ext.asyncio import create_async_engine -def get_pool(): +def get_database_connection_pool(): return create_async_engine( settings.database_url, pool_size=settings.db_pool_size, From 897652252eada69fe1cdaf058ceefd5bc0d475c9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 09:01:45 +0000 Subject: [PATCH 61/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- robyn/scaffold/structured/sqlalchemy/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/robyn/scaffold/structured/sqlalchemy/server.py b/robyn/scaffold/structured/sqlalchemy/server.py index 6c2cc7cec..b70876b9d 100644 --- a/robyn/scaffold/structured/sqlalchemy/server.py +++ b/robyn/scaffold/structured/sqlalchemy/server.py @@ -1,5 +1,5 @@ from conf import settings -from utils.db import get_database_connection_pool +from utils.db import get_database_connection_pool from robyn import Robyn from robyn.helpers import discover_routes From 170e496ce0bdcca9ea2d4975e0df7e5f72908e92 Mon Sep 17 00:00:00 2001 From: Ashu Pednekar Date: Wed, 16 Oct 2024 22:48:26 +0530 Subject: [PATCH 62/63] doc: added alembic readme, dep: added psycopg dep, style: ruff on scaffold dir --- robyn/scaffold/simple/postgres/app.py | 4 +- .../sqlalchemy/migrations/README.md | 62 +++++++++++++++++++ .../structured/sqlalchemy/migrations/env.py | 4 +- .../structured/sqlalchemy/requirements.txt | 1 + 4 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 robyn/scaffold/structured/sqlalchemy/migrations/README.md diff --git a/robyn/scaffold/simple/postgres/app.py b/robyn/scaffold/simple/postgres/app.py index 8c1362335..499c0d9a8 100644 --- a/robyn/scaffold/simple/postgres/app.py +++ b/robyn/scaffold/simple/postgres/app.py @@ -8,7 +8,9 @@ DB_PASS = "password" DB_PORT = "5455" -conn = psycopg2.connect(database=DB_NAME, host=DB_HOST, user=DB_USER, password=DB_PASS, port=DB_PORT) +conn = psycopg2.connect( + database=DB_NAME, host=DB_HOST, user=DB_USER, password=DB_PASS, port=DB_PORT +) app = Robyn(__file__) diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/README.md b/robyn/scaffold/structured/sqlalchemy/migrations/README.md new file mode 100644 index 000000000..3f89ec979 --- /dev/null +++ b/robyn/scaffold/structured/sqlalchemy/migrations/README.md @@ -0,0 +1,62 @@ + +# Alembic Migrations + +This directory contains database migrations managed by Alembic, a lightweight migration tool for SQLAlchemy applications. + +## Configuration + +Update the `sqlalchemy.url` in `alembic.ini` with your database connection string: + +``` +sqlalchemy.url = postgresql+psycopg://user:password@localhost:5432/yourdb +``` + +### Example Connection Strings: +- **PostgreSQL**: `postgresql+psycopg://user:password@localhost:5432/yourdb` +- **MySQL**: `mysql+pymysql://user:password@localhost:3306/yourdb` +- **SQLite**: `sqlite:///./test.db` + +## Migrations Workflow + +### Create a New Migration +Generate a migration script based on model changes: + +``` +alembic revision --autogenerate -m "describe your changes" +``` + +### Run Migrations +Apply all pending migrations: + +``` +alembic upgrade head +``` + +### Downgrade Migrations +Rollback the most recent migration: + +``` +alembic downgrade -1 +``` + +Or downgrade to a specific revision: + +``` +alembic downgrade +``` + +### Common Commands + +Other useful commands include: + +- View the current migration status: + + ``` + alembic current + ``` + +- View the migration history: + + ``` + alembic history + ``` diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 081d4c80f..25168758b 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -62,7 +62,9 @@ def run_migrations_online() -> None: Session = sessionmaker(bind=engine) with Session() as session: - context.configure(connection=session.connection(), target_metadata=target_metadata) + context.configure( + connection=session.connection(), target_metadata=target_metadata + ) with context.begin_transaction(): context.run_migrations() diff --git a/robyn/scaffold/structured/sqlalchemy/requirements.txt b/robyn/scaffold/structured/sqlalchemy/requirements.txt index a73591bab..e5c19dfd7 100644 --- a/robyn/scaffold/structured/sqlalchemy/requirements.txt +++ b/robyn/scaffold/structured/sqlalchemy/requirements.txt @@ -4,6 +4,7 @@ SQLAlchemy~=2.0.35 alembic~=1.13.3 #drivers asyncpg~=0.29.0 +psycopg2-binary~=2.9.9 aiosqlite~=0.20.0 #schema pydantic~=2.7.4 From 662c0093fa20d07cc9bd6b4a80af6796957195f3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 17:20:27 +0000 Subject: [PATCH 63/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- robyn/scaffold/simple/postgres/app.py | 4 +--- robyn/scaffold/structured/sqlalchemy/migrations/env.py | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/robyn/scaffold/simple/postgres/app.py b/robyn/scaffold/simple/postgres/app.py index 499c0d9a8..8c1362335 100644 --- a/robyn/scaffold/simple/postgres/app.py +++ b/robyn/scaffold/simple/postgres/app.py @@ -8,9 +8,7 @@ DB_PASS = "password" DB_PORT = "5455" -conn = psycopg2.connect( - database=DB_NAME, host=DB_HOST, user=DB_USER, password=DB_PASS, port=DB_PORT -) +conn = psycopg2.connect(database=DB_NAME, host=DB_HOST, user=DB_USER, password=DB_PASS, port=DB_PORT) app = Robyn(__file__) diff --git a/robyn/scaffold/structured/sqlalchemy/migrations/env.py b/robyn/scaffold/structured/sqlalchemy/migrations/env.py index 25168758b..081d4c80f 100644 --- a/robyn/scaffold/structured/sqlalchemy/migrations/env.py +++ b/robyn/scaffold/structured/sqlalchemy/migrations/env.py @@ -62,9 +62,7 @@ def run_migrations_online() -> None: Session = sessionmaker(bind=engine) with Session() as session: - context.configure( - connection=session.connection(), target_metadata=target_metadata - ) + context.configure(connection=session.connection(), target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations()