`migration-risk` text output prints `app.None` for graph-level findings
@phoenixbycaselka ya está trabajando en esto.
Desde el 14/11/2026.
- #270 de @phoenixbycaselka — abierto
Evaluación
- Dificultad
- 1/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 88/100
Línea de trabajo
La línea de encabezado se construye con f"{f.operation} {f.app}.{f.model}" en la salida de texto de cli/orm_lens/cli.py, alrededor de las líneas 313-317. Haz que la parte del modelo aparezca solo cuando f.model esté definido, de modo que los hallazgos a nivel de grafo impriman solo el nombre de la app. Añade un caso a cli/tests/test_cli_subcommands_smoke.py que ejecute migration-risk sobre el repro de dos leaf y compruebe que aparece (migration graph) shop sin None, mientras que un hallazgo normal de AddField sigue imprimiendo app.model.field. Terminado cuando pasen ese test, pytest, ruff y mypy.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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, andcli/orm_lens/alembic_risk.py, line 467: the two places that create a finding withmodel=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: runmigration-riskon the repro tree, check the output has(migration graph) shopand noNone.- A normal finding (
AddFieldNOT NULL without default) still printsapp.model.field. cd cli && python -m pytest -q,ruffandmypypass.
Difficulty: good first issue, one line and a test.
- Lenguaje dominante
- Python
- Estrellas
- 84
- Forks
- 13
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Preparar el entorno
- Incluye un Dockerfile o un archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de FROWNINGdev/django-orm-lens
-
suggest-indexes proposes composite indexes that include the primary key or a unique fieldPosiblemente ocupada @bfs2021 la tomó hoy. Abiertobug good first issue python
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
FROWNINGdev/django-orm-lens#269 ·
-
Finish the Chinese rule reference — DOL001–DOL007Quizá libre de nuevo @harbinresearcher la tomó hace 64 días y no hay ningún pull request abierto. Abiertodocumentation good first issue help wanted
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
FROWNINGdev/django-orm-lens#81 · 2 comentarios ·
-
Fields inherited from Django's `AbstractBaseUser` / `PermissionsMixin` / `AbstractUser` are missingAbiertobug good first issue python
Dificultad 3/5 1-2 días Aptitud para principiantes 62/100
FROWNINGdev/django-orm-lens#267 ·
-
bug good first issue python
Dificultad 3/5 Medio día Aptitud para principiantes 78/100
FROWNINGdev/django-orm-lens#266 ·
-
enhancement help wanted python
Dificultad 4/5 3-5 días Aptitud para principiantes 35/100
FROWNINGdev/django-orm-lens#254 ·
Todos los issues de FROWNINGdev/django-orm-lens
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
gorakhargosh/watchdog#1462 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
openwisp/openwisp-monitoring#889 ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
OpenFreeEnergy/Lomap#180 ·
-
generate_observation_scenario_from_cpgs exposure time conversion when auto-gain set to 'yes'Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
roman-corgi/corgisim#327 ·
Los mantenedores suelen responder en 2 días
-
agent:WSL bug code-review linux pri:medium sev:low tooling
Dificultad 2/5 Medio día Aptitud para principiantes 62/100
Los mantenedores suelen responder en 1 día