| name | myfy-patterns |
| description | Core myfy patterns and conventions for building applications. Use when working with myfy.core, Application, WebModule, DataModule, FrontendModule, TasksModule, UserModule, CliModule, AuthModule, RateLimitModule, or @route decorators. |
myfy Framework Patterns
You are assisting a developer building an application with the myfy Python framework.
Core Principles
- Opinionated, not rigid - Strong defaults, full configurability
- Modular by design - Features are modules (web, data, tasks, frontend)
- Type-safe DI - Constructor injection with compile-time validation
- Async-native - Built on ASGI and AnyIO with contextvars
- Zero-config defaults - Convention over configuration
Imports
Always import from the public API:
from myfy.core import Application, provider, SINGLETON, REQUEST, TASK
from myfy.core import BaseSettings, BaseModule
from myfy.web import WebModule, route, Query, abort, errors
from myfy.web import Authenticated, Anonymous, AuthModule
from myfy.web.ratelimit import RateLimitModule, rate_limit
from myfy.data import DataModule, AsyncSession
from myfy.tasks import TasksModule, task, TaskContext
from myfy.frontend import FrontendModule, render_template
from myfy.user import UserModule
from myfy.commands import CliModule, cli
Application Structure
from myfy.core import Application
from myfy.web import WebModule, route
from myfy.data import DataModule
app = Application(
settings_class=AppSettings,
auto_discover=False,
)
app.add_module(DataModule())
app.add_module(WebModule())
Module Categories
| Module | Package | Purpose |
|---|
| WebModule | myfy-web | HTTP routing, ASGI, FastAPI-like decorators |
| DataModule | myfy-data | SQLAlchemy async, migrations, sessions |
| FrontendModule | myfy-frontend | Jinja2, Tailwind 4, DaisyUI 5, Vite |
| TasksModule | myfy-tasks | Background jobs, SQL-based task queue |
| UserModule | myfy-user | Auth, OAuth, user management |
| CliModule | myfy-commands | Custom CLI commands |
| AuthModule | myfy-web.auth | Type-based authentication, protected routes |
| RateLimitModule | myfy-web.ratelimit | Rate limiting per IP or user |
Key Conventions
- File naming:
app.py, main.py, or application.py for entry point
- Settings: Extend
BaseSettings from myfy.core
- Routes: Use global
route decorator from myfy.web
- Providers: Use
@provider(scope=...) decorator from myfy.core
- Tasks: Use
@task decorator for background jobs
Common Patterns
Creating a Route with DI
from myfy.web import route
from myfy.data import AsyncSession
@route.get("/users/{user_id}")
async def get_user(user_id: int, session: AsyncSession) -> dict:
result = await session.execute(select(User).where(User.id == user_id))
return {"user": result.scalar_one_or_none()}
Creating a Provider
from myfy.core import provider, SINGLETON
@provider(scope=SINGLETON)
def email_service(settings: AppSettings) -> EmailService:
return EmailService(api_key=settings.email_api_key)
Settings Class
from pydantic import Field
from pydantic_settings import SettingsConfigDict
from myfy.core import BaseSettings
class AppSettings(BaseSettings):
app_name: str = Field(default="my-app")
debug: bool = Field(default=False)
database_url: str = Field(default="sqlite+aiosqlite:///./app.db")
model_config = SettingsConfigDict(
env_prefix="MYFY_",
env_file=".env",
)
Error Handling
from myfy.web import abort, errors
abort(404, "User not found")
raise errors.NotFound("User not found")
raise errors.BadRequest("Invalid email", field="email")
When Generating Code
Always:
- Use type hints for all function parameters and return types
- Use async/await for all handlers
- Import from
myfy.* not internal modules
- Follow existing project structure
- Use Pydantic models for request/response bodies