Skip to content

Conversation

jerader
Copy link
Collaborator

@jerader jerader commented Aug 25, 2025

…pi level to shared-data

closes AUTH-2225

Overview

Please read the description in the ticket. But basically, previously, PD would get the latest labware def versions that are available in shared-data. This causes issues because some versions are not supported in the Robot stack version that is public or will be released before the upcoming PD 8.6 release.

This PR first moves the list of labware that are bumped in api level 2.26 to shared-data into its own JSON file. Then, that JSOn file is imported into the api in _default_labware_versions.py to reference for the labware versions gated by api level 2.26.

Next, the JSON file is exported for JS/TS files to use. I created a getUnsupportedLabwareDefVersionsByApiLevel() util that gets all the labware versions that are not supported based on the api level that pd's python emits. And then I plugged it into PD's getOnlyLatestDefs()

There is a README that explains how everything works.

Test Plan and Hands on Testing

Create a protocol in PD and add a labware that has a version bump in api level 2.26 -> for example, the bio-rad 96 well plate. Export the protocol and open it and see that the version loaded for the bio-rad plate is version 4.

Upload to the app and it should pass analysis.

Changelog

create the json file
import into api and JS
create the JS util that returns the disallowed labware def versions based on the given api level
plug into PD's get latest version util

Risk assessment

low, merged into edge

Copy link

codecov bot commented Aug 25, 2025

Codecov Report

❌ Patch coverage is 10.20408% with 44 lines in your changes missing coverage. Please review.
✅ Project coverage is 54.58%. Comparing base (ee7be87) to head (40ba346).
⚠️ Report is 27 commits behind head on edge.

Files with missing lines Patch % Lines
protocol-designer/src/labware-defs/utils.ts 0.00% 23 Missing ⚠️
shared-data/js/labware.ts 16.00% 21 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             edge   #19358       +/-   ##
===========================================
+ Coverage   23.90%   54.58%   +30.67%     
===========================================
  Files        3392     3393        +1     
  Lines      299732   299980      +248     
  Branches    32754    39266     +6512     
===========================================
+ Hits        71657   163735    +92078     
+ Misses     228058   135981    -92077     
- Partials       17      264      +247     
Flag Coverage Δ
protocol-designer 18.86% <10.20%> (+0.03%) ⬆️
step-generation 5.48% <10.20%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
step-generation/src/utils/pythonFileUtils.ts 85.99% <100.00%> (ø)
shared-data/js/labware.ts 72.44% <16.00%> (-19.34%) ⬇️
protocol-designer/src/labware-defs/utils.ts 0.00% <0.00%> (ø)

... and 1726 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@SyntaxColoring SyntaxColoring left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable so far!

In Slack discussions, there are questions about the premise of all of this, and whether we should really be basing this on robot software release versions instead of apiLevels. But I think this is a good incremental improvement over, like, manually keeping LABWAREV2_DO_NOT_LIST up to date, and we should see how far we can get with this approach.

@jerader jerader requested a review from SyntaxColoring August 26, 2025 16:14
@jerader jerader requested a review from SyntaxColoring August 28, 2025 20:20
@jerader
Copy link
Collaborator Author

jerader commented Aug 28, 2025

TODO:

  • fix the test_default_labware_versions.py py test

from opentrons.protocol_api.core.engine._default_labware_versions import (
from opentrons_shared_data.labware._default_labware_versions import (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_default_labware_versions was previously prefixed with an underscore because it was a private implementation detail of opentrons.protocol_api.core.engine. Since it's now a public interface of opentrons_shared_data.labware, let's remove the underscore.


@functools.cache
def _parse_json_from_filesystem() -> DefaultLabwareVersions:
with open(DEFAULT_LABWARE_VERSIONS_FILE) as file:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have to do open(get_shared_data_root() / DEFAULT_LABWARE_VERSIONS_FILE), not just open(DEFAULT_LABWARE_VERSIONS_FILE). Otherwise, the path will be relative to the process's current working directory.

from pathlib import Path

from typing import TypeAlias
from opentrons.protocols.api_support.types import APIVersion
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. We can't import opentrons from opentrons_shared_data, unfortunately—that's a circular dependency.

I think your options here are either:

  • Move the get_standard_labware_default_version() processing logic back to api/. (Sorry for misleading you! 😬) This file in shared-data/ can remain, to either expose parse_json_from_filesystem() to the file in api/, or expose DEFAULT_LABWARE_VERSIONS_FILE to the file in api/. So the data would be owned by shared-data/, and maybe also the parsing; but the processing would be owned by api/.
  • Or, rewrite this file to not use APIVersion. Maybe it can just be replaced with tuple[int, int]?

No real preference from me.

Comment on lines 29 to 39
def _get_available_load_names_and_highest_versions() -> list[tuple[str, int]]:
versions_by_api = _parse_json_from_filesystem()
highest_available_version_by_load_name: dict[str, int] = {}
for load_name, version, _ in list_labware_definitions():
if (
load_name not in highest_available_version_by_load_name
or version > highest_available_version_by_load_name[load_name]
):
highest_available_version_by_load_name[load_name] = version
for labware_map in versions_by_api.values():
for load_name, version in labware_map.items():
if (
load_name not in highest_available_version_by_load_name
or version > highest_available_version_by_load_name[load_name]
):
highest_available_version_by_load_name[load_name] = version
return sorted(highest_available_version_by_load_name.items())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is changing the behavior of _get_available_load_names_and_highest_versions() in a way that we don't want:

Formerly, it was returning the maximum version of every single labware definition in shared-data, using labware/definitions/{2,3}/*/*.json as the source of truth.

With these changes, it's returning the maximum version of every single labware mentioned in the API version map.

The difference matters because of how this function was being used in test_default_labware_version_coverage(). It's like an independent source to check the API version map against. So if we implement this in terms of the API version map, the test becomes kind of tautological.

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.

2 participants