`migration-risk` text output prints `app.None` for graph-level findings

未关闭 适合新手
#268 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

@phoenixbycaselka 已经在做这个了。

开始于 2026年11月14日。

  • #270 来自 @phoenixbycaselka —— 未关闭

评估

难度
1/5
预计耗时
1-3 小时
新手友好度
88/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
django, python
领域
cli

调研方向

标题行在 cli/orm_lens/cli.py 的文本输出中由 f"{f.operation} {f.app}.{f.model}" 构建,大约在第 313-317 行。让模型部分仅在 f.model 已设置时显示,使图级别的发现只打印应用名。在 cli/tests/test_cli_subcommands_smoke.py 中添加一个用例:对双 leaf 复现运行 migration-risk,并检查输出为 (migration graph) shop 且不包含 None,同时普通的 AddField 发现仍然输出 app.model.field。当该测试、pytest、ruff 和 mypy 都通过时即完成。

由索引模型根据 Issue 内容生成。

描述

bug good first issue python

Source: pretix sendmail, weblate trans (seen while checking the conflicting_migration_leaves reports from #246 and #247)

What happens

The text output of migration-risk prints f"{f.operation} {f.app}.{f.model}". Graph-level findings have no model: conflicting_migration_leaves and alembic_multiple_heads both set model=None. So the header line reads (migration graph) shop.None.

--format sarif and --format github are fine, only the text format has it. Same family as #207.

Repro

shop/models.py

from django.db import models


class Item(models.Model):
    name = models.CharField(max_length=100)
    price = models.IntegerField(default=0)
    sku = models.CharField(max_length=20, default="")

shop/migrations/: 0001_initial.py creates Item(id, name), then two branches that both depend on it:

# 0002_item_price.py
class Migration(migrations.Migration):
    dependencies = [("shop", "0001_initial")]
    operations = [migrations.AddField(model_name="item", name="price", field=models.IntegerField(default=0))]

# 0002_item_sku.py
class Migration(migrations.Migration):
    dependencies = [("shop", "0001_initial")]
    operations = [migrations.AddField(model_name="item", name="sku", field=models.CharField(max_length=20, default=""))]

This is a real conflict, so the finding itself is right. Only the header line is off:

$ orm-lens migration-risk
shop/migrations/0002_item_price.py:1  [critical/high]  (migration graph) shop.None
  rule:      conflicting_migration_leaves
  risk:      App 'shop' has 2 leaf migrations (0002_item_price, 0002_item_sku). ...
shop/migrations/0002_item_sku.py:1  [critical/high]  (migration graph) shop.None
  rule:      conflicting_migration_leaves
  ...

Expected: (migration graph) shop.

Where
  • cli/orm_lens/cli.py, lines 313–317: the header line of the text format.
  • cli/orm_lens/migrations_parser.py, line 1522, and cli/orm_lens/alembic_risk.py, line 467: the two places that create a finding with model=None (for reference, no change needed there).
Suggested fix

Build the target from the parts that are set: f.app, then .{f.model} only when f.model is set, then .{f.field} as now. A small helper next to the print keeps it readable.

How to test
  • cli/tests/test_cli_subcommands_smoke.py: run migration-risk on the repro tree, check the output has (migration graph) shop and no None.
  • A normal finding (AddField NOT NULL without default) still prints app.model.field.
  • cd cli && python -m pytest -q, ruff and mypy pass.

Difficulty: good first issue, one line and a test.

主要语言
Python
星标
84
派生
13
PR 合并指标
30 天内没有已合并 PR

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

FROWNINGdev/django-orm-lens 的其他 Issue

查看 FROWNINGdev/django-orm-lens 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。