Skip to content

Add CARTA startup version validation - #168

Open
izkgao wants to merge 115 commits into
devfrom
zhenkai/check_version
Open

Add CARTA startup version validation#168
izkgao wants to merge 115 commits into
devfrom
zhenkai/check_version

Conversation

@izkgao

@izkgao izkgao commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Description

Closes #166 and #28.

Dependency #161 has been merged.

Adds startup validation for CARTA scripting sessions by fetching frontendVersion and checking it against the minimum CARTA version supported by the installed carta-python wrapper.

Script authors can also provide a single minimum version through minimum_carta_version, for example "6.1.0". Prerelease suffixes such as "6.1.0-dev" are supported. Version operators and ranges are intentionally not accepted.

What is implemented

  • Add CartaUnsupportedVersion for unsupported CARTA frontend versions.
  • Add CARTA version parsing and validation helpers.
  • Validate the frontend version during all session creation methods:
    • Session.interact
    • Session.start_and_interact
    • Session.create
    • Session.start_and_create
    • Browser session creation helpers
  • Enforce the internal minimum CARTA version of 6.0.0 (will be bumped to 6.1.0 before release).
  • Support script-specific minimum versions through minimum_carta_version.
  • Support warning or exception behavior through
    VersionMismatchAction.WARN and VersionMismatchAction.ERROR.
  • Provide actionable diagnostics for older frontends, newer unsupported major
    versions, invalid frontend versions, and validation failures.
  • Clean up wrapper-controlled browser and backend resources when startup
    validation fails.
  • Update the quickstart documentation.

Checklist

  • Documentation added
  • Tests added

izkgao added 30 commits April 30, 2025 16:38
…or coordinate system and number format methods
…ces for consistency with documentation style
@izkgao izkgao added the awaiting code changes For pull requests that require code changes label Aug 18, 2026
@izkgao izkgao added awaiting code review For pull requests that require code review awaiting testing For pull requests that require testing and removed awaiting code changes For pull requests that require code changes blocked For issues/PRs that are blocked, either by other issues/PRs, or by external dependencies labels Aug 18, 2026
@izkgao izkgao assigned confluence and unassigned kswang1029 Aug 18, 2026
@confluence

Copy link
Copy Markdown
Collaborator

A minor modification: it may make more sense for the script's target version to be compared to the wrapper's target frontend version rather than to the frontend's version directly. Or maybe do a three-way comparison, to cover all the bases (the failure setting could then be a bitmask of three possible values).

@izkgao

izkgao commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

I was thinking specifying a minimum frontend version in a script does not necessarily establish compatibility with the script. For example, a future feature may be implemented entirely in carta-python without requiring any frontend changes. In that case, increasing the script's minimum frontend version would be unnecessary, and the corresponding carta-python release might continue to support the same frontend minimum.
We could document the use of uv for declaring the required carta-python version in standalone scripts:

uv add --script example.py "carta-python==2.0.0"

This adds the following metadata to the head of example.py:

# /// script
# dependencies = [
#   "carta-python==2.0.0",
# ]
# ///

Anyone can then run the script with:

uv run example.py

and uv will automatically create or reuse an isolated environment with the specified carta-python version. This makes the script's Python-side dependency explicit and reproducible. Therefore, I think we should remove minimum_carta_version from the session APIs and retain only the wrapper's own frontend compatibility check.
What do you think?

@confluence

Copy link
Copy Markdown
Collaborator

I'm happy with that -- I think it's more important for us to check compatibility between the wrapper and the frontend, which is within our area of responsibility.

The uv feature you suggested is a much better way for users to manage script / wrapper compatibility; we don't have to reinvent the wheel. If the older version of the wrapper isn't compatible with the frontend, the wrapper's version check should pick that up, and then the user can update the script as needed.

Once we have started publishing the package, we should add that workflow as a suggestion to the docs.

@izkgao izkgao added awaiting code changes For pull requests that require code changes and removed awaiting code review For pull requests that require code review awaiting testing For pull requests that require testing labels Aug 19, 2026
@izkgao izkgao added awaiting code review For pull requests that require code review awaiting testing For pull requests that require testing and removed awaiting code changes For pull requests that require code changes labels Aug 19, 2026
@confluence

Copy link
Copy Markdown
Collaborator

