From 6eae52bf7076d6ecdbff3664aee11dbe3fa514b8 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Wed, 29 Apr 2026 13:04:46 -0700 Subject: [PATCH 1/4] feat: database imrovements --- CLAUDE.md | 186 ++++++++++++++++++ .../src/fastapi_startkit/application.py | 25 +-- .../src/fastapi_startkit/config/__init__.py | 1 - .../fastapi_startkit/exceptions/handler.py | 5 +- .../src/fastapi_startkit/helpers/string.py | 20 ++ .../commands/MakeMigrationCommand.py | 9 +- .../commands/MigrateFreshCommand.py | 4 +- .../commands/stubs/create_migration.stub | 10 +- .../commands/stubs/table_migration.stub | 10 +- .../masoniteorm/connections/factory.py | 3 + .../masoniteorm/connections/manager.py | 7 +- .../connections/mysql_connection.py | 20 ++ .../masoniteorm/models/model.py | 2 +- .../masoniteorm/providers/DatabaseProvider.py | 1 + .../masoniteorm/schema/schema.py | 10 + .../fastapi_startkit/providers/Provider.py | 1 + 16 files changed, 284 insertions(+), 30 deletions(-) create mode 100644 CLAUDE.md create mode 100644 fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..1b0b3a68 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,186 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is a **monorepo** for the FastAPI Startkit ecosystem — a Laravel/Masonite-inspired framework for building Python applications with FastAPI. It contains four main components: + +| Directory | Purpose | Published as | +|---|---|---| +| `fastapi_startkit/` | Core framework package | [`fastapi-startkit`](https://pypi.org/project/fastapi-startkit/) on PyPI | +| `fastapi_startkit.github.io.git/` | Documentation site | GitHub Pages (VitePress) | +| `example/` | Standalone example apps | Not published — reference only | +| `application/` | Starter application template | Not published — clone/scaffold target | + +### `fastapi_startkit/` — Core Package + +The PyPI package (`fastapi-startkit`, currently v0.13.6). Source lives under `src/fastapi_startkit/`. This is the foundational framework all other components depend on. + +**Do not modify framework code unless explicitly necessary.** Changes to core abstractions (Container, Application, Model, Provider, Facades) can have broad breaking effects on downstream applications. + +Optional extras are installed with pip/uv extras: + +``` +fastapi-startkit[fastapi] # FastAPI + Starlette +fastapi-startkit[database] # SQLAlchemy async ORM +fastapi-startkit[postgres] # asyncpg driver +fastapi-startkit[sqlite] # aiosqlite driver +fastapi-startkit[mysql] # aiomysql driver +fastapi-startkit[vite] # Jinja2 for Vite integration +``` + +### `fastapi_startkit.github.io.git/` — Documentation + +VitePress site. Docs cover getting started, configuration, console, database, logging, FastAPI integration, frontend, and exception handling. Edit `.md` files under `docs/` and the home page at `index.md`. + +### `example/` — Example Applications + +Self-contained apps demonstrating specific features. Each subdirectory is an independent uv workspace member: + +| App | What it shows | +|---|---| +| `config-app/` | Configuration system | +| `console-app/` | CLI / Cleo commands | +| `database-app/` | ORM, migrations, seeders | +| `fastapi-app/` | Minimal FastAPI setup | +| `inertia-pingcrm-app/` | Full Inertia.js + PingCRM clone | +| `onefile-app/` | Single-file application | +| `vite-app/` | Vite + Jinja2 frontend | + +### `application/` — Starter Application + +The template users clone when starting a new project. Contains the minimal scaffolding: `artisan` entrypoint, `bootstrap/`, `config/`, `providers/`, `routes/`, and `storage/`. It mirrors a typical project layout and is a uv workspace member of this monorepo. + +## Commands + +```bash +# Install all workspace dependencies +uv sync + +# Build the core package +cd fastapi_startkit && uv build + +# Run framework tests +uv run pytest fastapi_startkit/src/fastapi_startkit/tests/ -v + +# Run a single test file +uv run pytest fastapi_startkit/src/fastapi_startkit/tests/configurations/test_config_merge.py -v + +# Serve the docs locally +cd fastapi_startkit.github.io.git && npm run dev +``` + +Tests run with `asyncio_mode = "auto"` (configured in `pyproject.toml`), so all tests are async-capable by default. + +## Architecture (Core Package) + +### Application Lifecycle + +1. `Application(base_path)` initializes the service container and singleton +2. `.load_environment()` loads `.env` + `.env.{APP_ENV}` (auto-detects `.env.testing` under pytest) +3. `.configure_paths()` sets config/storage paths +4. `.register_providers()` → `.load_providers()` (two-phase boot) +5. `app.fastapi` is lazy-loaded; HTTP routes delegate to the FastAPI instance + +### Service Container (`container/container.py`) + +Central IoC container. Core API: +- `bind(key, value)` — register a binding +- `make(key)` — resolve a binding +- `resolve(obj)` — auto-wire a callable by inspecting its type-hinted parameters + +Hooks (`on_bind`, `on_make`, `on_resolve`) allow intercepting container operations. `collect('Auth*')` returns all bindings matching a wildcard. + +### Configuration (`configuration/`) + +Define config as a dataclass with fields sourced from environment variables via `env()`: + +```python +from dataclasses import dataclass, field +from fastapi_startkit.environment import env + +@dataclass +class RedisConfig: + host: str = field(default_factory=lambda: env('REDIS_HOST')) + port: int = field(default_factory=lambda: env('REDIS_PORT')) +``` + +`app.load_environment()` applies a two-step merge: `.env` as base, then `.env.{APP_ENV}` on top. + +Register in the container for dotted-key access: + +```python +config = app.make('config') +config.set('redis', RedisConfig()) + +Config.get('redis.host') # via facade +``` + +### Provider Pattern (`providers/`) + +Providers are the standard way to register services. Each provider has two phases: +- `register()` — bind things into the container +- `boot()` — run after all providers are registered (safe to resolve dependencies here) + +### FastAPI Routing (`fastapi/routers/router.py`) + +`Router` wraps FastAPI's `APIRouter` and adds a `resource()` shortcut. + +```python +from fastapi_startkit.fastapi import Router + +router = Router() +router.get("/path", endpoint) +router.post("/path", endpoint) +router.put("/path", endpoint) +router.patch("/path", endpoint) +router.delete("/path", endpoint) +``` + +`router.resource(name, controller)` registers standard CRUD routes (index, create, store, show, edit, update, destroy). Use `only=`, `excepts=`, `names=`, `parameters=` to customise. + +Group routes by access level using separate `Router` instances: + +```python +# routes/web.py +from fastapi import Depends +from fastapi_startkit.fastapi import Router + +guest = Router() +guest.get("/login", auth_controller.create) +guest.post("/login", auth_controller.store) + +auth = Router(dependencies=[Depends(auth_middleware)]) +auth.get("/", dashboard_controller.index) +auth.resource("users", users_controller) +``` + +### ORM (`masoniteorm/`) + +Async-first fork of Masonite ORM built on SQLAlchemy async: +- All DB operations are `async`/`await` +- `Model` auto-pluralizes table names via `inflection` +- `created_at`/`updated_at` managed as `pendulum` Carbon objects +- Relationships: `HasOne`, `HasMany`, `BelongsTo`, `BelongsToMany`, `HasOneThrough` +- `AsyncQueryBuilder` provides the chainable query interface + +### Facades (`facades/`) + +Static-like access to container-resolved services (`Config.get()`, `Auth.user()`, etc.). Each facade has a `.pyi` stub for IDE type support. Requires a booted Application singleton. + +### Console (`commands/`, `masoniteorm/commands/`) + +CLI built on [Cleo](https://github.com/python-poetry/cleo). Database commands (migrate, seed, make:model, etc.) live in `masoniteorm/commands/`. Run via `uv run artisan`. + +## Key Dependencies + +| Package | Purpose | +|---|---| +| `fastapi[standard]` | HTTP framework (lazily imported) | +| `sqlalchemy[asyncio]` | Async ORM backend | +| `pendulum` | Datetime/timezone (used as Carbon) | +| `cleo` | CLI commands | +| `dotty-dict` | Nested dict access via dotted keys | +| `inflection` | Table name pluralization | +| `asyncpg` / `aiomysql` / `aiosqlite` | DB drivers | diff --git a/fastapi_startkit/src/fastapi_startkit/application.py b/fastapi_startkit/src/fastapi_startkit/application.py index 05efa65b..065dcdbd 100644 --- a/fastapi_startkit/src/fastapi_startkit/application.py +++ b/fastapi_startkit/src/fastapi_startkit/application.py @@ -1,9 +1,9 @@ import os +from fastapi_startkit.providers.app_provider import AppProvider from pathlib import Path from typing import TYPE_CHECKING, Optional from typing import Type, Callable, Any, List, TypeVar, Generic -from fastapi_startkit.providers.app_provider import AppProvider from .config import AppConfig from .configuration.providers import ConfigurationProvider from .container import Container @@ -30,12 +30,12 @@ class Application(Container, Generic[TConfig]): ] def __init__( - self, - base_path: str | Path = None, - env=None, - providers=None, - config: Type[TConfig] | None = None, - exception_handler: Type[ExceptionHandler] | None = None, + self, + base_path: str | Path = None, + env=None, + providers=None, + config: Type[TConfig] | None = None, + exception_handler: Type[ExceptionHandler] | None = None, ): super().__init__() @@ -83,6 +83,9 @@ def register_providers(self): config = {} if isinstance(provider_data, tuple): provider_class, config = provider_data + + if callable(config): + config = config() else: provider_class = provider_data @@ -151,7 +154,7 @@ def mount(self, path: str, app_instance: "FastAPI", **kwargs): # Add custom exception handlers def add_exception_handler( - self, exc_class_or_status_code: Any, handler: Callable[..., Any] + self, exc_class_or_status_code: Any, handler: Callable[..., Any] ): self._fastapi.add_exception_handler(exc_class_or_status_code, handler) return self @@ -178,9 +181,9 @@ def load_environment(self): def is_debug(self) -> bool: return ( - hasattr(self, "_config_instance") - and self._config_instance is not None - and getattr(self._config_instance, "debug", False) + hasattr(self, "_config_instance") + and self._config_instance is not None + and getattr(self._config_instance, "debug", False) ) def configure_config(self): diff --git a/fastapi_startkit/src/fastapi_startkit/config/__init__.py b/fastapi_startkit/src/fastapi_startkit/config/__init__.py index 2854ca9f..916a0e7e 100644 --- a/fastapi_startkit/src/fastapi_startkit/config/__init__.py +++ b/fastapi_startkit/src/fastapi_startkit/config/__init__.py @@ -1,2 +1 @@ from .app import AppConfig -from .facades import Config diff --git a/fastapi_startkit/src/fastapi_startkit/exceptions/handler.py b/fastapi_startkit/src/fastapi_startkit/exceptions/handler.py index c5e8d8af..4310d18d 100644 --- a/fastapi_startkit/src/fastapi_startkit/exceptions/handler.py +++ b/fastapi_startkit/src/fastapi_startkit/exceptions/handler.py @@ -62,10 +62,13 @@ def report(self, exception: Exception): self.report_exception(exception) def report_exception(self, exception: Exception): + context = self._build_context(exception) if self.app and self.app.has("logger"): from fastapi_startkit.logging.logger import Logger - Logger.error(self._build_context(exception)) + Logger.error(context) + else: + print(context, file=sys.stderr) def _build_context(self, exception: Exception) -> str: import traceback diff --git a/fastapi_startkit/src/fastapi_startkit/helpers/string.py b/fastapi_startkit/src/fastapi_startkit/helpers/string.py index b27e1f35..091c5b7c 100644 --- a/fastapi_startkit/src/fastapi_startkit/helpers/string.py +++ b/fastapi_startkit/src/fastapi_startkit/helpers/string.py @@ -14,6 +14,12 @@ def trim(self, suffix: str) -> "Stringable": def slugify(self) -> "Stringable": return Stringable(Str.slugify(self.text)) + def camel_case(self) -> "Stringable": + return Stringable(Str.camel_case(self.text)) + + def snake_case(self) -> "Stringable": + return Stringable(Str.snake_case(self.text)) + class Str: @classmethod @@ -29,3 +35,17 @@ def slugify(cls, text: str) -> str: def trim(cls, text: str, word: str) -> str: """Remove all occurrences of a word from the string (case-insensitive).""" return re.sub(re.escape(word), "", text, flags=re.IGNORECASE).strip("_").strip() + + @classmethod + def camel_case(cls, text: str) -> str: + """Convert a string to camelCase.""" + words = re.split(r"[-_\s]+", text) + return words[0].lower() + "".join(word.capitalize() for word in words[1:]) + + @classmethod + def snake_case(cls, text: str) -> str: + """Convert a string to snake_case.""" + text = re.sub(r"[-\s]+", "_", text) + text = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1_\2", text) + text = re.sub(r"([a-z\d])([A-Z])", r"\1_\2", text) + return text.lower() diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/MakeMigrationCommand.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/MakeMigrationCommand.py index 9d1b6b35..6b79baf7 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/MakeMigrationCommand.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/MakeMigrationCommand.py @@ -1,8 +1,9 @@ import datetime import os import pathlib -from inflection import camelize, tableize +from inflection import tableize from cleo.helpers import argument, option +from fastapi_startkit.helpers.string import Str from .Command import Command @@ -29,7 +30,7 @@ class MakeMigrationCommand(Command): ] def handle(self): - name = self.argument("name") + name = self.argument("name").replace("-", "_") now = datetime.datetime.today() if self.option("create") != "None": @@ -52,7 +53,9 @@ def handle(self): ) ) as fp: output = fp.read() - output = output.replace("__MIGRATION_NAME__", camelize(name)) + camel = Str.camel_case(name) + class_name = camel[0].upper() + camel[1:] + output = output.replace("__MIGRATION_NAME__", class_name) output = output.replace("__TABLE_NAME__", table) file_name = f"{now.strftime('%Y_%m_%d_%H%M%S')}_{name}.py" diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py index 35aba878..0f63c32b 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py @@ -22,7 +22,7 @@ class MigrateFreshCommand(Command): description="The location of the migration directory", ), option( - "ignore-fk", "i", flag=True, description="Ignore foreign key constraints" + "no-fk", None, flag=True, description="Re-enable foreign key constraints during drop" ), option( "seed", @@ -54,7 +54,7 @@ async def handle_async(self): migration_directory=self.option("directory"), ) - await migration.fresh(ignore_fk=self.option("ignore-fk")) + await migration.fresh(ignore_fk=not self.option("no-fk")) if self.option("seed") == "null": self.call( diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/stubs/create_migration.stub b/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/stubs/create_migration.stub index fe48fcf2..fe3573a3 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/stubs/create_migration.stub +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/stubs/create_migration.stub @@ -1,20 +1,20 @@ """__MIGRATION_NAME__ Migration.""" -from masoniteorm.migrations import Migration +from fastapi_startkit.masoniteorm.migrations import Migration class __MIGRATION_NAME__(Migration): - def up(self): + async def up(self): """ Run the migrations. """ - with self.schema.create("__TABLE_NAME__") as table: + async with await self.schema.create("__TABLE_NAME__") as table: table.increments("id") table.timestamps() - def down(self): + async def down(self): """ Revert the migrations. """ - self.schema.drop("__TABLE_NAME__") + await self.schema.drop("__TABLE_NAME__") diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/stubs/table_migration.stub b/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/stubs/table_migration.stub index 78985f8e..008964ce 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/stubs/table_migration.stub +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/stubs/table_migration.stub @@ -1,19 +1,19 @@ """__MIGRATION_NAME__ Migration.""" -from masoniteorm.migrations import Migration +from fastapi_startkit.masoniteorm.migrations import Migration class __MIGRATION_NAME__(Migration): - def up(self): + async def up(self): """ Run the migrations. """ - with self.schema.table("__TABLE_NAME__") as table: + async with await self.schema.table("__TABLE_NAME__") as table: pass - def down(self): + async def down(self): """ Revert the migrations. """ - with self.schema.table("__TABLE_NAME__") as table: + async with await self.schema.table("__TABLE_NAME__") as table: pass diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/factory.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/factory.py index 73be80b4..80d62021 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/factory.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/factory.py @@ -8,6 +8,7 @@ from fastapi_startkit.masoniteorm.connections.postgres_connection import ( PostgresConnection, ) +from fastapi_startkit.masoniteorm.connections.mysql_connection import MySQLConnection class ConnectionFactory: @@ -48,5 +49,7 @@ def make(self, config: dict, name: str) -> type[Connection]: return SQliteConnection(engine, config) case "postgres": return PostgresConnection(engine, config) + case "mysql": + return MySQLConnection(engine, config) raise ValueError(f"Unsupported driver: {driver}") diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/manager.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/manager.py index d287fb0f..3a8d29fd 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/manager.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/manager.py @@ -1,3 +1,4 @@ +from dumpdie import dd from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -13,7 +14,11 @@ def __init__(self, factory: "ConnectionFactory", config: dict): def connection(self, name: str | None): name = self.get_default_connection_name(name) assert name is not None - config = self.config[name] + config = self.config.get('connections', {}).get(name) + + if config is None: + raise ValueError(f"Connection '{name}' not found in configuration") + if name not in self.connections: self.connections[name] = self.factory.make(config, name) diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py new file mode 100644 index 00000000..b244c9a3 --- /dev/null +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py @@ -0,0 +1,20 @@ +from fastapi_startkit.masoniteorm.query.grammars import MySQLGrammar +from fastapi_startkit.masoniteorm.query.processors import MySQLPostProcessor +from fastapi_startkit.masoniteorm.schema.platforms import MySQLPlatform +from .connection import Connection + + +class MySQLConnection(Connection): + """Async MySQL connection backed by aiomysql via SQLAlchemy.""" + + @classmethod + def get_query_grammar(cls): + return MySQLGrammar + + @classmethod + def get_default_platform(cls): + return MySQLPlatform + + @classmethod + def get_post_processor(cls): + return MySQLPostProcessor \ No newline at end of file diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/model.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/model.py index 06a065d5..d86e5d60 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/model.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/model.py @@ -177,7 +177,7 @@ def fill(self, attributes: dict) -> "Model": self.set_attribute(key, value) return self - async def save(self, options: dict | None = None) -> bool: + async def save(self, options: dict | None = None): query = self.new_query() self.observe_events(self, "saving") diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py index aa9c0c25..712b8405 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py @@ -1,3 +1,4 @@ +from dumpdie import dd from pathlib import Path from fastapi_startkit.masoniteorm.commands import ( diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/schema/schema.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/schema/schema.py index ef0f5678..c8f6a4b6 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/schema/schema.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/schema/schema.py @@ -92,6 +92,16 @@ async def rename(self, table: str, new_name: str) -> None: ) await self._connection.run(sql, ()) + async def disable_foreign_key_constraints(self) -> None: + connection = self.get_connection() + sql = connection.get_default_platform()().disable_foreign_key_constraints() + await connection.statement(sql, ()) + + async def enable_foreign_key_constraints(self) -> None: + connection = self.get_connection() + sql = connection.get_default_platform()().enable_foreign_key_constraints() + await connection.statement(sql, ()) + async def get_all_tables(self): """Gets all tables in the database.""" connection = self.get_connection() diff --git a/fastapi_startkit/src/fastapi_startkit/providers/Provider.py b/fastapi_startkit/src/fastapi_startkit/providers/Provider.py index f03982c5..3fa59ba5 100644 --- a/fastapi_startkit/src/fastapi_startkit/providers/Provider.py +++ b/fastapi_startkit/src/fastapi_startkit/providers/Provider.py @@ -1,4 +1,5 @@ import dataclasses +from dumpdie import dd, dump from typing import TYPE_CHECKING, Any from fastapi_startkit.helpers.string import Str From 92c485660cc274aae2e0da52952a83a32b2aa845 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Wed, 29 Apr 2026 13:30:52 -0700 Subject: [PATCH 2/4] feat: database --- .../fastapi_startkit/fastapi/exceptions.py | 27 +++++++++++++++++++ .../fastapi/providers/fastapi_provider.py | 5 ++-- 2 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 fastapi_startkit/src/fastapi_startkit/fastapi/exceptions.py diff --git a/fastapi_startkit/src/fastapi_startkit/fastapi/exceptions.py b/fastapi_startkit/src/fastapi_startkit/fastapi/exceptions.py new file mode 100644 index 00000000..bdfcbc67 --- /dev/null +++ b/fastapi_startkit/src/fastapi_startkit/fastapi/exceptions.py @@ -0,0 +1,27 @@ +class HTTPExceptionHandler: + """ + The base exception handler for FastAPI applications. + """ + async def render(self, request, exc): + import traceback + from fastapi.responses import JSONResponse + from fastapi_startkit.container import Container + + app = Container.instance() + if app.is_debug(): + tb = exc.__traceback__ + frames = traceback.extract_tb(tb) + content = { + "message": str(exc), + "exception": f"{type(exc).__module__}.{type(exc).__qualname__}", + "file": frames[-1].filename if frames else None, + "line": frames[-1].lineno if frames else None, + "trace": [ + {"file": f.filename, "line": f.lineno, "function": f.name} + for f in frames + ], + } + else: + content = {"message": "Server Error"} + + return JSONResponse(status_code=500, content=content) diff --git a/fastapi_startkit/src/fastapi_startkit/fastapi/providers/fastapi_provider.py b/fastapi_startkit/src/fastapi_startkit/fastapi/providers/fastapi_provider.py index 4f6ef39c..bd4d72a5 100644 --- a/fastapi_startkit/src/fastapi_startkit/fastapi/providers/fastapi_provider.py +++ b/fastapi_startkit/src/fastapi_startkit/fastapi/providers/fastapi_provider.py @@ -1,3 +1,4 @@ +from fastapi_startkit.fastapi.exceptions import HTTPExceptionHandler from fastapi import FastAPI from fastapi_startkit.fastapi.commands import ServeCommand @@ -20,10 +21,8 @@ def boot(self): def _register_exception_handlers(self): """Wire exception_manager as a catch-all handler for all exceptions.""" - if not self.app.exception_manager: - return - exception_manager = self.app.exception_manager + exception_manager.register_handler(Exception, HTTPExceptionHandler()) async def handler(request, exc): return await exception_manager.handle(exc, {"request": request}) From 04416df84fed7b5d3d156dfd73d84dc4765886fa Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Wed, 29 Apr 2026 13:32:26 -0700 Subject: [PATCH 3/4] feat: ruff fix --- example/database-app/bootstrap/application.py | 25 ++++++------------- example/database-app/routes/api.py | 2 +- fastapi_startkit/pyproject.toml | 7 ++++++ .../src/fastapi_startkit/application.py | 20 +++++++-------- .../fastapi_startkit/exceptions/handler.py | 1 - .../fastapi_startkit/fastapi/exceptions.py | 1 + .../commands/MigrateFreshCommand.py | 5 +++- .../masoniteorm/connections/manager.py | 3 +-- .../connections/mysql_connection.py | 2 +- .../masoniteorm/providers/DatabaseProvider.py | 1 - .../fastapi_startkit/providers/Provider.py | 1 - .../vite/providers/provider.py | 1 - .../src/fastapi_startkit/vite/vite.py | 1 - 13 files changed, 33 insertions(+), 37 deletions(-) diff --git a/example/database-app/bootstrap/application.py b/example/database-app/bootstrap/application.py index 4ca635a7..c764e406 100644 --- a/example/database-app/bootstrap/application.py +++ b/example/database-app/bootstrap/application.py @@ -1,32 +1,23 @@ from pathlib import Path -from config.database import DatabaseConfig -from config.logging import LoggingConfig -from providers.console_provider import ConsoleProvider -from providers.fastapi_provider import FastAPIServiceProvider - -from config.app import AppConfig - -print("Loading Application class...") from fastapi_startkit.application import Application from fastapi_startkit.exceptions import ExceptionHandler from fastapi_startkit.logging.providers import LogProvider from fastapi_startkit.masoniteorm.providers import DatabaseProvider - -class _FallbackHandler: - async def render(self, request, exc): - from fastapi.responses import JSONResponse - return JSONResponse(status_code=500, content={"detail": "Internal Server Error"}) +from config.app import AppConfig +from config.database import DatabaseConfig +from config.logging import LoggingConfig +from providers.console_provider import ConsoleProvider +from providers.fastapi_provider import FastAPIServiceProvider class AppExceptionHandler(ExceptionHandler): def register(self): - self.register_handler(Exception, _FallbackHandler()) - + pass app: Application[AppConfig] = Application( - base_path=str(Path().cwd()), + base_path=Path(__file__).parent.parent, config=AppConfig, providers=[ (LogProvider, LoggingConfig), @@ -35,4 +26,4 @@ def register(self): FastAPIServiceProvider, ], exception_handler=AppExceptionHandler, -) \ No newline at end of file +) diff --git a/example/database-app/routes/api.py b/example/database-app/routes/api.py index 8861e7f6..240d1fa5 100644 --- a/example/database-app/routes/api.py +++ b/example/database-app/routes/api.py @@ -6,4 +6,4 @@ public = Router() public.post("/register/student", student_auth.register) -public.post("/register/teacher", AuthController.register_teacher) \ No newline at end of file +public.post("/register/teacher", AuthController.register_teacher) diff --git a/fastapi_startkit/pyproject.toml b/fastapi_startkit/pyproject.toml index 89d7cfdb..56170227 100644 --- a/fastapi_startkit/pyproject.toml +++ b/fastapi_startkit/pyproject.toml @@ -50,6 +50,13 @@ dev = [ ] +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +select = ["F401"] +fixable = ["F401"] + [tool.pytest.ini_options] asyncio_mode = "auto" diff --git a/fastapi_startkit/src/fastapi_startkit/application.py b/fastapi_startkit/src/fastapi_startkit/application.py index 065dcdbd..c8c6d76d 100644 --- a/fastapi_startkit/src/fastapi_startkit/application.py +++ b/fastapi_startkit/src/fastapi_startkit/application.py @@ -30,12 +30,12 @@ class Application(Container, Generic[TConfig]): ] def __init__( - self, - base_path: str | Path = None, - env=None, - providers=None, - config: Type[TConfig] | None = None, - exception_handler: Type[ExceptionHandler] | None = None, + self, + base_path: str | Path = None, + env=None, + providers=None, + config: Type[TConfig] | None = None, + exception_handler: Type[ExceptionHandler] | None = None, ): super().__init__() @@ -154,7 +154,7 @@ def mount(self, path: str, app_instance: "FastAPI", **kwargs): # Add custom exception handlers def add_exception_handler( - self, exc_class_or_status_code: Any, handler: Callable[..., Any] + self, exc_class_or_status_code: Any, handler: Callable[..., Any] ): self._fastapi.add_exception_handler(exc_class_or_status_code, handler) return self @@ -181,9 +181,9 @@ def load_environment(self): def is_debug(self) -> bool: return ( - hasattr(self, "_config_instance") - and self._config_instance is not None - and getattr(self._config_instance, "debug", False) + hasattr(self, "_config_instance") + and self._config_instance is not None + and getattr(self._config_instance, "debug", False) ) def configure_config(self): diff --git a/fastapi_startkit/src/fastapi_startkit/exceptions/handler.py b/fastapi_startkit/src/fastapi_startkit/exceptions/handler.py index 4310d18d..f7ae5ee6 100644 --- a/fastapi_startkit/src/fastapi_startkit/exceptions/handler.py +++ b/fastapi_startkit/src/fastapi_startkit/exceptions/handler.py @@ -2,7 +2,6 @@ import atexit from typing import Any, Callable, Dict, List, Optional, Type -from dumpdie import dd class ExceptionHandler: diff --git a/fastapi_startkit/src/fastapi_startkit/fastapi/exceptions.py b/fastapi_startkit/src/fastapi_startkit/fastapi/exceptions.py index bdfcbc67..1bce844a 100644 --- a/fastapi_startkit/src/fastapi_startkit/fastapi/exceptions.py +++ b/fastapi_startkit/src/fastapi_startkit/fastapi/exceptions.py @@ -2,6 +2,7 @@ class HTTPExceptionHandler: """ The base exception handler for FastAPI applications. """ + async def render(self, request, exc): import traceback from fastapi.responses import JSONResponse diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py index 0f63c32b..babfdc22 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/MigrateFreshCommand.py @@ -22,7 +22,10 @@ class MigrateFreshCommand(Command): description="The location of the migration directory", ), option( - "no-fk", None, flag=True, description="Re-enable foreign key constraints during drop" + "no-fk", + None, + flag=True, + description="Re-enable foreign key constraints during drop", ), option( "seed", diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/manager.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/manager.py index 3a8d29fd..f081a4dc 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/manager.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/manager.py @@ -1,4 +1,3 @@ -from dumpdie import dd from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -14,7 +13,7 @@ def __init__(self, factory: "ConnectionFactory", config: dict): def connection(self, name: str | None): name = self.get_default_connection_name(name) assert name is not None - config = self.config.get('connections', {}).get(name) + config = self.config.get("connections", {}).get(name) if config is None: raise ValueError(f"Connection '{name}' not found in configuration") diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py index b244c9a3..a12ab4c5 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/mysql_connection.py @@ -17,4 +17,4 @@ def get_default_platform(cls): @classmethod def get_post_processor(cls): - return MySQLPostProcessor \ No newline at end of file + return MySQLPostProcessor diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py index 712b8405..aa9c0c25 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/providers/DatabaseProvider.py @@ -1,4 +1,3 @@ -from dumpdie import dd from pathlib import Path from fastapi_startkit.masoniteorm.commands import ( diff --git a/fastapi_startkit/src/fastapi_startkit/providers/Provider.py b/fastapi_startkit/src/fastapi_startkit/providers/Provider.py index 3fa59ba5..f03982c5 100644 --- a/fastapi_startkit/src/fastapi_startkit/providers/Provider.py +++ b/fastapi_startkit/src/fastapi_startkit/providers/Provider.py @@ -1,5 +1,4 @@ import dataclasses -from dumpdie import dd, dump from typing import TYPE_CHECKING, Any from fastapi_startkit.helpers.string import Str diff --git a/fastapi_startkit/src/fastapi_startkit/vite/providers/provider.py b/fastapi_startkit/src/fastapi_startkit/vite/providers/provider.py index 5b39cb74..cb184f71 100644 --- a/fastapi_startkit/src/fastapi_startkit/vite/providers/provider.py +++ b/fastapi_startkit/src/fastapi_startkit/vite/providers/provider.py @@ -1,6 +1,5 @@ import os -from dumpdie import dd from fastapi_startkit.providers import Provider from ..config.vite import ViteConfig diff --git a/fastapi_startkit/src/fastapi_startkit/vite/vite.py b/fastapi_startkit/src/fastapi_startkit/vite/vite.py index ebcedb02..95155597 100644 --- a/fastapi_startkit/src/fastapi_startkit/vite/vite.py +++ b/fastapi_startkit/src/fastapi_startkit/vite/vite.py @@ -5,7 +5,6 @@ import secrets from typing import Callable, Optional -from dumpdie import dd from .exceptions import ViteException, ViteManifestNotFoundException From 2a2c95a76b50311ad12337282f8b61a6aca59d24 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Wed, 29 Apr 2026 14:46:13 -0700 Subject: [PATCH 4/4] feat: fix by ruff --- .githooks/pre-commit | 2 ++ fastapi_startkit/pyproject.toml | 3 +++ .../src/fastapi_startkit/configuration/Configuration.py | 2 +- fastapi_startkit/src/fastapi_startkit/loader/Loader.py | 1 - .../fastapi_startkit/logging/channels/SingleChannel.py | 2 -- .../fastapi_startkit/logging/channels/SyslogChannel.py | 2 -- .../fastapi_startkit/logging/channels/TerminalChannel.py | 2 -- .../fastapi_startkit/logging/drivers/LogSingleDriver.py | 1 - .../fastapi_startkit/logging/drivers/LogSlackDriver.py | 1 - .../logging/drivers/LogTerminalDriver.py | 2 -- .../fastapi_startkit/logging/providers/log_provider.py | 1 - .../src/fastapi_startkit/masoniteorm.backup/config.py | 1 - .../masoniteorm.backup/testing/Database.py | 1 - .../masoniteorm.backup/tests/integrations/model.py | 2 -- .../masoniteorm/commands/ShellCommand.py | 2 +- .../masoniteorm/connections/connection.py | 3 +-- .../src/fastapi_startkit/masoniteorm/models/builder.py | 1 - .../src/fastapi_startkit/masoniteorm/models/caster.py | 1 - .../src/fastapi_startkit/masoniteorm/models/fields.py | 1 - .../fastapi_startkit/masoniteorm/models/relationship.py | 1 - .../masoniteorm/relationships/BelongsTo.py | 1 - .../fastapi_startkit/masoniteorm/relationships/HasOne.py | 1 - .../masoniteorm/tests/fixtures/factory.py | 1 - .../masoniteorm/tests/models/test_model_attributes.py | 1 - .../masoniteorm/tests/models/test_model_query.py | 1 - .../src/fastapi_startkit/providers/Provider.py | 3 +-- .../tests/configurations/test_config_merge.py | 1 - .../src/fastapi_startkit/utils/structures.py | 2 -- readme.md | 9 +++++++++ 29 files changed, 18 insertions(+), 34 deletions(-) create mode 100755 .githooks/pre-commit diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 00000000..3e760e18 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,2 @@ +#!/bin/sh +cd fastapi_startkit && uvx ruff check --fix src/ diff --git a/fastapi_startkit/pyproject.toml b/fastapi_startkit/pyproject.toml index 56170227..10156f54 100644 --- a/fastapi_startkit/pyproject.toml +++ b/fastapi_startkit/pyproject.toml @@ -57,6 +57,9 @@ line-length = 120 select = ["F401"] fixable = ["F401"] +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["F401"] + [tool.pytest.ini_options] asyncio_mode = "auto" diff --git a/fastapi_startkit/src/fastapi_startkit/configuration/Configuration.py b/fastapi_startkit/src/fastapi_startkit/configuration/Configuration.py index 70e84bf5..ebf8d42a 100644 --- a/fastapi_startkit/src/fastapi_startkit/configuration/Configuration.py +++ b/fastapi_startkit/src/fastapi_startkit/configuration/Configuration.py @@ -1,6 +1,6 @@ from fastapi_startkit.loader import Loader from ..utils.structures import data -from ..exceptions import InvalidConfigurationLocation, InvalidConfigurationSetup +from ..exceptions import InvalidConfigurationSetup class Configuration: diff --git a/fastapi_startkit/src/fastapi_startkit/loader/Loader.py b/fastapi_startkit/src/fastapi_startkit/loader/Loader.py index 7125f005..a292a6f1 100644 --- a/fastapi_startkit/src/fastapi_startkit/loader/Loader.py +++ b/fastapi_startkit/src/fastapi_startkit/loader/Loader.py @@ -2,7 +2,6 @@ import inspect import pkgutil -import os from ..exceptions import LoaderNotFound from ..utils.str import as_filepath diff --git a/fastapi_startkit/src/fastapi_startkit/logging/channels/SingleChannel.py b/fastapi_startkit/src/fastapi_startkit/logging/channels/SingleChannel.py index 09af81a8..a45e366f 100644 --- a/fastapi_startkit/src/fastapi_startkit/logging/channels/SingleChannel.py +++ b/fastapi_startkit/src/fastapi_startkit/logging/channels/SingleChannel.py @@ -1,8 +1,6 @@ from ..factory import DriverFactory from fastapi_startkit.facades import Config from fastapi_startkit.utils.filesystem import make_directory -import os -import pendulum from .BaseChannel import BaseChannel diff --git a/fastapi_startkit/src/fastapi_startkit/logging/channels/SyslogChannel.py b/fastapi_startkit/src/fastapi_startkit/logging/channels/SyslogChannel.py index caeb8e22..a9a1eeb5 100644 --- a/fastapi_startkit/src/fastapi_startkit/logging/channels/SyslogChannel.py +++ b/fastapi_startkit/src/fastapi_startkit/logging/channels/SyslogChannel.py @@ -1,8 +1,6 @@ from ..factory import DriverFactory from fastapi_startkit.facades import Config from fastapi_startkit.utils.filesystem import make_directory -import os -import pendulum from .BaseChannel import BaseChannel diff --git a/fastapi_startkit/src/fastapi_startkit/logging/channels/TerminalChannel.py b/fastapi_startkit/src/fastapi_startkit/logging/channels/TerminalChannel.py index 380b20fb..8e20d69e 100644 --- a/fastapi_startkit/src/fastapi_startkit/logging/channels/TerminalChannel.py +++ b/fastapi_startkit/src/fastapi_startkit/logging/channels/TerminalChannel.py @@ -1,6 +1,4 @@ -import os -import pendulum from fastapi_startkit.facades import Config from ..factory import DriverFactory diff --git a/fastapi_startkit/src/fastapi_startkit/logging/drivers/LogSingleDriver.py b/fastapi_startkit/src/fastapi_startkit/logging/drivers/LogSingleDriver.py index c6648428..bb6bfb72 100644 --- a/fastapi_startkit/src/fastapi_startkit/logging/drivers/LogSingleDriver.py +++ b/fastapi_startkit/src/fastapi_startkit/logging/drivers/LogSingleDriver.py @@ -1,5 +1,4 @@ import logging -import os from .BaseDriver import BaseDriver diff --git a/fastapi_startkit/src/fastapi_startkit/logging/drivers/LogSlackDriver.py b/fastapi_startkit/src/fastapi_startkit/logging/drivers/LogSlackDriver.py index 2e837a4f..257b9f3e 100644 --- a/fastapi_startkit/src/fastapi_startkit/logging/drivers/LogSlackDriver.py +++ b/fastapi_startkit/src/fastapi_startkit/logging/drivers/LogSlackDriver.py @@ -1,4 +1,3 @@ -import os from .BaseDriver import BaseDriver import requests diff --git a/fastapi_startkit/src/fastapi_startkit/logging/drivers/LogTerminalDriver.py b/fastapi_startkit/src/fastapi_startkit/logging/drivers/LogTerminalDriver.py index 446fe6c3..3c929fc8 100644 --- a/fastapi_startkit/src/fastapi_startkit/logging/drivers/LogTerminalDriver.py +++ b/fastapi_startkit/src/fastapi_startkit/logging/drivers/LogTerminalDriver.py @@ -1,7 +1,5 @@ # from logging import Logger -import os -from fastapi_startkit.facades import Config from fastapi_startkit.utils.console import HasColoredOutput from .BaseDriver import BaseDriver diff --git a/fastapi_startkit/src/fastapi_startkit/logging/providers/log_provider.py b/fastapi_startkit/src/fastapi_startkit/logging/providers/log_provider.py index 4363e82e..94e531cf 100644 --- a/fastapi_startkit/src/fastapi_startkit/logging/providers/log_provider.py +++ b/fastapi_startkit/src/fastapi_startkit/logging/providers/log_provider.py @@ -1,4 +1,3 @@ -import os from pathlib import Path from fastapi_startkit.providers import Provider diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm.backup/config.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm.backup/config.py index 459173a5..2d6f2578 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm.backup/config.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm.backup/config.py @@ -1,6 +1,5 @@ import os import pydoc -import sys import urllib.parse as urlparse from .exceptions import ConfigurationNotFound, InvalidUrlConfiguration diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm.backup/testing/Database.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm.backup/testing/Database.py index 02908b40..250368d8 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm.backup/testing/Database.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm.backup/testing/Database.py @@ -1,4 +1,3 @@ -import os from ..config import load_config from ..migrations import Migration from ..seeds import Seeder diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm.backup/tests/integrations/model.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm.backup/tests/integrations/model.py index ca04b543..e1823ef8 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm.backup/tests/integrations/model.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm.backup/tests/integrations/model.py @@ -1,9 +1,7 @@ from dataclasses import dataclass, asdict from enum import StrEnum -from fastapi_startkit.carbon import Carbon from fastapi_startkit.masoniteorm import Model -from fastapi_startkit.masoniteorm.models.fields import Field @dataclass diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/ShellCommand.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/ShellCommand.py index 9cb6a0d0..0a33b466 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/ShellCommand.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/commands/ShellCommand.py @@ -1,4 +1,4 @@ -from cleo.helpers import argument, option +from cleo.helpers import option import os import re import shlex diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/connection.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/connection.py index 2da593b0..7badb0a9 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/connection.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/connections/connection.py @@ -1,7 +1,6 @@ -from typing import Any from sqlalchemy import text -from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine +from sqlalchemy.ext.asyncio import AsyncEngine from fastapi_startkit.masoniteorm.models.builder import QueryBuilder diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/builder.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/builder.py index ba23113c..dc8ae3ad 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/builder.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/builder.py @@ -1,6 +1,5 @@ import inspect -import inflection from typing import TYPE_CHECKING from fastapi_startkit.masoniteorm.expressions.expressions import ( diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/caster.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/caster.py index edb1a264..a78c4e7d 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/caster.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/caster.py @@ -133,7 +133,6 @@ def __init__(self, model: "Model", casts: dict | None = None): @classmethod def build_casts(cls, model): model = model if isinstance(model, type) else model.__class__ - from .registry import Registry from fastapi_startkit.masoniteorm.relationships.BaseRelationship import ( BaseRelationship, ) diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/fields.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/fields.py index 35653383..52ea7f35 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/fields.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/fields.py @@ -1,4 +1,3 @@ -import pendulum from pydantic.fields import FieldInfo from pydantic import Field as BaseField from typing import Any diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/relationship.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/relationship.py index 14dcceb7..0e9da0c5 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/relationship.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/relationship.py @@ -1,4 +1,3 @@ -from fastapi_startkit.masoniteorm.query.EagerRelation import EagerRelations class Relationship: diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/relationships/BelongsTo.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/relationships/BelongsTo.py index d16d8793..b2dfe25a 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/relationships/BelongsTo.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/relationships/BelongsTo.py @@ -1,4 +1,3 @@ -from typing import Callable from ..collection import Collection from . import BaseRelationship diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/relationships/HasOne.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/relationships/HasOne.py index 22297820..cfb966bd 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/relationships/HasOne.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/relationships/HasOne.py @@ -1,4 +1,3 @@ -import inflection from ..collection import Collection from .BaseRelationship import BaseRelationship diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/tests/fixtures/factory.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/tests/fixtures/factory.py index d5841d72..e1ae84e4 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/tests/fixtures/factory.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/tests/fixtures/factory.py @@ -1,4 +1,3 @@ -import faker from fastapi_startkit.orm.factory.factory import Factory from .model import User diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/tests/models/test_model_attributes.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/tests/models/test_model_attributes.py index 23a40420..c14ccfb3 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/tests/models/test_model_attributes.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/tests/models/test_model_attributes.py @@ -194,7 +194,6 @@ def test_query_returns_query_builder(self, UserModel): assert isinstance(builder, QueryBuilder) def test_query_builder_has_model_set(self, UserModel): - from fastapi_startkit.orm.models.builder import QueryBuilder builder = UserModel.query() assert builder._model is not None diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/tests/models/test_model_query.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/tests/models/test_model_query.py index 45815137..db76588e 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/tests/models/test_model_query.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/tests/models/test_model_query.py @@ -11,7 +11,6 @@ from fastapi_startkit.carbon import Carbon from fastapi_startkit.masoniteorm.connections.factory import ConnectionFactory from fastapi_startkit.masoniteorm.connections.manager import DatabaseManager -from fastapi_startkit.masoniteorm.models.builder import QueryBuilder from fastapi_startkit.masoniteorm.models.fields import DateTimeField from fastapi_startkit.masoniteorm.models.model import Model diff --git a/fastapi_startkit/src/fastapi_startkit/providers/Provider.py b/fastapi_startkit/src/fastapi_startkit/providers/Provider.py index f03982c5..7a49873f 100644 --- a/fastapi_startkit/src/fastapi_startkit/providers/Provider.py +++ b/fastapi_startkit/src/fastapi_startkit/providers/Provider.py @@ -1,5 +1,4 @@ -import dataclasses -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from fastapi_startkit.helpers.string import Str diff --git a/fastapi_startkit/src/fastapi_startkit/tests/configurations/test_config_merge.py b/fastapi_startkit/src/fastapi_startkit/tests/configurations/test_config_merge.py index 67772763..d6d1810a 100644 --- a/fastapi_startkit/src/fastapi_startkit/tests/configurations/test_config_merge.py +++ b/fastapi_startkit/src/fastapi_startkit/tests/configurations/test_config_merge.py @@ -1,6 +1,5 @@ from unittest.mock import MagicMock, patch from fastapi_startkits.configuration import Configuration -from fastapi_startkits.loader import Loader class TestConfiguration: diff --git a/fastapi_startkit/src/fastapi_startkit/utils/structures.py b/fastapi_startkit/src/fastapi_startkit/utils/structures.py index 1fc1b0ab..838c95fd 100644 --- a/fastapi_startkit/src/fastapi_startkit/utils/structures.py +++ b/fastapi_startkit/src/fastapi_startkit/utils/structures.py @@ -1,12 +1,10 @@ """Helpers for multiple data structures""" import importlib -from importlib.abc import Loader from dotty_dict import dotty from ..exceptions.exceptions import LoaderNotFound -from .str import modularize def load(path, object_name=None, default=None, raise_exception=False): diff --git a/readme.md b/readme.md index e69de29b..2671c39f 100644 --- a/readme.md +++ b/readme.md @@ -0,0 +1,9 @@ +## Setup + +After cloning, activate the git hooks: + +```sh +git config core.hooksPath .githooks +``` + +This enables the pre-commit hook that runs `ruff check --fix` on the core package before every commit. \ No newline at end of file