-
Notifications
You must be signed in to change notification settings - Fork 186
refactor(app, labware-designer, labware-library, opentrons-ai-client, share-data): Move all labware images to shared-data #19088
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: edge
Are you sure you want to change the base?
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## edge #19088 +/- ##
===========================================
+ Coverage 23.84% 54.77% +30.93%
===========================================
Files 3373 3373
Lines 296660 296979 +319
Branches 31486 37800 +6314
===========================================
+ Hits 70736 162684 +91948
+ Misses 225901 134030 -91871
- Partials 23 265 +242
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, this seems like a huge improvement! Glad the glob import thing is working out so far.
Changes requested for a couple things, which I'll elaborate on below:
- Some images going missing (probably unintentional) and some images changing (OK if it's intentional, but not sure).
- Possible delineation of a "primary image," for the one (?) case where that matters.
Besides that, just small, optional, code-level nitpicks.
We should also get input from someone else who's better-versed in our JS machinery, since this is largely new to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just double-checking that it's okay to remove this favicon.ico file, and the other two favicon.ico files? I can't see where they were being used, if they even were being used, so it seems fine? 🤷
]) | ||
|
||
const definitionModules = import.meta.glob( | ||
'../../labware/definitions/2/*/*.{json,ts}', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Roughly the same comment as in labware-images.ts
:
Instead of writing out a glob import for the labware definitions, can we use one of the existing functions or constants in labware.ts
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if I use functions in labware.ts it creates a circular dependency since labware.ts needs labwareImages. I could move all of this into labware.ts?
shared-data/Pipfile
Outdated
@@ -33,3 +33,4 @@ numpy = "==1.22.3" | |||
# transitive dependency. 3.22 introduces a build plugin called coherent.licensed that | |||
# is not safe to have installed when another project is being built. | |||
zipp = "==3.21.0" | |||
pillow = "*" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it actually matters in this case, but for clarity, can we move this to [dev-packages]
? That might need a regeneration of Pipfile.lock, not sure.
imageSrc = labwareImages[loadName as keyof typeof labwareImages] | ||
imageSrc = labwareImages[loadName as keyof typeof labwareImages][0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need some way to convey which image is "primary"? Or at least make sure the images are sorted in a deliberate way such that [0]
is always "primary"?
You can imagine, like, a tip rack having a picture of the whole tip rack, and a separate picture of just a single tip. The prior behavior of this code was to show the whole tip rack, and we probably want to keep doing that. As-is, I don't think anything guarantees that we wouldn't accidentally show the single-tip picture.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It creates the list in alphabetical order so I don't think we need to
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed this to sort labwareImages
let i = 0 | ||
for (let j = 0; j < varParts.length; j++) { | ||
if (loadParts[i] === varParts[j]) { | ||
i++ | ||
} | ||
if (i === loadParts.length) break | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this just checking to see if loadParts
is the same as varParts
?
If so, we can use isEqual
from Lodash (import isEqual from "lodash/isEqual"
).
Yes, it's shocking to me too that JavaScript doesn't have a built-in way to do this. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, I want to check if loadParts is within varParts in order to map tube racks and tube definitions so we don't have as many duplicate image cases.
if (matchingUrls.length > 0) { | ||
labwareImages[loadName] = matchingUrls | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As written, if a labware doesn't have any images, it looks like this will result in labwareImages["labware_load_name"]
being undefined
.
But when calling code does labwareImages["labware_load_name"]
, TypeScript will always think the type of images
is string[]
. So there's a hazard of type errors, e.g. if someone did labwareImages["labware_load_name"].map(...)
without remembering to check for the undefined
case.
So, could we either:
- Change
labwareImages: Record<string, string[]>
toRecord<string, string[] | undefined>
, making sure callers can't forget to handle theundefined
case. - Or, change this code to set
labwareImages[loadName]
to[]
, so there is noundefined
case.- I would probably do this one.
I might have seen you added a test somewhere in here to make sure that each labware always has at least one image, so this might not be a problem in practice. Just a safety thing in case there end up being any exceptions where that doesn't hold true, that's easy to add now.
// 6. Add unmatched images using their file name as loadName | ||
for (const [varName, url] of Object.entries(imageKeyToUrl)) { | ||
if (!matchedImageVars.has(varName)) { | ||
labwareImages[varName] = [url] | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No real action needed, just thinking aloud.
To use one of these unmatched images, calling code is presumably going to have to do labwareImages["some_hard_coded_key"][0]
. That's fine, but if they can do that—if they know what the hard-coded key is—couldn't they have just directly imported the image file in the first place, instead of going through this labware-images.ts
aggregation logic?
I'm a little bit fuzzy on the right way to accomplish that, which is why I'm not outright suggesting it. Like, there are definitely ways for other projects to directly reach into shared-data's file tree and import individual files, and we definitely have precedent for that, but I'm not sure if it's "right"—maybe the "right" way is for those images to be in shared-data's package.json
's exports
, for example. Maybe someone better-versed in JS packaging can answer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The broader context behind my thinking is that there's some evidence that we've been overusing "barrel files," i.e. files that just re-export other things. They can cause circular dependencies, increase test run times, maybe increase bundle sizes, and maybe interfere with hot module reloading. So it might be beneficial to figure out a direct import pattern, instead of encouraging callers to go through labware-images.ts
.
There's not really consensus on this yet, though.
const normalizedLoadName = loadName.replace(/\./g, '_').replace(/-/g, '_') | ||
const loadParts = normalizedLoadName.split('_') | ||
|
||
const matchingUrls = Object.entries(imageKeyToUrl) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Structural suggestion for readability. Could we have a helper function whose signature is something like:
function doesImageBelongToLabware(loadName: string, imagePath: string): boolean {
...
}
And then we'd centralize all the path parsing and normalization in there. As-is, it's a little difficult to follow because some of the normalization happens in here while other parts of it happen up above, and they need to stay in sync with each other.
}) | ||
|
||
if (matchingUrls.length > 0) { | ||
labwareImages[loadName] = matchingUrls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect we'll want some kind of sort here to make sure the URLs for each labware are always in the same order. When iterating over files in the filesystem, it's generally good practice to not assume they'll be in any particular order. (It can depend on the OS, filesystem, locale settings, ...)
Overview
Relocate labware images from opentrons-ai-client, labware-designer, app, and labware-library to shared-data
Test Plan and Hands on Testing
Changelog
labware-images.ts
and images folder in the app, opentrons-ai-client, labware-designer, and labware-librarylabware-designer
that only contains svgs of labware shapeslabware-images.ts
can be run to generatelabware-images-generated.ts
. This automatically pairs the labware load name with the associated image based on the file name. This will pair labware + the adapter if part of the load name string is found in the image file name.Pillow
library to pip file for use informat_image.py
in order to crop and resize image before uploading it to shared-data folderReview requests
Risk assessment