问题现象与背景
在Python异步Web开发中,uvicorn作为高性能ASGI服务器被广泛使用。get_factory()方法负责将用户提供的应用工厂转换为可调用对象,但开发者常会遇到以下报错:
Traceback (most recent call last):
File "main.py", line 15, in module
server = uvicorn.Server(config)
File "/uvicorn/server.py", line 60, in __init__
self.app_factory = get_factory(app)
TypeError: 'NoneType' object is not callable
根本原因分析
该错误表明ASGI应用工厂未被正确初始化,具体可能由以下情况导致:
- 工厂函数未返回可调用对象:应用工厂返回了None而非ASGI应用实例
- 路径引用错误:使用字符串模块路径时导入失败(如
"module:app_factory"格式错误) - 依赖注入缺失:工厂函数需要未提供的参数(数据库连接、配置对象等)
- 生命周期事件冲突:在
lifespan事件处理中意外返回None
解决方案
方案1:验证工厂函数返回值
确保工厂函数返回有效的ASGI可调用对象:
# 正确的工厂模式示例
def create_app():
from fastapi import FastAPI
app = FastAPI()
return app # 必须返回ASGI兼容对象
方案2:检查模块导入语法
使用字符串路径时需确认:
- 模块文件存在且可导入
- 目标函数/类与路径声明一致(如
"module:create_app") - PYTHONPATH包含模块所在目录
方案3:实现参数化工厂
对于需要参数的工厂,使用闭包或functools.partial:
from functools import partial
def app_factory(config):
app = FastAPI()
app.state.config = config
return app
# 在uvicorn配置中
config.app = partial(app_factory, config=settings)
深度优化建议
| 场景 | 检查点 | 工具推荐 |
|---|---|---|
| 复杂依赖 | 依赖项是否在工厂外初始化 | pytest-dependency |
| 异步环境 | 工厂是否包含未await的协程 | aiocontextvars |
预防措施
通过单元测试提前发现问题:
# 工厂函数测试用例示例
def test_app_factory():
app = create_app()
assert callable(app), "工厂必须返回可调用ASGI应用"
# 模拟ASGI接口调用
scope = {"type": "http"}
async def receive(): return {}
async def send(*args): pass
import asyncio
asyncio.run(app(scope, receive, send))