I'll review these changes ASAP. I've realised that if we're going to be using the wrapper package version, we also need to decide how that's going to work (currently it's a bit random, and hasn't been updated in ages). I think that it should be tied to the CARTA release version, but there should also be a way of specifying updates to the wrapper only (that don't correspond to CARTA release updates).

I've read the documentation about versioning here and here, and looked through some real packages on PyPi to see how versions are actually used in the wild, and this is my suggestion:

main branch (compatible with last CARTA release; used for PyPi releases):

  • Last CARTA version number (N.N.N) with an additional .N to represent wrapper-only updates
  • This is legal (you can have any number of components in this element, although more than 3 is uncommon -- there are definitely projects on PyPi that use four).
  • Every time we backport release-compatible changes from dev to main and make a new package, we should bump the last number.

dev branch (compatible with dev or beta CARTA):

If there are no wrapper changes that depend on the development version of CARTA, this branch should match the versions of the main branch (the main branch should be kept in sync, so that they are identical), only switching to the scheme below when / if the branches need to diverge:

  • Upcoming CARTA version number (N.N.N, no -dev) with an additional .devN to represent individual wrapper changes
  • This is also legal, and I think makes sense for representing development updates.
  • Every pull request that is merged into dev should bump the last component.
  • Because we aren't going to be publishing versions from this branch, we could also use local identifiers (+something), but that doesn't make sense with our model of using the next CARTA release in this branch: 1.2.3.dev1 < 1.2.3.0 or 1.2.3, as expected, but 1.2.3+dev1 > 1.2.3.0 or 1.2.3 (because it's interpreted as 1.2.3 with additional changes, not a development step towards 1.2.3).
  • We could maybe use .betaN versions when we depend on a beta release, but this is unlikely to diverge from the development branch, so it may not be necessary (we can consider the possible cases). .devN < .betaM, as expected.

Whenever a new CARTA release is published, the dev branch version should become N.N.N.0 and the main branch should be synced with the dev branch. That's assuming that there are new development-only changes -- if not, I don't think that we should bump either branch (see below for major version bumps).

If we can read the version from the package, we wouldn't need to have a separate constant for the minimum compatible CARTA version, since we could parse it from the package version. I think that if we strip -dev from the CARTA version (if it exists) we can always compare it to the first three components of the wrapper package version and get the right answer.

What about major version boundaries? I previously suggested that we could bump the wrapper's minimum version with every major CARTA release to try to safeguard against removal of deprecated frontend functions, but this approach has drawbacks, and I don't think that there's any method that would be more reliable. I suggest that we don't bump the version unless we actually need to and rely on deprecation warnings to alert the user that they need to update the wrapper. We could perhaps remove functions in the second major release after deprecation, to ensure that the deprecation period is at least one full major version.

@confluence

Copy link
Copy Markdown
Collaborator

I've thought about it some more and I have an alternative suggestion for a maximum version heuristic: decouple the versions used for the minimum and maximum check. For the minimum check, use the package version (as suggested above). For the maximum version, store a TARGET_CARTA_VERSION constant which is only a major version. Bump this constant with every CARTA release, but if there are no development changes, do not bump the CARTA portion of the package version. So for example:

  1. CARTA is on 6.2.0; wrapper is on 6.1.0.5 (dev, main and package), TARGET_CARTA_VERSION is 6.
  2. CARTA 6.3.0-dev deprecates a frontend function.
  3. Wrapper dev branch adds a change to stop using the function. Let's say that this change depends on a new function in 6.3.0. The dev branch gets a 6.3.0.dev1 version; this change is not backported to main and no package is built.
  4. CARTA 6.3.0 release. Wrapper dev version changed to 6.3.0.0; main synced with dev; new package built.
  5. CARTA has some more minor releases; is now on 6.5.0. Wrapper has some more wrapper-only releases; is now on 6.3.0.2 (dev, main and package).
  6. CARTA 7.0.0 release. Wrapper dev changes TARGET_CARTA_VERSION to 7; bumps version to 6.3.0.3; main synced with dev; package built.

The checks should fail if the CARTA version is lower than the minimum version (as per package version) or if the CARTA major version is higher than TARGET_CARTA_VERSION.

So these should be the results for recent wrappers:

  • 6.3.0.3: Below 6.3.0 is too low; 6.3.0 to 7.x is fine; 8.x is too high. This is correct -- 6.3.0 is the minimum version, and we should be able to guarantee that no more functionality will be removed in 7.x (only deprecated), but we can't guarantee compatibility with 8.
  • 6.3.0.0 to 6.3.0.2: As above, but 7.x is too high. While in this case all these versions do work with 7.x (and the user can switch to warnings to use them), we cannot in general guarantee this: if there are multiple deprecations, fixed in incremental wrapper versions, there may be versions that fix some of them and not others (and which may therefore fail when used with 7.x). So the check result is correct. This is why we should only update the target version with the major release -- that's when we can guarantee that we have handled every deprecated function that will be removed in this release.
  • 6.1.0.5 and below: Below 6.1.0 is too low; 6.1.0 to 6.5.0 is fine; 7.x is too high. This is correct -- 6.1.0 is the minimum version, and higher versions of 6.x will work with deprecation warnings because no functions have been removed, but in 7.x those functions will actually be removed. If no functions were deprecated in 6.x, and 7.x should therefore still be compatible, the user can switch to warnings.

In contrast to this strategy, if we were to estimate the maximum major version from the minimum version, and we bumped the package version to 7.0.0.0 with the release, the 7.0.0.0 version of the wrapper would report that CARTA 6.5.0 was too old (despite versions all the way down to 6.3.0 being fine), and the user would have to switch to warnings to use it. Given that the user is likely to have control over their wrapper version (they can install it in a userspace environment), but may be reliant on a site provider to upgrade CARTA, this is a common use case. Since we would in general like to encourage users to keep their wrapper up to date and maintain their scripts to match, and not to provide any barriers to upgrading, I would prefer to slightly inconvenience users of old wrappers than to slightly inconvenience users of the latest wrapper. 😆 So my vote is for separating the checks.

There may be slight modifications to the procedure outlined above if the situation is different:

  • If at 1 the wrapper dev branch already has development changes, its version will be incremented to .dev2; everything else is the same.
  • If at 3 the fix for the deprecation only uses frontend functions already in 6.1.0, the fix can immediately be backported to main as 6.1.0.6, and a new package can be built. If there are no other dev changes, a 6.3.0.0 package will not be necessary, and the subsequent wrapper-only changes will bring the version up to 6.1.0.8 instead.
  • If at 3 the fix requires functionality added in 6.2.0, it can be backported to main but with a 6.2.0.0 version, and a new package can be built. If there are no other dev changes, a 6.3.0.0 package will not be necessary, and the subsequent wrapper-only changes will bring the version up to 6.2.0.2 instead.

(I'm not dead-set on the last two -- we could always treat deprecation fixes as dependent on the release that deprecated them, and most of the time they will probably be caused by refactoring and will probably depend on new changes. But if they don't, we don't have to.)

Does this make sense?

(Once we have agreed on all of these versioning procedures, we can document them in a developer section of the docs.)

@izkgao

izkgao commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Sorry for taking longer to think through the versioning strategy. I discussed this with KC and KS regarding how frontend should be handled from a broader perspective. After considering the different compatibility boundaries between CARTA and carta-python, I think it may be better for carta-python to use an independent versioning scheme instead of being directly tied to the CARTA version.

The reason is that CARTA and carta-python represent different compatibility boundaries:

  • CARTA version represents the frontend/backend product release.
  • carta-python version represents the Python user-facing API contract.

Therefore, these two versions should evolve independently.

For example:

  • A new CARTA release does not necessarily require a new carta-python release if there are no changes affecting the frontend APIs.
  • A new carta-python release is only required when new functionality needs to be implemented or APIs (frontend/python) require changes.
  • A breaking change in the carta-python API should result in a carta-python major version bump, regardless of the CARTA version.

Compatibility handling

Instead of encoding CARTA versions into the carta-python version number, we can maintain a compatibility table inside carta-python. The purpose of this table is not to define a strict API version dependency, but to provide meaningful suggestions when compatibility issues occur.

For example:

CARTA version Recommended carta-python version
5.0 - 5.9 1.0.x
6.0 - 6.2 1.2.x
6.3+ 1.3.x

This allows carta-python to provide better error messages:

  • If an old carta-python version is used with a newer CARTA version and a frontend scripting call fails, users can be advised to upgrade carta-python to the latest version since it can further advise users with latest information if this version is still not compatible (see the next point).
  • If a newer carta-python version is used with an older CARTA version, users can be advised to either:
    • upgrade CARTA, or
    • downgrade carta-python to the latest compatible version.

The table should describe the recommended compatibility relationship, rather than requiring every CARTA release to have a corresponding carta-python release. For example, if CARTA 6.3 introduces new scripting functionality but does not break existing scripting APIs, existing carta-python versions can continue to work. A new carta-python release is only needed if the new functionality is exposed or compatibility needs to be updated.

Backward compatibility

Backward compatibility handling should be maintained within carta-python instead of within the frontend since a single refactor may result in marking a lot of functions and attributes deprecated which seems messy. When the frontend API changes, carta-python can temporarily support both old and new frontend APIs. However, compatibility code should not accumulate indefinitely. When the minimum supported CARTA version is increased to the next major version, obsolete compatibility handling should be removed. This keeps the codebase clean and avoids maintaining unnecessary legacy paths.

@confluence

Copy link
Copy Markdown
Collaborator

I'm happy with this general idea. Should we update this PR to start implementing it now, or should we move it back into draft until we're ready to start branching and packaging the wrapper?

We could start the table with the CARTA and wrapper versions as they are now -- but we should start by bumping the wrapper version in dev, since it currently depends on the dev frontend.

@izkgao izkgao added awaiting code changes For pull requests that require code changes and removed awaiting code review For pull requests that require code review awaiting testing For pull requests that require testing labels Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting code changes For pull requests that require code changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Validate frontend version

3 participants