WebPy is a lightweight Python framework for web development. It provides the tools needed for building web applications and APIs efficiently. This documentation covers the core features, project structure, and essential functionality.
| Feature | Description |
|---|---|
| Fast HTTP Handling | Handle HTTP requests and responses quickly and smoothly. |
| Smart Routing | Set up your routes however you want—it's super flexible. |
| Jinja2 Templates | Build dynamic HTML templates that you can reuse everywhere. |
| Static File Serving | Serve up your CSS, JavaScript, and images with ease. |
| Session Management | Manage user sessions in a way that's both secure and simple. |
| HTTPS Support | Lock down your app with built-in HTTPS support. |
| Error Handling | Create custom error pages that actually look good. |
| Blueprint System | Break your app into smaller, manageable pieces. |
| Middleware System | Run custom logic on requests and responses as they flow through. |
| WebSocket Support | Get real-time, two-way communication working in no time. |
Here's how a typical WebPy project looks when you've got everything organized:
project/
├── static/ # Static files (CSS, JS, images)
│ ├── css/
│ ├── js/
│ └── images/
├── templates/ # Jinja2 templates
├── blueprints/ # App blueprints
├── middleware/ # Custom middleware components
└── app.py # Main app file
Getting started with WebPy is pretty straightforward. Just create an instance of the WebPy class, define where you want your routes to go, and fire up the server with the run() method.
from webpy import WebPy
# Initialize the WebPy application
app = WebPy()
def main() -> None:
"""
Main entry point for the application.
Starts the WebPy server with the specified configuration.
"""
# Start the server on all network interfaces (0.0.0.0) on port 8080
app.run(ip="0.0.0.0", port=8080)
if __name__ == "__main__":
main()WebPy makes dealing with different HTTP methods (like GET, POST, and friends) really easy. You can pull data from requests without jumping through hoops.
from webpy import WebPy
from broadcast import Request, Response
# Initialize the WebPy application
app = WebPy()
@app.route("/api/data", methods=["GET", "POST"])
def data(request: Request, response: Response) -> None:
"""
Handle API requests for the /api/data endpoint.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
Returns:
None: The function modifies the response object directly
"""
if request.method == "GET":
# Extract the "page" query parameter, defaulting to "1" if not provided
page = request.queries.get("page", ["1"])[0]
# Return JSON data with the page number and example data
response.json({"page": page, "data": "example"})
elif request.method == "POST":
# Parse JSON data from the request body
data = request.json()
# Return the received data as an API response
response.api(data)WebPy lets you set up dynamic routes so you can grab variables straight from the URL. It's perfect for things like user IDs or resource identifiers.
from webpy import WebPy
from broadcast import Request, Response
# Initialize the WebPy application
app = WebPy()
@app.route("/users/<id:int>")
def user(request: Request, response: Response, id: int) -> None:
"""
Handle requests for individual user information.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
id: User ID extracted from the URL path
Returns:
None: The function modifies the response object directly
"""
# Return JSON data with the user ID
response.json({"id": id})
@app.route("/resources", methods=["GET", "POST", "PUT", "DELETE"])
def resource(request: Request, response: Response) -> None:
"""
RESTful endpoint handling multiple HTTP methods for resource management.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
Returns:
None: The function modifies the response object directly
"""
# Return the HTTP method used in the request
response.api({"method": request.method})WebPy works great with Jinja2 for templating. This means you can build dynamic HTML pages that adapt to whatever data you throw at them.
<!-- templates/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>Welcome, {{ name }}!</h1>
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
</body>
</html>from webpy import WebPy
from broadcast import Request, Response
# Initialize the WebPy application
app = WebPy()
@app.route("/")
def index(request: Request, response: Response) -> None:
"""
Render the index page with dynamic content.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
Returns:
None: The function modifies the response object directly
"""
# Prepare context data to be passed to the template
context = {
"title": "Home",
"name": "Friend",
"messages": ["Welcome to WebPy!", "Enjoy your development journey!"]
}
# Render the template with the context data
html = app.render("index.html", **context)
# Set the Content-Type header and response body
response.html(html)When your app starts getting bigger, blueprints help you keep things organized. Think of them as a way to group related routes and functionality together so your codebase doesn't turn into a mess.
from webpy import WebPy
from blueprint import Blueprint
from broadcast import Request, Response
# Initialize the WebPy application
app = WebPy()
# Create a blueprint for user-related routes
user = Blueprint("user", prefix="/user")
@user.route("/profile")
def profile(request: Request, response: Response) -> None:
"""
Handle requests for user profile information.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
Returns:
None: The function modifies the response object directly
"""
# Extract the user ID from query parameters, defaulting to "current"
id = request.queries.get("id", ["current"])[0]
# Return JSON data with user information
response.json({"id": id, "name": "John"})
# Create a blueprint for admin-related routes
admin = Blueprint("admin", prefix="/admin")
@admin.route("/dashboard")
def dashboard(request: Request, response: Response) -> None:
"""
Handle requests for the admin dashboard.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
Returns:
None: The function modifies the response object directly
"""
# Return JSON data with dashboard statistics
response.json({"stats": {"users": 1250, "sessions": 37}})
# Add blueprints to the application
app.blueprint(user)
app.blueprint(admin)
if __name__ == "__main__":
# Start the server on port 8080
app.run(port=8080)WebPy's Middleware system lets you process requests and responses as they come in and go out. Here's a quick example showing how you can use it to track user activity.
from webpy import WebPy
from middleware import Middleware
from broadcast import Request, Response
# Initialize the WebPy application
app = WebPy()
# Initialize the middleware
middleware = Middleware(app)
# Create a user logging middleware function
@middleware.before("log")
def log(request: Request, response: Response) -> bool:
"""
Logs when users join the application.
Args:
request: The Request object
response: The Response object
Returns:
bool: Whether to continue processing the request
"""
address = request.ip
print(f"User has joined: {address}")
print(f"User accessed: {request.path}")
return True
# Apply middleware to all routes by default
@app.route("/")
def homepage(request: Request, response: Response) -> None:
"""
Homepage with user logging middleware.
"""
response.json({
"message": "Welcome to the homepage!"
})
if __name__ == "__main__":
# Start the server on port 8080
app.run(port=8080)Nobody likes seeing generic error pages. With WebPy, you can create custom error pages that match your app's style and give users actually helpful information.
from webpy import WebPy
from broadcast import Request, Response
# Initialize the WebPy application
app = WebPy()
@app.error(404)
def not_found(request: Request, response: Response) -> None:
"""
Custom handler for 404 Not Found errors.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
Returns:
None: The function modifies the response object directly
"""
# Set the HTTP status code to 404
response.status = 404
# Return JSON with error information including the requested path
response.json({
"error": "Not Found",
"path": request.path
})
@app.error(500)
def server_error(request: Request, response: Response) -> None:
"""
Custom handler for 500 Internal Server Error.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
Returns:
None: The function modifies the response object directly
"""
# Set the HTTP status code to 500
response.status = 500
# Return JSON with error information
response.json({
"error": "Internal Server Error"
})
if __name__ == "__main__":
# Start the server on port 8080
app.run(port=8080)Security matters, right? WebPy has HTTPS support built right in, so you can secure your app with SSL/TLS without needing to mess around with a bunch of extra configuration.
from webpy import WebPy
# Initialize the WebPy application
app = WebPy()
def main() -> None:
"""
Main entry point for the application.
Starts the WebPy server with HTTPS enabled.
Notes:
The certfile and keyfile parameters specify the paths to the SSL/TLS certificate
and private key files required for HTTPS.
"""
# Start the server on all network interfaces (0.0.0.0) on port 443 (default HTTPS port)
# with SSL/TLS enabled using the specified certificate and key files
app.run(
ip="0.0.0.0",
port=443,
certfile="path/to/cert.pem", # Path to SSL/TLS certificate
keyfile="path/to/key.pem" # Path to private key
)
if __name__ == "__main__":
main()WebPy comes with session management already set up for you. You can track user sessions securely without having to reinvent the wheel.
from webpy import WebPy
from broadcast import Request, Response
from sessions import Sessions
# Initialize the WebPy application
app = WebPy()
# Initialize the Sessions module
sessions = Sessions()
@app.route("/login")
def login(request: Request, response: Response) -> None:
"""
Handle user login and session creation.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
Returns:
None: The function modifies the response object directly
"""
# Add a session variable "id" with value "user123" that expires in 3600 seconds (1 hour)
sessions.add("id", "user123", expires=3600)
# Return a success message
response.api({"message": "Welcome aboard!"})
@app.route("/info")
def info(request: Request, response: Response) -> None:
"""
Retrieve and display session information.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
Returns:
None: The function modifies the response object directly
"""
# Get the session ID, defaulting to "No active session" if not found
id = sessions.get("id", "No active session")
# Return the session ID as JSON
response.json({"id": id})
if __name__ == "__main__":
# Start the server on port 8080
app.run(port=8080)Every web app needs static files. WebPy handles serving your CSS, JavaScript, and images without any fuss.
from webpy import WebPy
from broadcast import Request, Response
# Initialize the WebPy application
app = WebPy()
@app.route("/static/<path:filepath>", methods=["GET"])
def static_files(request: Request, response: Response, filepath: str) -> None:
"""
Serve static files from the static directory.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
filepath: The path to the static file
Returns:
None: The function modifies the response object directly
"""
response.serve(f"static/{filepath}")
if __name__ == "__main__":
# Start the server on port 8080
app.run(port=8080)Want to do something with every request that comes in? Custom middleware is your friend. You can log stuff, check authentication, or do whatever preprocessing you need.
from webpy import WebPy
from middleware import Middleware
from broadcast import Request, Response
# Initialize the WebPy application
app = WebPy()
# Initialize the middleware
middleware = Middleware(app)
# Create a custom middleware function
@middleware.before("log_requests")
def log_requests(request: Request, response: Response) -> bool:
"""
Log all incoming requests.
Args:
request: The Request object
response: The Response object
Returns:
bool: Whether to continue processing the request
"""
print(f"Request received: {request.method} {request.path}")
return True
# Apply middleware to all routes by default
@app.route("/")
def homepage(request: Request, response: Response) -> None:
"""
Homepage with request logging middleware.
"""
response.json({
"message": "Welcome to the homepage!"
})
if __name__ == "__main__":
# Start the server on port 8080
app.run(port=8080)Instead of returning boring JSON errors, you can serve up fully styled HTML error pages that match your app's design.
from webpy import WebPy
from broadcast import Request, Response
# Initialize the WebPy application
app = WebPy()
@app.error(404)
def not_found(request: Request, response: Response) -> None:
"""
Custom handler for 404 Not Found errors.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
Returns:
None: The function modifies the response object directly
"""
# Set the HTTP status code to 404
response.status = 404
# Return a custom error page
response.html("<h1>404 - Page Not Found</h1>")
@app.error(500)
def server_error(request: Request, response: Response) -> None:
"""
Custom handler for 500 Internal Server Error.
Args:
request: The Request object containing all request information
response: The Response object to be populated with the response data
Returns:
None: The function modifies the response object directly
"""
# Set the HTTP status code to 500
response.status = 500
# Return a custom error page
response.html("<h1>500 - Internal Server Error</h1>")
if __name__ == "__main__":
# Start the server on port 8080
app.run(port=8080)Need real-time features? WebPy has WebSocket support baked in. You can set up bidirectional communication between your server and clients using a simple event-driven approach.
from webpy import WebPy
from websocket import WebSocket
from broadcast import Request, Response
import threading
import time
# Initialize the WebPy application
app = WebPy()
# Initialize WebSocket server
ws = WebSocket(app)
@ws.on("message")
def chat(data, client):
"""
Handle incoming chat messages.
Args:
data: Message data from client
client: Client socket object
Returns:
None: Broadcasts message to all connected clients
"""
user = data.get("user", "Anonymous")
text = data.get("text", "")
# Broadcast message to all connected clients
ws.emit("message", {
"user": user,
"text": text,
"timestamp": int(time.time())
})
@ws.on("join")
def join(data, client):
"""
Handle user joining the chat.
Args:
data: Join data from client
client: Client socket object
Returns:
None: Notifies all clients about new user
"""
user = data.get("user", "Anonymous")
# Notify all clients about new user
ws.emit("join", {
"user": user,
"message": f"{user} joined the chat"
})
@ws.on("leave")
def leave(data, client):
"""
Handle user leaving the chat.
Args:
data: Leave data from client
client: Client socket object
Returns:
None: Notifies all clients about user leaving
"""
user = data.get("user", "Anonymous")
# Notify all clients about user leaving
ws.emit("leave", {
"user": user,
"message": f"{user} left the chat"
})
@ws.on("disconnect")
def disconnect(data, client):
"""
Handle client disconnection.
Args:
data: Disconnect data from client
client: Client socket object
Returns:
None: Performs cleanup when client disconnects
"""
print(f"Client disconnected: {client}")
# Client cleanup is handled automatically by the WebSocket server
if __name__ == "__main__":
# Start WebSocket server on port 8081 in a separate thread
thread = threading.Thread(target=ws.run, kwargs={"host": "127.0.0.1", "port": 8081})
thread.daemon = True
thread.start()
# Start HTTP server on port 8080
app.run(port=8080)