Skip to content

Let extensions upgrade their own data via versioned @extensions#403

Open
gustavdelius wants to merge 1 commit into
masterfrom
extension-version-upgrades
Open

Let extensions upgrade their own data via versioned @extensions#403
gustavdelius wants to merge 1 commit into
masterfrom
extension-version-upgrades

Conversation

@gustavdelius

Copy link
Copy Markdown
Member

Summary

mizer can upgrade its own (core) slots across mizer versions, but extension
packages had no way to migrate their data when their storage layout changes,
and an object carried no record of which extension version it conformed to.
This PR adds per-extension version tracking and an upgrade-dispatch path so an
extension can upgrade its objects independently of the mizer version.

The motivating case is mizerMR moving its resource_params data frame to a new
location; with this PR a saved mizerMR model is migrated automatically the first
time it passes through validParams() / readParams().

What changed

  • Versioned @extensions slot. Slot type widened to "ANY". It may hold
    the legacy named character vector of requirement strings, or a named list of
    c(requirement = ..., version = ...) entries, where version is the version
    of the extension package the object conforms to. objectExtensions() returns
    the requirement-only view, so all dispatch / suffix-chain logic is unchanged.
    New helpers: exported recordExtension() plus internal
    extensionRequirements(), extensionVersions(), extensionVersion(),
    makeExtensions().
  • upgrade() methods. upgradeParams() / upgradeSim() are now the
    upgrade.MizerParams() / upgrade.MizerSim() methods of the
    utils::upgrade() generic; the old names remain as thin internal wrappers.
    Extensions register their own method with @exportS3Method utils::upgrade.
  • Orchestration in validParams(). It runs the core upgrade when
    @mizer_version is stale, then runExtensionUpgrades() calls each
    out-of-date extension's upgrade method directly (no NextMethod()) and
    re-stamps it afterwards. Extension methods are pure, idempotent migrations.
  • needs_upgrading() now also fires when an extension's recorded stamp is
    missing or older than the installed package version. A missing stamp counts
    as stale, so objects created before version tracking are migrated and stamped
    on first use.
  • registerExtensions(), readParams()/readSim() and
    requiredExtensionPackages() accept the versioned list form.
  • New vignette section "Upgrading objects across versions of your extension".

Testing

  • New tests/testthat/test-extension-versions.R.
  • Full suite green: 2827 tests, 0 failures, 0 errors.

Note: the unrelated getFluxGradient() doc cross-references that document()
would otherwise add were left out to keep this PR focused.

🤖 Generated with Claude Code

mizer could upgrade core slots across mizer versions, but extensions had
no hook to migrate their own data and no record of which extension version
last conformed an object. This adds per-extension version tracking and an
upgrade dispatch path so extensions can upgrade their objects independently
of the mizer version.

- The `@extensions` slot (now typed "ANY") may hold either the legacy named
  character vector of requirement strings or a named list of
  `c(requirement, version)` entries. `objectExtensions()` returns the
  requirement-only view, so all dispatch/suffix logic is unchanged. New
  helpers: `recordExtension()` (exported), `extensionRequirements()`,
  `extensionVersions()`, `extensionVersion()`, `makeExtensions()`.
- `upgradeParams()`/`upgradeSim()` are now the `upgrade.MizerParams()` /
  `upgrade.MizerSim()` methods of `utils::upgrade()`; the old names remain as
  thin internal wrappers.
- `validParams()` orchestrates upgrades: it runs the core upgrade when
  `@mizer_version` is stale, then `runExtensionUpgrades()` calls each
  out-of-date extension's `upgrade` method directly (no `NextMethod()`) and
  re-stamps it. `needs_upgrading()` now also fires on a missing or stale
  extension stamp.
- `registerExtensions()` / `readParams()` / `requiredExtensionPackages()`
  accept the versioned list form via the requirement view.
- Documented the pattern in the creating-extension-packages vignette and
  added tests in test-extension-versions.R.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant