π Project Setup GuideΒΆ
π§ Under Construction
This guide is currently being developed with comprehensive setup procedures and troubleshooting tips. More detailed examples and best practices are being added.
Complete guide for setting up new Neuroglia Python Framework projects, from initial creation to deployment-ready applications.
π― OverviewΒΆ
This guide walks you through creating a new Neuroglia project using the Mario's Pizzeria example, covering project structure, dependency management, and initial configuration.
π PrerequisitesΒΆ
Before starting, ensure you have:
- Python 3.9+ installed
- Poetry for dependency management
- Git for version control
- VS Code or preferred IDE
# Verify Python version
python --version # Should be 3.9 or higher
# Install Poetry if not already installed
curl -sSL https://install.python-poetry.org | python3 -
# Verify Poetry installation
poetry --version
ποΈ Creating a New ProjectΒΆ
Option 1: Using PyNeuroctl (Recommended)ΒΆ
# Install the CLI tool
pip install neuroglia-cli
# Create new project from pizzeria template
pyneuroctl new my-pizzeria --template pizzeria
cd my-pizzeria
# Install dependencies
poetry install
# Run the application
poetry run python main.py
Option 2: Manual SetupΒΆ
# Create project directory
mkdir my-pizzeria && cd my-pizzeria
# Initialize Poetry project
poetry init --name my-pizzeria --description "Pizza ordering system"
# Add Neuroglia framework
poetry add neuroglia
# Add development dependencies
poetry add --group dev pytest pytest-asyncio httpx
# Create project structure
mkdir -p src/{api,application,domain,integration}
mkdir -p tests/{unit,integration}
π Project StructureΒΆ
Create the clean architecture structure:
my-pizzeria/
βββ pyproject.toml # Project configuration
βββ main.py # Application entry point
βββ README.md # Project documentation
βββ .env # Environment variables
βββ .gitignore # Git ignore patterns
βββ src/
β βββ __init__.py
β βββ api/ # π API Layer
β β βββ __init__.py
β β βββ controllers/ # REST endpoints
β β βββ dtos/ # Request/response models
β βββ application/ # πΌ Application Layer
β β βββ __init__.py
β β βββ commands/ # Write operations
β β βββ queries/ # Read operations
β β βββ handlers/ # Business logic
β β βββ services/ # Application services
β βββ domain/ # ποΈ Domain Layer
β β βββ __init__.py
β β βββ entities/ # Business entities
β β βββ events/ # Domain events
β β βββ repositories/ # Repository interfaces
β βββ integration/ # π Integration Layer
β βββ __init__.py
β βββ repositories/ # Data access implementations
β βββ services/ # External service integrations
βββ tests/
β βββ __init__.py
β βββ conftest.py # Test configuration
β βββ unit/ # Unit tests
β βββ integration/ # Integration tests
βββ docs/ # Project documentation
βοΈ Configuration SetupΒΆ
1. Environment ConfigurationΒΆ
Create .env file:
# Application Settings
APP_NAME=My Pizzeria
APP_VERSION=1.0.0
DEBUG=true
# Server Configuration
HOST=0.0.0.0
PORT=8000
# Database Configuration
DATABASE_TYPE=mongodb
MONGODB_CONNECTION_STRING=mongodb://localhost:27017/pizzeria
# External Services
SMS_SERVICE_API_KEY=your_sms_api_key
EMAIL_SERVICE_API_KEY=your_email_api_key
PAYMENT_GATEWAY_API_KEY=your_payment_api_key
# Logging
LOG_LEVEL=INFO
LOG_FORMAT=json
2. Project ConfigurationΒΆ
Update pyproject.toml:
[tool.poetry]
name = "my-pizzeria"
version = "1.0.0"
description = "Pizza ordering system built with Neuroglia"
authors = ["Your Name <your.email@example.com>"]
packages = [{include = "src"}]
[tool.poetry.dependencies]
python = "^3.9"
neuroglia = "^0.3.0"
fastapi = "^0.104.0"
uvicorn = "^0.24.0"
motor = "^3.3.0" # MongoDB async driver
pydantic-settings = "^2.0.0"
[tool.poetry.group.dev.dependencies]
pytest = "^7.4.0"
pytest-asyncio = "^0.21.0"
httpx = "^0.25.0"
pytest-cov = "^4.1.0"
black = "^23.0.0"
isort = "^5.12.0"
mypy = "^1.6.0"
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
[tool.black]
line-length = 100
target-version = ['py39']
[tool.isort]
profile = "black"
multi_line_output = 3
line_length = 100
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
π Initial ImplementationΒΆ
1. Application Entry PointΒΆ
Create main.py:
import asyncio
from src.startup import create_app
async def main():
"""Application entry point"""
app = await create_app()
import uvicorn
uvicorn.run(
app,
host="0.0.0.0",
port=8000,
reload=True # Development only
)
if __name__ == "__main__":
asyncio.run(main())
2. Application StartupΒΆ
Create src/startup.py:
from neuroglia.hosting.web import WebApplicationBuilder
from neuroglia.dependency_injection import ServiceCollection
from src.api.controllers.orders_controller import OrdersController
from src.application.handlers.place_order_handler import PlaceOrderHandler
from src.integration.repositories.mongo_order_repository import MongoOrderRepository
async def create_app():
"""Configure and build the application"""
builder = WebApplicationBuilder()
# Configure services
configure_services(builder.services)
# Build application
app = builder.build()
# Configure core services
configure_services(builder)
# Configure middleware
configure_middleware(app)
return app
def configure_services(builder: WebApplicationBuilder):
"""Configure dependency injection"""
# Configure framework services
Mediator.configure(builder, ["application.commands", "application.queries"])
Mapper.configure(builder, ["application.mapping", "api.dtos", "domain.entities"])
# Add SubApp with controllers
builder.add_sub_app(
SubAppConfig(
path="/api",
name="api",
controllers=["src.api.controllers"]
)
)
# Add repositories
builder.services.add_scoped(MongoOrderRepository)
# Add external services
# builder.services.add_scoped(SMSService)
# builder.services.add_scoped(PaymentService)
def configure_middleware(app):
"""Configure application middleware"""
# Add CORS if needed
# app.add_middleware(CORSMiddleware, ...)
# Add authentication if needed
# app.add_middleware(AuthenticationMiddleware, ...)
pass
3. First Domain EntityΒΆ
Create src/domain/entities/order.py:
from dataclasses import dataclass
from decimal import Decimal
from datetime import datetime
from typing import List, Optional
from enum import Enum
from neuroglia.domain import Entity
from src.domain.events.order_events import OrderPlacedEvent
class OrderStatus(Enum):
PENDING = "pending"
CONFIRMED = "confirmed"
PREPARING = "preparing"
READY = "ready"
DELIVERED = "delivered"
CANCELLED = "cancelled"
@dataclass
class OrderItem:
pizza_name: str
size: str
quantity: int
price: Decimal
class Order(Entity):
def __init__(self,
customer_id: str,
items: List[OrderItem],
delivery_address: str,
special_instructions: Optional[str] = None):
super().__init__()
self.customer_id = customer_id
self.items = items
self.delivery_address = delivery_address
self.special_instructions = special_instructions
self.status = OrderStatus.PENDING
self.total = self._calculate_total()
self.created_at = datetime.now(timezone.utc)
self.updated_at = self.created_at
# Raise domain event
self.raise_event(OrderPlacedEvent(
order_id=self.id,
customer_id=customer_id,
total=self.total,
items=items
))
def _calculate_total(self) -> Decimal:
"""Calculate order total with tax"""
subtotal = sum(item.price * item.quantity for item in self.items)
tax = subtotal * Decimal('0.08') # 8% tax
return subtotal + tax
def confirm(self):
"""Confirm the order"""
if self.status != OrderStatus.PENDING:
raise ValueError("Only pending orders can be confirmed")
self.status = OrderStatus.CONFIRMED
self.updated_at = datetime.now(timezone.utc)
4. First Command HandlerΒΆ
Create src/application/handlers/place_order_handler.py:
from dataclasses import dataclass
from typing import List
from neuroglia.mediation import Command, CommandHandler
from neuroglia.core import OperationResult
from src.domain.entities.order import Order, OrderItem
from src.api.dtos.order_dto import OrderDto
@dataclass
class PlaceOrderCommand(Command[OperationResult[OrderDto]]):
customer_id: str
items: List[OrderItem]
delivery_address: str
special_instructions: str = None
class PlaceOrderHandler(CommandHandler[PlaceOrderCommand, OperationResult[OrderDto]]):
def __init__(self, order_repository):
self._repository = order_repository
async def handle_async(self, command: PlaceOrderCommand) -> OperationResult[OrderDto]:
try:
# Create domain entity
order = Order(
customer_id=command.customer_id,
items=command.items,
delivery_address=command.delivery_address,
special_instructions=command.special_instructions
)
# Persist order
await self._repository.save_async(order)
# Return success result
dto = OrderDto(
id=order.id,
customer_id=order.customer_id,
total=order.total,
status=order.status.value,
created_at=order.created_at
)
return self.created(dto)
except Exception as ex:
return self.internal_server_error(f"Failed to place order: {str(ex)}")
5. First ControllerΒΆ
Create src/api/controllers/orders_controller.py:
from fastapi import HTTPException
from neuroglia.mvc import ControllerBase
from classy_fastapi import post
from src.application.handlers.place_order_handler import PlaceOrderCommand
from src.api.dtos.place_order_request import PlaceOrderRequest
from src.api.dtos.order_dto import OrderDto
class OrdersController(ControllerBase):
@post("/orders", response_model=OrderDto, status_code=201)
async def place_order(self, request: PlaceOrderRequest) -> OrderDto:
"""Place a new pizza order"""
command = PlaceOrderCommand(
customer_id=request.customer_id,
items=request.items,
delivery_address=request.delivery_address,
special_instructions=request.special_instructions
)
result = await self.mediator.execute_async(command)
if result.is_success:
return result.data
else:
raise HTTPException(
status_code=result.status_code,
detail=result.error_message
)
π§ͺ Testing SetupΒΆ
1. Test ConfigurationΒΆ
Create tests/conftest.py:
import pytest
from unittest.mock import Mock
from neuroglia.dependency_injection import ServiceCollection
from src.startup import configure_services
@pytest.fixture
def service_collection():
"""Provide a configured service collection for testing"""
services = ServiceCollection()
configure_services(services)
return services
@pytest.fixture
def mock_order_repository():
"""Provide a mocked order repository"""
return Mock()
@pytest.fixture
def sample_order_items():
"""Provide sample order items for testing"""
from src.domain.entities.order import OrderItem
from decimal import Decimal
return [
OrderItem(
pizza_name="Margherita",
size="Large",
quantity=1,
price=Decimal('15.99')
),
OrderItem(
pizza_name="Pepperoni",
size="Medium",
quantity=2,
price=Decimal('12.99')
)
]
2. First Unit TestΒΆ
Create tests/unit/test_place_order_handler.py:
import pytest
from decimal import Decimal
from src.application.handlers.place_order_handler import PlaceOrderHandler, PlaceOrderCommand
class TestPlaceOrderHandler:
def setup_method(self):
self.mock_repository = Mock()
self.handler = PlaceOrderHandler(self.mock_repository)
@pytest.mark.asyncio
async def test_place_order_success(self, sample_order_items):
# Arrange
command = PlaceOrderCommand(
customer_id="123",
items=sample_order_items,
delivery_address="123 Pizza St"
)
# Act
result = await self.handler.handle_async(command)
# Assert
assert result.is_success
assert result.data.customer_id == "123"
self.mock_repository.save_async.assert_called_once()
π Running the ApplicationΒΆ
Development ModeΒΆ
# Install dependencies
poetry install
# Run with hot reload
poetry run python main.py
# Or using uvicorn directly
poetry run uvicorn src.main:app --reload
TestingΒΆ
# Run all tests
poetry run pytest
# Run with coverage
poetry run pytest --cov=src
# Run specific test file
poetry run pytest tests/unit/test_place_order_handler.py -v
Code QualityΒΆ
# Format code
poetry run black src tests
# Sort imports
poetry run isort src tests
# Type checking
poetry run mypy src
π§ Next StepsΒΆ
After basic setup, consider:
- API Development Guide - Add more endpoints
- Testing Guide - Comprehensive testing strategies
- Database Integration Guide - Connect to real databases
- Deployment Guide - Deploy to production
π TroubleshootingΒΆ
Common IssuesΒΆ
Import Errors
Poetry Issues
Missing Dependencies
π Related GuidesΒΆ
- Testing Setup - Comprehensive testing strategies
- API Development - Building REST endpoints
- Database Integration - Data persistence setup
This guide provides the foundation for building production-ready Neuroglia applications using proven architectural patterns. π