Unfazed App System¶
Unfazed organizes code into apps — self-contained Python packages that each provide a piece of your project's functionality. Every app registers itself through a BaseAppConfig subclass, and the framework's AppCenter loads them all at startup. This modular structure keeps large projects maintainable and makes it easy to share or reuse components.
Quick Start¶
1. Create an app¶
This generates a simple app skeleton:
myapp/
├── app.py
├── endpoints.py
├── models.py
├── routes.py
├── schema.py
├── serializers.py
├── settings.py
├── admin.py
└── test_all.py
For a more structured layout with sub-packages, use the standard template:
2. Write the AppConfig¶
Every app must have an app.py file containing an AppConfig class that extends BaseAppConfig:
# myapp/app.py
from unfazed.app import BaseAppConfig
class AppConfig(BaseAppConfig):
async def ready(self) -> None:
pass
3. Register the app¶
Add the app's module path to INSTALLED_APPS in your project settings:
When the server starts, Unfazed will import myapp, find myapp.app.AppConfig, and call its ready() hook.
App Structure¶
An app is any Python package that contains an app.py with an AppConfig class. Beyond that requirement, you are free to organize files however you like. The conventional layout is:
| File / Directory | Purpose |
|---|---|
app.py |
Required. Contains the AppConfig class. |
models.py |
Tortoise ORM model definitions. |
endpoints.py |
Request handler functions or classes. |
routes.py |
URL route declarations. |
serializers.py |
Pydantic-based serializers for request/response validation. |
settings.py |
App-level settings — auto-imported at startup via the wakeup mechanism. |
admin.py |
Admin panel registration. |
commands/ |
Custom CLI commands (see Command Discovery). |
The ready() Hook¶
The ready() method is an async lifecycle hook called once during startup, right after the app is loaded. Use it for one-time initialization such as populating caches, registering signal handlers, or logging startup information.
# myapp/app.py
from unfazed.app import BaseAppConfig
class AppConfig(BaseAppConfig):
async def ready(self) -> None:
print(f"{self.name} is ready")
The startup sequence for each app is:
- Import the app module.
- Import
app.pyand locateAppConfig. - Instantiate
AppConfig. - Call
await app_config.ready(). - Auto-import
settings.pyif it exists (wakeup mechanism). - Store the app in the registry.
Because ready() is awaited, you can perform async work (database queries, HTTP calls, etc.) inside it.
Command Discovery¶
If your app has a commands/ directory, Unfazed automatically discovers all Python files in it (excluding files that start with _) and registers them as CLI commands.
Each command file must define a Command class. See the Command documentation for details on writing custom commands.
API Reference¶
BaseAppConfig¶
Abstract base class for application configuration. Subclass this and implement ready().
Properties:
app_path -> Path: Absolute filesystem path to the app's directory.name -> str: Fully qualified module name (e.g."myapp").label -> str: Module name with dots replaced by underscores (e.g."my_app").
Methods:
async ready() -> None: Abstract. Called once at startup — put your initialization logic here.list_command() -> List[Command]: Discovers command files in the app'scommands/directory.has_models() -> bool: ReturnsTrueif the app has amodelssubmodule.wakeup(filename: str) -> bool: Imports a submodule by name; returnsTrueon success,Falseif not found.from_entry(entry: str, unfazed: Unfazed) -> BaseAppConfig(classmethod): Factory that loads an app from a dotted module path. RaisesImportError,ModuleNotFoundError,AttributeError, orTypeErrorif the entry is invalid.
AppCenter¶
Central registry that manages all installed apps. You typically don't interact with it directly — the framework creates one internally from your INSTALLED_APPS setting.
Methods:
async setup() -> None: Loads and initializes every app ininstalled_apps. RaisesRuntimeErrorif a duplicate app path is detected.load_app(app_path: str) -> BaseAppConfig: Loads a single app without callingready().
Container operations:
app_center["myapp"]— get an app by module name (KeyErrorif missing)."myapp" in app_center— check if an app is registered.for name, config in app_center— iterate over all registered apps.app_center.store— the underlyingDict[str, BaseAppConfig].