on_version_apply is typed as a positional callable, but alembic calls it with keyword arguments

Aperta Adatta ai principianti
#1,883 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

  • #1886 di @anish-yen — chiusa senza merge

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
82/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
python, sqlalchemy
Ambito
backend, databases

Direzione di ricerca

Leggi le definizioni di OnVersionApplyFn in alembic/runtime/environment.py e alembic/context.pyi, quindi confrontale con la chiamata con argomenti denominati in alembic/runtime/migration.py. Aggiorna il tipo chiamabile in modo che corrisponda agli argomenti denominati documentati e verifica la copertura di tipizzazione correlata. Il lavoro è completato quando i type checker accettano un callback scritto come documentato e rifiutano un callback che accetta solo argomenti posizionali.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Describe the bug

EnvironmentContext.configure(on_version_apply=...) documents that "Each callable accepts no positional arguments and the following keyword arguments: ctx, step, heads, run_args", and MigrationContext.run_migrations() calls each callable that way (alembic/runtime/migration.py):

callback(
    ctx=self,
    step=step.info,
    heads=set(head_maintainer.heads),
    run_args=kw,
)

But the parameter is typed as a callable of four positional arguments, in alembic/runtime/environment.py and in alembic/context.pyi:

OnVersionApplyFn = Callable[
    [MigrationContext, "MigrationInfo", Collection[Any], Mapping[str, Any]],
    None,
]

So a type checker rejects a callback written as documented, and accepts one that fails at runtime.

Expected behavior

The type of on_version_apply describes the keyword arguments, for example:

class OnVersionApplyFn(Protocol):
    def __call__(
        self,
        *,
        ctx: MigrationContext,
        step: MigrationInfo,
        heads: Collection[Any],
        run_args: Mapping[str, Any],
    ) -> None: ...

To Reproduce

from typing import Any

from alembic import context
from alembic.runtime.migration import MigrationContext, MigrationInfo


def as_documented(
    *,
    ctx: MigrationContext,
    step: MigrationInfo,
    heads: set[str],
    run_args: dict[str, Any],
) -> None:
    """Takes the arguments by keyword, as documented."""


context.configure(on_version_apply=as_documented)  # rejected by type checkers


def as_typed(
    context_: MigrationContext, step: MigrationInfo, heads: Any, args: Any
) -> None:
    """Takes them by place, as typed."""


context.configure(on_version_apply=as_typed)  # accepted; run_migrations() then fails

Error

pyright 1.1.407:
error: Argument of type "(*, ctx: MigrationContext, step: MigrationInfo, heads: set[str], run_args: dict[str, Any]) -> None" cannot be assigned to parameter "on_version_apply" of type "((MigrationContext, MigrationInfo, Collection[Any], Mapping[str, Any]) -> None) | None" in function "configure" (reportArgumentType)

pyrefly 1.3.2:
ERROR Argument `(*, ctx: MigrationContext, step: MigrationInfo, heads: set[str], run_args: dict[str, Any]) -> None` is not assignable to parameter `on_version_apply` with type `((MigrationContext, MigrationInfo, Collection[Any], Mapping[str, Any]) -> None) | None` in function `alembic.context.configure` [bad-argument-type]

at runtime, with as_typed:
TypeError: as_typed() got an unexpected keyword argument 'ctx'

Versions.

  • OS: Linux, macOS
  • Python: 3.14
  • Alembic: 1.20.0
  • SQLAlchemy: 2.0.54
  • Database: PostgreSQL 17
  • DBAPI: asyncpg

Additional context

Our workaround takes the arguments both ways: def on_apply(ctx, step, heads, run_args) -> None, the parameters named as alembic passes them.

Have a nice day!

Lingua principale
Python
Stelle
4.5k
Fork
391
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di sqlalchemy/alembic

Tutte le issue di sqlalchemy/alembic

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.