๐ฆ Fennec - A lightweight, fast, and agile Python backend framework built in Tunisia
Project description
Fennec ๐ฆ
A lightweight, fast, and agile Python backend framework
Named after the Fennec fox - small, swift, and adaptable
Built with โค๏ธ in Tunisia ๐น๐ณ
๐ Quick Start
# Install Fennec
pip install fennec-framework
# Create your first API
from fennec import Application
app = Application(title="My API")
@app.get("/")
async def hello():
return {"message": "Hello from Fennec! ๐ฆ"}
# Run with: uvicorn main:app --reload
โจ Features
A modular, async-first Python framework for building REST APIs with minimal dependencies.
Core Features
Core Features
- ๐ Async/Await Support: Built from the ground up with async/await
- ๐ Modular Architecture: Use only what you need
- โ Automatic Validation: Type-hint based validation
- ๐ Auto Documentation: OpenAPI/Swagger generation
- ๐งช Testing Utilities: Easy-to-use test client
- ๐ ๏ธ CLI Tools: Project scaffolding and management commands
- ๐ Dependency Injection: Clean dependency management
- ๐ฏ Middleware System: Flexible request/response processing
- ๐ฅ๏ธ GUI Client: Beautiful Tkinter desktop application included!
v0.2.0 Features
- ๐ WebSocket Support: Real-time bidirectional communication
- ๐ GraphQL Support: Flexible API queries with GraphiQL interface
- ๐ Enhanced Security: Password hashing, CSRF protection, input sanitization
- ๐๏ธ Database Integration: PostgreSQL and MongoDB examples
- ๐๏ธ Microservices: API Gateway pattern and service decomposition
- ๐ OAuth2 Authentication: Complete authorization code flow
- ๐ณ Docker Ready: Production deployment examples
v0.3.0 Features (Production-Grade)
- ๐ Redis Caching: High-performance caching with decorators and strategies
- ๐๏ธ Database Migrations: Version-controlled schema management
- ๐ Monitoring Tools: Prometheus metrics, distributed tracing, structured logging
- ๐๏ธ Admin Dashboard: Real-time monitoring and management interface
- ๐จ Message Queues: Async task processing with Redis, RabbitMQ, AWS SQS
- โก gRPC Support: High-performance RPC for microservices
Why Fennec?
Named after the Fennec fox ๐ฆ - the smallest, fastest, and most adaptable fox species native to the Sahara Desert and Tunisia. Just like the Fennec fox, our framework is:
- ๐ฆ Small & Lightweight: Minimal dependencies, maximum efficiency
- โก Fast & Agile: Async/await throughout for blazing performance
- ๐ Adaptable: Works for any project size, from MVP to enterprise
- ๐ง Smart: Elegant design with powerful features
- ๐น๐ณ Tunisian Pride: Built with โค๏ธ in Tunisia
Installation
pip install fennec-framework uvicorn
Quick Start
Create Your First API
from fennec import Application, Router, JSONResponse
# Create application
app = Application(title="My API", version="1.0.0")
router = Router()
# Define routes
@router.get("/")
async def root():
return JSONResponse(data={"message": "Hello World!"})
@router.get("/users/{id}")
async def get_user(id: int):
return JSONResponse(data={"id": id, "name": "John Doe"})
# Include router
app.include_router(router)
# Run with: uvicorn main:app
With Validation
from fennec.validation import BaseModel, Field
class User(BaseModel):
name: str = Field(min_length=2, max_length=50)
email: str
age: int
def validate_age(self, value):
if value < 0:
raise ValueError("Age must be positive")
return value
@router.post("/users")
async def create_user(request):
data = await request.json()
user = User(**data) # Automatic validation
return JSONResponse(data=user.dict(), status_code=201)
With Middleware
from fennec.security import CORSMiddleware, RateLimitMiddleware
# Add CORS
app.middleware_manager.add(CORSMiddleware(allow_origins=["*"]))
# Add rate limiting
app.middleware_manager.add(RateLimitMiddleware(max_requests=100, window_seconds=60))
# Custom middleware
@app.middleware("http")
async def log_requests(request, call_next):
print(f"Request: {request.method} {request.path}")
response = await call_next(request)
return response
With Dependency Injection
from fennec.dependencies import Depends
def get_db():
return {"users": []}
@router.get("/users")
async def list_users(db=Depends(get_db)):
return JSONResponse(data={"users": db["users"]})
With Authentication
from fennec.security import JWTHandler, requires_auth
jwt = JWTHandler(secret_key="your-secret-key")
@router.post("/login")
async def login(request):
data = await request.json()
# Verify credentials...
token = jwt.encode({"user_id": 1, "username": data["username"]})
return JSONResponse(data={"token": token})
@router.get("/protected")
@requires_auth
async def protected_route(request):
return JSONResponse(data={"message": "You are authenticated!"})
CLI Tools
Create New Project
python -m fennec.cli startproject myproject
cd myproject
python -m app.main
Create New Module
python -m fennec.cli create:module users
Run Development Server
python -m fennec.cli runserver --host=0.0.0.0 --port=8000
API Documentation
The framework automatically generates OpenAPI/Swagger documentation for your API.
Visit http://localhost:8000/docs to see interactive API documentation.
Testing
import asyncio
from fennec.testing import TestClient
from main import app
async def test_api():
client = TestClient(app)
# Test GET request
response = await client.get("/users/1")
assert response.status_code == 200
assert response.json()["data"]["id"] == 1
# Test POST request
response = await client.post("/users", json_data={
"name": "John",
"email": "john@example.com",
"age": 30
})
assert response.status_code == 201
asyncio.run(test_api())
Project Structure
myproject/
โโโ app/
โ โโโ __init__.py
โ โโโ main.py # Application entry point
โ โโโ routers/ # Route handlers
โ โ โโโ __init__.py
โ โ โโโ users.py
โ โโโ models/ # Data models
โ โ โโโ __init__.py
โ โ โโโ user.py
โ โโโ services/ # Business logic
โ โ โโโ __init__.py
โ โ โโโ user_service.py
โ โโโ db/ # Database layer
โ โโโ __init__.py
โ โโโ repositories.py
โโโ tests/
โ โโโ test_users.py
โโโ README.md
Core Concepts
Application
The main application class that manages the lifecycle and ASGI interface.
app = Application(title="My API", version="1.0.0", docs_enabled=True)
Router
Manages routes and URL mapping.
router = Router(prefix="/api/v1")
@router.get("/users")
async def list_users():
return JSONResponse(data={"users": []})
app.include_router(router)
Request & Response
@router.post("/data")
async def handle_data(request):
# Get JSON body
data = await request.json()
# Get headers
auth = request.headers.get("authorization")
# Get path parameters
user_id = request.path_params.get("id")
# Get query parameters
page = request.query_params.get("page", 1)
return JSONResponse(
data={"result": "success"},
message="Data processed",
status_code=200
)
Validation
from fennec.validation import BaseModel, Field
class Product(BaseModel):
name: str = Field(min_length=1, max_length=100)
price: float
quantity: int = Field(default=0, required=False)
def validate_price(self, value):
if value < 0:
raise ValueError("Price must be positive")
return value
Middleware
from fennec.middleware import Middleware
class CustomMiddleware(Middleware):
async def __call__(self, request, call_next):
# Pre-processing
request.custom_data = "something"
# Call next middleware/handler
response = await call_next(request)
# Post-processing
response.headers["X-Custom"] = "value"
return response
app.middleware_manager.add(CustomMiddleware())
Exception Handling
from fennec.exceptions import HTTPException
class CustomException(HTTPException):
def __init__(self):
super().__init__(418, "I'm a teapot")
@app.exception_handler(CustomException)
async def handle_custom(request, exc):
return JSONResponse(
message=exc.message,
status="error",
status_code=exc.status_code
)
WebSocket Support (v0.2.0)
Build real-time applications with WebSocket support:
from fennec import Application, WebSocketRouter, WebSocket, WebSocketManager
app = Application()
ws_router = WebSocketRouter()
ws_manager = WebSocketManager()
@ws_router.websocket("/ws/chat/{room}")
async def chat_room(websocket: WebSocket, room: str):
await websocket.accept()
client_id = await ws_manager.connect(websocket)
ws_manager.join_room(client_id, room)
try:
while True:
message = await websocket.receive_text()
await ws_manager.broadcast(message, room=room)
finally:
await ws_manager.disconnect(client_id)
app.include_websocket_router(ws_router)
GraphQL Support (v0.2.0)
Create flexible GraphQL APIs:
from fennec import Application, GraphQLEngine, query, mutation
app = Application()
gql = GraphQLEngine()
# Define schema
schema = """
type User {
id: ID!
name: String!
email: String!
}
type Query {
users: [User!]!
user(id: ID!): User
}
type Mutation {
createUser(name: String!, email: String!): User!
}
"""
gql.set_schema(schema)
# Define resolvers
@query("users")
async def resolve_users(parent, info):
return get_all_users()
@mutation("createUser")
async def resolve_create_user(parent, info, name: str, email: str):
return create_user(name, email)
# Add GraphQL endpoint with GraphiQL interface
app.add_graphql("/graphql", gql, graphiql=True)
Enhanced Security (v0.2.0)
Production-ready security features:
from fennec.security import (
PasswordHasher,
SecurityHeadersMiddleware,
CSRFMiddleware,
InputSanitizer,
EnhancedJWTHandler
)
# Password hashing with bcrypt
hashed = PasswordHasher.hash("password123")
is_valid = PasswordHasher.verify("password123", hashed)
# Security headers
app.middleware_manager.add(SecurityHeadersMiddleware())
# CSRF protection
app.middleware_manager.add(CSRFMiddleware(secret_key="your-secret"))
# Input sanitization
clean_html = InputSanitizer.sanitize_html(user_input)
email = InputSanitizer.validate_email(email_input)
# Enhanced JWT with refresh tokens
jwt = EnhancedJWTHandler(secret_key="your-secret")
access_token = jwt.create_access_token({"user_id": 1})
refresh_token = jwt.create_refresh_token({"user_id": 1})
new_token = jwt.refresh_access_token(refresh_token)
Redis Caching (v0.3.0)
Boost performance with Redis caching:
from fennec.cache import RedisCache, cache, CacheAside
# Initialize cache
redis_cache = RedisCache(url="redis://localhost:6379")
# Use decorator for automatic caching
@cache(ttl=300, backend=redis_cache)
async def get_expensive_data(user_id: int):
# This result will be cached for 5 minutes
return await database.query(user_id)
# Use cache-aside pattern
cache_aside = CacheAside(redis_cache, ttl=600)
async def get_user(user_id: int):
return await cache_aside.get(
f"user:{user_id}",
lambda: database.get_user(user_id)
)
Database Migrations (v0.3.0)
Manage database schema changes:
from fennec.migrations import MigrationManager
# Initialize migration manager
manager = MigrationManager(connection, migrations_dir="migrations")
# Create migration
await manager.create("add users table", migration_type="python")
# Apply migrations
await manager.migrate()
# Rollback
await manager.rollback(steps=1)
# Check status
status = await manager.status()
Monitoring & Observability (v0.3.0)
Production-ready monitoring:
from fennec.monitoring import PrometheusMetrics, RequestTracer, StructuredLogger
# Prometheus metrics
metrics = PrometheusMetrics(app_name="my_app")
app.add_middleware(MetricsMiddleware(metrics))
# Distributed tracing
tracer = RequestTracer(service_name="my_app")
app.add_middleware(TracingMiddleware(tracer))
# Structured logging
logger = StructuredLogger(name="my_app")
logger.info("User logged in", user_id=123, ip="192.168.1.1")
# Expose metrics endpoint
@app.get("/metrics")
async def metrics_endpoint(request):
return Response(metrics.generate_metrics(), content_type=metrics.get_content_type())
Admin Dashboard (v0.3.0)
Web-based monitoring interface:
from fennec.admin import AdminDashboard
# Initialize admin dashboard
admin = AdminDashboard(
app,
auth_required=True,
prefix="/admin"
)
# Access dashboard at http://localhost:8000/admin
# View real-time metrics, system health, and request logs
Message Queues (v0.3.0)
Async task processing:
from fennec.queue import QueueManager, Worker
# Initialize queue manager
queue = QueueManager(backend="redis", connection_url="redis://localhost:6379")
# Define tasks
@queue.task(queue_name="emails", max_retries=3)
async def send_email(to: str, subject: str, body: str):
await email_service.send(to, subject, body)
# Enqueue task
await send_email("user@example.com", "Hello", "Welcome!")
# Start worker
worker = Worker(queue, queue_names=["emails"], concurrency=4)
await worker.start()
gRPC Support (v0.3.0)
High-performance microservices:
from fennec.grpc import GRPCServer, GRPCClient
# Server
server = GRPCServer(host="0.0.0.0", port=50051)
server.add_service(UserServiceStub, UserServicer())
await server.start()
# Client
client = GRPCClient(host="localhost", port=50051)
await client.connect()
response = await client.call(
UserServiceStub,
'GetUser',
GetUserRequest(id=1)
)
Examples
Check the examples/ directory for complete working examples:
v0.1.0 Examples
- simple_api: Basic CRUD API with validation and middleware
v0.2.0 Examples
- websocket_chat: Real-time chat application with rooms
- graphql_api: GraphQL API with queries and mutations
- microservices: API Gateway with user and order services
- database_integration: PostgreSQL and MongoDB examples
- oauth2_auth: OAuth2 authorization code flow
- deployment: Docker, docker-compose, and cloud deployment
v0.3.0 Examples
- caching_example: Redis caching with decorators and strategies
- migration_example: Database migration workflow
- monitoring_setup: Prometheus, tracing, and logging
- admin_dashboard: Real-time monitoring interface
- message_queue: Async task processing with workers
- grpc_service: gRPC microservice with Protocol Buffers
โ ๏ธ Security Notice
This framework is currently suitable for development and testing only.
Before deploying to production, please read:
- ๐ Production Readiness Guide - Complete roadmap to production
- ๐ Security Assessment - Current security status
- ๐ก๏ธ Security Improvements - Step-by-step hardening guide
Estimated time to production-ready: 1-2 days of security hardening.
Quick Links
- ๐ฆ Meet Fennec - Learn about the framework and the fox!
- ๐ Welcome Guide - New to Fennec? Start here!
- ๐ Quick Start Guide - Get started in 5 minutes
- ๐ How to Run - Step-by-step running instructions
- ๐ฅ๏ธ GUI Client Guide - Desktop GUI application
- ๐ OpenAPI Documentation Guide - How to document your API
- ๐ Security Assessment - Security status and recommendations
- ๐ก๏ธ Security Improvements - How to harden for production
- ๐จ Branding Guide - Logo, colors, and brand guidelines
- ๐ Project Summary - Complete project overview
- ๐ค Contributing - Contribution guidelines
- ๐ Changelog - Version history
Requirements
- Python 3.8+
- uvicorn (for running the server)
Development
# Install in development mode
pip install -e .
# Run quick test
python test_framework.py
# Run example (Method 1: with PYTHONPATH)
PYTHONPATH=$PWD python examples/simple_api/main.py
# Run example (Method 2: with script)
./run_example.sh
# Visit API documentation
# http://localhost:8001/docs
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License
About Fennec
The Name
Fennec (Vulpes zerda) is the smallest fox species, native to the Sahara Desert and North Africa, including Tunisia ๐น๐ณ. Known for their:
- Large ears (excellent for hearing - like our great error messages!)
- Small size (lightweight and efficient)
- Speed and agility (async performance)
- Adaptability (works in any environment)
The Mission
To provide developers with a simple, fast, and powerful framework that doesn't get in the way. We believe in:
- Simplicity over complexity
- Performance over features
- Developer experience over everything
Made in Tunisia ๐น๐ณ
Proudly built in Tunisia, showcasing North African tech talent to the world.
Credits
Created by: Ghassen (Tunisia ๐น๐ณ) Inspired by: The Fennec fox, native to the Sahara Desert Built with: โค๏ธ, Python, and lots of coffee
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fennec_framework-0.3.0.tar.gz.
File metadata
- Download URL: fennec_framework-0.3.0.tar.gz
- Upload date:
- Size: 135.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b70320d6e94ca163a3dd9ac6c57afe98cee49315e35ebea5e893fa06682e2b4c
|
|
| MD5 |
90e5c9eac4f64251bc6d03b17e393ed0
|
|
| BLAKE2b-256 |
df27052b409b5dbddcd15a7062254dd6ac83ea7aacaf798e777ed18ff7079af2
|
File details
Details for the file fennec_framework-0.3.0-py3-none-any.whl.
File metadata
- Download URL: fennec_framework-0.3.0-py3-none-any.whl
- Upload date:
- Size: 85.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
515aacd23a966e919e54b03134be95bb63dee70d44ceabbad01522a5bd7a4d29
|
|
| MD5 |
0a329ad08bf98024b65c164f7ab0a3c6
|
|
| BLAKE2b-256 |
410e1056f8c1f263e87e97b8cd03004afa146d9d5da2d4f1f595e87ef7331dac
|