2.9 KiB
2.9 KiB
| name | description |
|---|---|
| dspy-patterns | Use when writing DSPY. sqlor, Python bools, IN lists. |
DSPY File Writing Patterns
Python vs JSON boolean
Use Python True/False, not JSON true/false:
{"autoplay": True} # CORRECT
{"autoplay": true} # NameError
sqlor %% escaping
"WHERE x LIKE '%%pattern%%'" → SQL: WHERE x LIKE '%pattern%'
sqlor IN lists
Some sqlor versions fail on ${ids}$ list expansion. Use manual SQL:
id_list = ','.join(["'" + str(x) + "'" for x in ids])
sql = "WHERE id IN (" + id_list + ")"
URL in widgets
Use entire_url() for full URLs:
media_url = entire_url(safe_url(path))
# "/idfile/44/file.mp4" → "https://host/idfile/44/file.mp4"
Debug silent failures
Replace except Exception: pass with:
except Exception as e:
return {"widgettype":"Text","options":{"text":f"ERR:{e}"}}
f-string 禁止(CRITICAL)
DSPY 文件在受限的 exec() 命名空间中执行。f-string 在 dict 字面量中会导致语法错误:
# ❌ SyntaxError: '{' was never closed
return {"widgettype": "Text", "options": {"otext": f'算力池: {n} 个'}}
# ❌ unittest string literal
return {'widgettype': 'Text', 'options': {'otext': f'存储: {total}GB'}}
# ✅ 使用字符串拼接
return {"widgettype": "Text", "options": {"otext": '算力池: ' + str(n) + ' 个'}}
错误日志特征:except=unterminated string literal (detected at line X)
返回 FileResponse 提供文件下载/媒体流
DSPY 可直接返回 aiohttp FileResponse 服务任意文件系统路径,因为 BaseProcessor.handle() 检查 isinstance(self.content, StreamResponse) 直接返回,绕过 JSON 序列化:
import os
from urllib.parse import quote
from aiohttp.web_fileresponse import FileResponse
full_path = ws_dir + '/' + file_id # 任意绝对路径,不必在 FileStorage
# 路径穿越校验
real_ws = os.path.realpath(ws_dir)
real_full = os.path.realpath(full_path)
if not real_full.startswith(real_ws + os.sep):
return {"widgettype": "Message", "options": {"title": "错误", "message": "非法路径"}}
headers = {}
if download:
filename = os.path.basename(full_path)
headers['Content-Disposition'] = 'attachment; filename="%s"; filename*=UTF-8\'\'%s' % (filename, quote(filename))
return FileResponse(full_path, headers=headers)
- 无
download参数 → 流式返回,FileResponse自动探测 MIME。VideoPlayer/AudioPlayer/Image的url直接指向此 DSPY(entire_url("/module/api/file.dspy") + "?id=" + quote(rel_path))。 download=1→Content-Disposition: attachment触发浏览器下载(office/pdf 下载后本地应用打开)。- 对比
idfile(只服务 FileStorage)的优势:可服务任意目录(如项目工作区),不受FileStorage.realPath的 root 限制。