Python
Overview
Python runtime functions are the Python server-side runtime capabilities provided by EdgeOne Pages, allowing developers to write backend logic in Python and deploy it in the same project as the frontend page, enabling full-stack application development.
Advantages
Zero-configuration deployment: Automatically generate routes based on the file system without manual configuration of the route table. Just place the Python file in the
cloud-functions directory to automatically map it to an API endpoint.Multi-framework compatibility: Simultaneously support three modes - Handler class, WSGI (Flask/Django), and ASGI (FastAPI/Sanic). Automatic framework detection with no additional configuration required, and different modes can be mixed in the same project.
Intelligent dependency management: Auto-scan
import statements in code to detect dependencies, combine with user requirements.txt for merge and deduplication, support incremental installation and cache optimization, significantly enhance pull speed.
Development Mode
Python functions support various development modes:
Mode | Scenarios | Routing Mode | Framework Dependency |
Handler mode | Simple API, Serverless style | File system route (file as route) | None (pure standard library) |
WSGI framework mode | Complete Web application, RESTful API | Built-in framework routing | Flask,Django |
ASGI framework mode | Complete Web application, RESTful API | Built-in framework routing | FastAPI,Sanic |
Getting Started
Create a new
hello.py in the ./cloud-functions/api directory of your project, and use the following example code to create your first Python function:Basic Example: Handler Class
# ./cloud-functions/api/hello.pyfrom http.server import BaseHTTPRequestHandlerclass handler(BaseHTTPRequestHandler):def do_GET(self):self.send_response(200)self.send_header('Content-Type', 'application/json')self.end_headers()self.wfile.write('{"message": "Hello from Python Functions!"}'.encode('utf-8'))
handler class inherits from BaseHTTPRequestHandler and handles different http requests through methods such as do_GET and do_POST.Advanced Example: Using the Flask Framework
# ./cloud-functions/api/index.pyfrom flask import Flask, jsonify, requestapp = Flask(__name__)@app.route('/users', methods=['GET'])def get_users():return jsonify({'users': [{'id': 1, 'name': 'Alice'},{'id': 2, 'name': 'Bob'}]})@app.route('/users', methods=['POST'])def create_user():data = request.get_json()return jsonify({'message': 'User created', 'user': data}), 201
Note:
When using framework mode, the runtime automatically removes the file routing prefix. For example,
api/index.py corresponds to the routing prefix /api. After removal, the path received by Flask for the request /api/users is /users, so Flask internal routing just needs to define the relative path.Advanced Example: Using the FastAPI Framework
# ./cloud-functions/api/index.pyfrom fastapi import FastAPIapp = FastAPI()@app.get('/items')async def list_items():return {'items': [{'id': 1, 'name': 'Item A'}, {'id': 2, 'name': 'Item B'}]}@app.get('/items/{item_id}')async def get_item(item_id: int):return {'item_id': item_id, 'name': f'Item {item_id}'}@app.post('/items')async def create_item(item: dict):return {'message': 'Item created', 'item': item}
Routing
Python functions generate access routes based on the
/cloud-functions directory structure. You can create subdirectories at any level under the /cloud-functions directory in your project repository. See the following example.Directory Structure Example
...cloud-functions├── api│ ├── index.py│ ├── hello.py│ ├── users│ │ ├── index.py│ │ ├── list.py│ │ └── [id].py│ ├── orders│ │ └── index.py│ └── [[default]].py...
The above directory file structure will generate the following routes after EdgeOne Pages platform construction. These routes map Pages URLs to
/cloud-functions files. When client access the URL, it will trigger the corresponding file code to run:File path | Routing |
/cloud-functions/api/index.py | example.com/api |
/cloud-functions/api/hello.py | example.com/api/hello |
/cloud-functions/api/users/index.py | example.com/api/users |
/cloud-functions/api/users/list.py | example.com/api/users/list |
/cloud-functions/api/users/[id].py | example.com/api/users/:id |
/cloud-functions/api/orders/index.py | example.com/api/orders |
/cloud-functions/api/[[default]].py | example.com/api/* |
Route Match Priority
Routes are matched based on the following priorities (from high to low):
1. Static route: Path priority with exact matching (for example
/api/users/list)2. Single-level dynamic route:
[param] matches one path segment (for example /api/users/[id])3. Multi-level dynamic route (Catch-all):
[[param]] matches one or more path segments (for example /api/[[default]])In routes of the same level, the longer (more specific) the path, the higher priority.
Entry Point Identification
Not all
.py files will be registered as routes. Only Python files containing the following entry flag will generate routes:class handler(BaseHTTPRequestHandler) - Handler class modeapp = Flask(...) / app = FastAPI(...) - Framework instance modeapplication = get_wsgi_application() - Django WSGI mode .py files
excluding entry flags will be deemed as auxiliary modules, will be copied to build artifacts for other entry files to refer, but will not register as standalone routes.Dynamic routing
Python functions support dynamic routing. Use square brackets in the file name or directory name to define dynamic parameters:
Single-level dynamic path
[param]: matches one path segmentMulti-level dynamic path (Catch-all)
[[param]]: matches one or more path segmentsFile path | Routing | Match Example | Whether to Match |
/cloud-functions/api/users/[id].py | example.com/api/users/:id | example.com/api/users/1024 | Yes |
| | example.com/api/users/vip/1024 | No |
| | example.com/api/vip/1024 | No |
/cloud-functions/api/[[default]].py | example.com/api/* | example.com/api/books/list | Yes |
| | example.com/api/1024 | Yes |
| | example.com/v2/vip/1024 | No |
Dynamic Routing Parameter Retrieval
In the Handler class, you can get the request path via
self.path and parse dynamic parameters:# ./cloud-functions/api/users/[id].pyfrom http.server import BaseHTTPRequestHandlerclass handler(BaseHTTPRequestHandler):def do_GET(self):# self.path is the path without the prefix removeduser_id = self.path.strip('/')self.send_response(200)self.send_header('Content-Type', 'application/json')self.end_headers()self.wfile.write(f'{{"user_id": "{user_id}"}}'.encode('utf-8'))
Built-in Routing Framework
When using frameworks such as Flask and FastAPI, routing is divided into file system route and built-in framework routing two layers:
1. File system route (outer layer): Determined by file path, for example
api/index.py → /api2. Framework internal routing (inner layer): Defined by skeleton code, for example
@app.route('/users')The runtime automatically removes the file system routing prefix before transmitting it to the framework. For example:
request path
/api/usersfile system route matching
/api (corresponds to api/index.py)After removing the prefix, the framework received
/usersFlask's
@app.route('/users') match successfulNote:
Internal framework route definitions do not require file system routing prefixes. For example, Flask routes in
api/index.py should be written as @app.route('/users') instead of @app.route('/api/users').Each entry file corresponds to an independent framework instance, and files do not affect each other.
The same
index.py can register multiple framework routes, and at runtime all requests matching the file system routing prefix will be forwarded to the same framework instance.
Function Handlers
Use Function Handlers to create custom request handlers for Pages and define RESTful APIs to implement full-stack applications. The Handler class mode allows rapid development of API interfaces without depending on any framework.
Basic Usage
The Handler class inherits from
BaseHTTPRequestHandler and handles different http requests by implementing methods such as do_GET and do_POST.# ./cloud-functions/api/hello.pyfrom http.server import BaseHTTPRequestHandlerclass handler(BaseHTTPRequestHandler):def do_GET(self):self.send_response(200)self.send_header('Content-Type', 'text/plain')self.end_headers()self.wfile.write('Hello, world!'.encode('utf-8'))
Handling Multiple Request Methods
By implementing methods such as
do_POST, do_PUT, and do_DELETE, you can handle different types of HTTP requests:# ./cloud-functions/api/users/index.pyfrom http.server import BaseHTTPRequestHandlerimport jsonclass handler(BaseHTTPRequestHandler):def do_GET(self):self.send_response(200)self.send_header('Content-Type', 'application/json')self.end_headers()self.wfile.write('{"users": []}'.encode('utf-8'))def do_POST(self):content_length = int(self.headers.get('Content-Length', 0))body = self.rfile.read(content_length).decode('utf-8')data = json.loads(body) if body else {}self.send_response(201)self.send_header('Content-Type', 'application/json')self.end_headers()self.wfile.write(json.dumps({'message': 'Created', 'data': data}).encode('utf-8'))def do_DELETE(self):self.send_response(204)self.end_headers()
Handler Class Properties and Methods
handler class inherits from BaseHTTPRequestHandler and can use the following properties and methods:Attribute/Method | Type | Description |
self.path | str | request path (with query parameter) |
self.command | str | HTTP request method (GET, POST) |
self.headers | dict-like | Request header. |
self.rfile | file | Request body input stream |
self.wfile | file | response body output stream |
self.send_response(code) | method | Send HTTP Status Code |
self.send_header(key, value) | method | Send Response Headers |
self.end_headers() | method | End Response Headers |
Query Parameter Retrieval
# ./cloud-functions/api/search.pyfrom http.server import BaseHTTPRequestHandlerfrom urllib.parse import urlparse, parse_qsclass handler(BaseHTTPRequestHandler):def do_GET(self):# Parse query parametersparsed = urlparse(self.path)query_params = parse_qs(parsed.query)# query_params example: {'name': ['Alice'], 'age': ['25']}name = query_params.get('name', ['Guest'])[0]self.send_response(200)self.send_header('Content-Type', 'application/json')self.end_headers()self.wfile.write(f'{{"hello": "{name}"}}'.encode('utf-8'))
Dependency Management
Automated Dependency Detection
The builder will automatically scan ALL Python files under the
cloud-functions directory for import statements, detect used third-party libraries and add them to the dependency list automatically. Common frameworks and libraries supporting auto-detection include:fastapi, django, sanic, bottle, falcon, httpx, requests, pydantic, sqlalchemy, redis, pymongo, numpy, pandas.Manual Dependency Declaration
If you need to specify an exact version or automatically detect uncovered dependencies, you can place
requirements.txt in the following location:1.
cloud-functions/requirements.txt (prioritize)2. project root directory
requirements.txt# cloud-functions/requirements.txtflask>=2.0.0redis>=4.0.0openai>=1.0.0
During the build, basic dependencies, automatically detected dependencies, and user claims will be merged and deduplicated. The version explicitly declared by the user has the highest priority.
Exclude Directories
The following directories will not be scanned and copied to build artifacts:
__pycache__,.git,node_modulesvenv,.venv (virtual environment)scripts (local test script)tests,.pytest_cache (test file)
Sample Template
Python Handler template:
preview address: https://python-handler-template.edgeone.app
Source code address: https://github.com/TencentEdgeOne/python-handler-template
Use FastApi framework:
preview address: https://python-fastapi-template.edgeone.app
Source code address: https://github.com/TencentEdgeOne/python-fastapi-template
Use Flask framework:
preview address: https://python-flask-template.edgeone.app
Source code address: https://github.com/TencentEdgeOne/python-flask-template
Use Django framework:
preview address: https://python-django-template.edgeone.app
Source code address: https://github.com/TencentEdgeOne/python-django-template