User Tutorial: From Installation to Your First Plugin¶
[!NOTE] This guide walks you step-by-step from installing Structum to creating your first custom plugin.
Prerequisites¶
Python 3.11+ installed
Git installed
uv (modern package manager) - Installation
Part 1: Installation¶
[!IMPORTANT] Structum is in alpha phase (v0.1.0). Installation is from source only.
Step 1.1: Clone the Repository¶
git clone https://github.com/PythonWoods/structum.git
cd structum
Step 1.2: Install with uv¶
uv sync --extra dev
This command:
Creates a virtual environment automatically
Installs all workspace packages in editable mode
Installs development tools (pytest, mypy, ruff)
Step 1.3: Verify Installation¶
# Verify packages are installed
python -c "import structum; print('✓ Structum installed!')"
# Run tests (optional)
pytest packages/core/tests -v
Part 2: First Usage¶
Step 2.1: Create a Test Project¶
mkdir ~/my-structum-app
cd ~/my-structum-app
Step 2.2: Create the Config Structure¶
mkdir -p config/app
Step 2.3: Create a Configuration File¶
File: config/app/database.toml
[default]
host = "localhost"
port = 5432
name = "myapp"
[production]
host = "db.production.example.com"
Step 2.4: Use the Configuration¶
File: main.py
from structum.config import get_config, set_config_provider
from structum.plugins.dynaconf import DynaconfConfigProvider
# Setup provider
provider = DynaconfConfigProvider(root_path=".", env_prefix="MYAPP")
provider.auto_discover()
set_config_provider(provider)
# Use the configuration
config = get_config()
db_host = config.get("database.host", default="localhost")
db_port = config.get("database.port", default=5432)
db_name = config.get("database.name", default="app")
print(f"Database: {db_host}:{db_port}/{db_name}")
Step 2.5: Run¶
python main.py
# Output: Database: localhost:5432/myapp
# With a different environment
STRUCTUM_ENV=production python main.py
# Output: Database: db.production.example.com:5432/myapp
Part 3: Create Your First Plugin¶
Step 3.1: Plugin Structure¶
mkdir -p my_plugin
touch my_plugin/__init__.py my_plugin/provider.py
Step 3.2: Define the Interface (optional)¶
File: my_plugin/__init__.py
"""My Custom Plugin for Structum."""
from .provider import SlackNotificationProvider
__all__ = ["SlackNotificationProvider"]
Step 3.3: Implement the Provider¶
File: my_plugin/provider.py
from typing import Protocol
from dataclasses import dataclass
# 1. Define the protocol (interface)
class NotificationProviderInterface(Protocol):
"""Interface for notification providers."""
def send(self, to: str, message: str) -> bool:
"""Send a notification."""
...
# 2. Implement the provider
@dataclass
class SlackNotificationProvider:
"""Slack implementation of NotificationProvider."""
webhook_url: str
channel: str = "#general"
def send(self, to: str, message: str) -> bool:
"""Send notification to Slack."""
import requests
payload = {
"channel": self.channel,
"text": f"@{to}: {message}"
}
try:
response = requests.post(self.webhook_url, json=payload)
return response.status_code == 200
except Exception:
return False
@classmethod
def from_config(cls) -> "SlackNotificationProvider":
"""Create from Structum config."""
from structum.config import get_config
config = get_config()
return cls(
webhook_url=config.get("notifications.slack.webhook_url"),
channel=config.get("notifications.slack.channel", default="#general")
)
Step 3.4: Configure the Plugin¶
File: config/app/notifications.toml
[default.slack]
webhook_url = "https://hooks.slack.com/services/xxx"
channel = "#alerts"
Step 3.5: Use the Plugin¶
File: main.py
from my_plugin import SlackNotificationProvider
# Initialize from config
notifier = SlackNotificationProvider.from_config()
# Send notification
success = notifier.send("admin", "Deployment completed!")
if success:
print("✓ Notification sent!")
else:
print("✗ Notification failed")
Part 4: Advanced Patterns¶
4.1: Register the Plugin Globally¶
# In your app's __init__.py
from structum.config import set_config_provider
from structum.plugins.dynaconf import DynaconfConfigProvider
from my_plugin import SlackNotificationProvider
# Global singleton
_notifier: SlackNotificationProvider | None = None
def get_notifier() -> SlackNotificationProvider:
"""Get the global notifier instance."""
global _notifier
if _notifier is None:
_notifier = SlackNotificationProvider.from_config()
return _notifier
4.2: Use Dependency Injection¶
from structum.plugins.di import StructumContainer
from dependency_injector import providers
class AppContainer(StructumContainer):
"""Application container with notification provider."""
notifier = providers.Singleton(
SlackNotificationProvider.from_config
)
# Usage
container = AppContainer()
notifier = container.notifier()
notifier.send("user", "Hello!")
Next Steps¶
📖 Read the complete documentation
🔌 Explore available plugins
🏗️ Study the architecture
🤝 Contribute to the project