Skip to content

py-v1.10.0 - drift reported a false blocking failure when two apps shared a name

Choose a tag to compare

@github-actions github-actions released this 30 Jul 18:19
· 55 commits to main since this release

Three defects found by running the CLI over real checkouts of django-oscar,
django-guardian, django-allauth and django-cms rather than over fixtures. Each
one was invisible to a green test suite, and two of them made the tool answer
confidently with something false.

Fixed

  • drift reported a false blocking failure when two apps shared a name.
    The third finding from the same real-world run, on django-guardian, which
    ships both example_project/core and example_project_custom_group/core.
    The parser labels an app by its directory, so the declared side merged the
    two; the migration side replayed each directory on its own. One project's
    migrations were therefore compared against both projects' models, and the
    report contradicted itself — core.customgroup came out as "declared, but
    no migration creates it" and "migrated but no longer declared", with
    core.customuser printed twice. The first of those is a blocking verdict,
    so anyone running drift in CI over a repo with two same-named app
    directories — every monorepo — could have a build failed by a model that was
    migrated perfectly well. Replayed state is now merged per app name, matching
    how the declared side is already keyed. On the real guardian checkout the
    blocking count goes from 1 to 0 and the duplicate row disappears, while a
    genuinely unmigrated field still blocks.

  • Abstract bases in abstract_models.py were never read. The other half of
    the same django-oscar run: once its models were found, 72 of the 83 had zero
    fields between them, because every pluggable framework keeps the abstract
    base in abstract_models.py and leaves models.py holding only the
    concrete subclass. A model reported with no columns reads as a schema that
    lost them, which is a worse answer than admitting the file was not read.
    The workspace walk now takes abstract_models.py alongside models.py;
    the bases are still dropped from the results, they only become available for
    inheritance. oscar goes from 72 empty models to 8 — and those 8 are correct:
    they subclass concrete models, where multi-table inheritance leaves the
    columns on the parent's table.

  • Models declared inside a module-level block were invisible. Running the
    CLI over a real django-oscar checkout — not a fixture — showed 12 models for
    the whole framework, and every one of them came from oscar's tests/
    directory: 21 of its 22 app models.py files parsed to nothing. Catalogue,
    order, offer, partner, payment, shipping, voucher, customer, address,
    analytics, reviews and wishlists were all missing. Reporting a project's
    test fixtures as its schema is worse than reporting none of it.
    The cause is the swappable-model idiom every pluggable Django framework
    uses — if not is_model_registered(...): and then an indented class
    against class discovery anchored on ^class. A class is now matched on its
    dedented view and accepted when everything enclosing it is a block statement
    (if, try, with, for); a def or class outwards still rejects it,
    so Meta, nested helpers and factory-local models stay out. django-oscar
    now yields 82 models. All six golden snapshots are byte-identical: a
    column-0 class parses exactly as before.

Added

  • A sixth golden fixture: Read the Docs. The vendored projects/models.py,
    its generated snapshot, reproducible fetch metadata and MIT attribution, next
    to Zulip, Saleor, Wagtail, django-CMS and Mezzanine — 16 models and 142
    fields more, putting the parser under 75 models and 537 fields of real-world
    Django. Verified byte-identical to upstream blob cf1e913d before merge:
    fixtures are parser input for byte-stable snapshots, so an edited copy
    would quietly rewrite what those snapshots assert. Contributed by
    @JJordan0C in
    #62, closing
    #51.