Files
OnlineJudge/problem/utils.py
yuetsh 085110544d chore: 再清 6 处零引用的函数/类(-47 行)
utils/tasks.py            整个文件(delete_files)
  utils/async_helpers.py    async_cache_delete
  problem/utils.py          build_problem_template
  utils/shortcuts.py        build_query_string
  achievement/checker.py    get_or_create_stat
  problem/serializers.py    TemplateSerializer

delete_files 的唯一调用者是上一个 commit 删掉的 DownloadContestSubmissions
(`delete_files.send_with_options(args=(zip_path,), delay=300_000)`,生成 zip 后
延时清理)。django_dramatiq 按约定自动发现各 app 的 tasks.py,缺一个文件不报错,
已实跑确认 judge / achievement / flowchart 三处的 actor 都还在。

## 扫出来但**不能删**的,记在这里免得下次又查一遍

**achievement/metrics.py 的 18 个指标类**:静态扫描报"零引用",因为类名确实
从不被引用 —— 它们靠 `@metric(key, name)` 装饰器在**定义时**注册进
METRIC_REGISTRY。删掉会静默丢掉成就维度,而且不报错。运行时确认注册表里
18 个一个不少。

**async_cache_get / async_cache_set**:各 6 处引用,只有 delete 那个是死的。
**parse_problem_template**:5 处引用,和被删的 build_problem_template 只是名字像。

**User 模型上的 open_api / open_api_appkey / two_factor_auth / session_keys**:
删字段要迁移,会改生产库结构 —— 而新后端正是靠"库结构与旧后端逐列一致"才能
回滚(阶段 5 演练验证过)。切换完成之前不动。

## 验证

manage.py check 通过;起本地 Django + PostgreSQL 实跑 14 个端点全部 200
(前台 10 个 + 后台 4 个);ruff 全绿;行尾未被改动。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 07:23:42 -06:00

64 lines
2.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import json
import os
import re
from functools import lru_cache
from django.conf import settings
from judge.sql_runner import SQLCaseError, build_display
from utils.shortcuts import natural_sort_key
TEMPLATE_BASE = """//PREPEND BEGIN
{}
//PREPEND END
//TEMPLATE BEGIN
{}
//TEMPLATE END
//APPEND BEGIN
{}
//APPEND END"""
@lru_cache(maxsize=100)
def parse_problem_template(template_str):
prepend = re.findall(r"//PREPEND BEGIN\n([\s\S]+?)//PREPEND END", template_str)
template = re.findall(r"//TEMPLATE BEGIN\n([\s\S]+?)//TEMPLATE END", template_str)
append = re.findall(r"//APPEND BEGIN\n([\s\S]+?)//APPEND END", template_str)
return {"prepend": prepend[0] if prepend else "", "template": template[0] if template else "", "append": append[0] if append else ""}
def generate_sql_display(test_case_id, answers, sql_config):
"""SQL 题用测试点1的初始化脚本 + 标准答案生成题目页展示数据。
返回 (sql_display, error):成功时 error 为 None失败时 sql_display 为 None、error 为中文提示。
"""
test_case_dir = os.path.join(settings.TEST_CASE_DIR, test_case_id)
try:
with open(os.path.join(test_case_dir, "info"), encoding="utf-8") as f:
info = json.load(f)
except (OSError, json.JSONDecodeError):
return None, "测试点信息读取失败,请重新上传测试点"
if not info.get("sql"):
return None, "测试点不是 SQL 类型,请重新上传 SQL 测试点压缩包"
try:
keys = sorted(info["test_cases"].keys(), key=natural_sort_key)
if not keys:
return None, "题目没有任何测试点"
input_name = info["test_cases"][keys[0]]["input_name"]
except (KeyError, AttributeError, TypeError):
return None, "测试点信息损坏,请重新上传测试点"
try:
with open(os.path.join(test_case_dir, input_name), encoding="utf-8") as f:
init_sql = f.read()
except OSError:
return None, f"测试点脚本 {input_name} 读取失败"
ref_sql = next((item["code"] for item in answers or [] if item.get("language") == "SQL" and item.get("code", "").strip()), None)
if ref_sql is None:
return None, "题目缺少 SQL 标准答案"
try:
return build_display(init_sql, ref_sql, sql_config["mode"]), None
except SQLCaseError as e:
return None, f"SQL 展示数据生成失败: {e.message}"