Skip to content

fix: Agilent OpenLab CDS - accept zipped result sets - #1252

Merged
nathan-stender merged 3 commits into
mainfrom
fix/openlab-cds-accept-zipped-result-sets
Aug 25, 2026
Merged

fix: Agilent OpenLab CDS - accept zipped result sets#1252
nathan-stender merged 3 commits into
mainfrom
fix/openlab-cds-accept-zipped-result-sets

Conversation

@nathan-stender

@nathan-stender nathan-stender commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Problem

The OpenLab CDS help docs tell users they may compress their .rslt result set before dropping it in the File Watched directory:

(Optional) Users can additionally compress their RSLT file to a zipped file within their File Watched directory if they choose. The Agilent OpenLabs CDS connector is able to process this format along with the standard RSLT file export.

That was never true in allotropy. SUPPORTED_EXTENSIONS = "rslt" meant a .zip upload was rejected before the parser saw any bytes:

EXPLICIT .zip FAIL: AllotropeConversionError Unsupported file extension 'zip' for parser 'Agilent OpenLab CDS', expected one of '['rslt']'.
DISCOVER .zip FAIL: AllotropeVendorNotFoundError No vendor could be identified for file with extension '.zip'.

The .rslt files we already accept are zip archives, so the contents were never the problem — only the extension gate and, for one shape, an extra layer of nesting.

Changes

  • Accept the zip extension in addition to rslt.
  • Replace the unconditional sniff() with a content check. return True was only safe while .rslt was exclusive to this parser. With zip added, the old sniff would have claimed every .zip and stolen files from Cytiva Unicorn ("zip") and AppBio Absolute Q ("csv,zip"). It now looks for an ACAML member.
  • Unwrap extra layers of compression (open_result_set). Compressing the .rslt folder yields an archive whose members are the result set; compressing the .rslt file yields an archive whose only member is another archive. Both now work.
  • Clearer errors. A non-result-set archive raised bare StopIteration, and an uncompressed file raised BadZipFile. Both now raise AllotropeConversionError with a message, since malformed archives are newly reachable input.

Verification

Tested against archives produced by the real macOS Finder "Compress" path (ditto -c -k --sequesterRsrc --keepParent, which adds the __MACOSX resource forks that hand-built zips lack):

finder_folder.zip           parse=IDENTICAL  discover=AGILENT_OPENLAB_CDS
finder_folder_renamed.rslt  parse=IDENTICAL  discover=AGILENT_OPENLAB_CDS
finder_file.zip             parse=IDENTICAL  discover=AGILENT_OPENLAB_CDS
finder_file_renamed.rslt    parse=IDENTICAL  discover=AGILENT_OPENLAB_CDS

IDENTICAL = byte-equal ASM against the existing fixture (~192KB of output, data cubes included), ignoring file name / UNC path, which legitimately differ.

  • Full suite: 1496 passed, hatch run lint clean.
  • tests/discover_vendor_test.py passes, confirming no cross-vendor sniff regressions.

Notes for reviewers

  • The new test synthesizes each compression shape from the existing .rslt fixture rather than checking in new files, avoiding ~3MB of duplicate test data.
  • Mutation-tested the new test (MAX_ARCHIVE_NESTING 3 → 1): exactly the two nested cases fail, so the assertions aren't vacuous.
  • Nesting is bounded at 3 archive levels. Beyond that a user would have to compress three or more times, which the docs don't describe.
  • Still open, outside this repo: if the connector zips the watched folder itself, a pre-zipped upload may not reach allotropy to benefit from this. The Unsupported file extension 'zip' error above is the signal that it did.

🤖 Generated with Claude Code

Update: rebased on main (2026-08-25)

Merged latest main, which now contains #1254 (OpenLab CDS memory + optional ACAML metadata) and #1258. Resolving the overlap in agilent_openlab_cds_decoder.py changed two things in this PR:

  • .sqx stays optional. This PR originally routed the sequence-file lookup through a new _get_first_matching_filename helper that raised when .sqx was absent. fix: Cut OpenLab CDS peak memory 4x and handle optional ACAML metadata #1254 made .sqx optional (falling back to the ACAML method documents), and the Sirius fixture it added has no .sqx, so main's behaviour wins. The helper became dead code and was removed — the "clearer errors" bullet above now applies only to the ACAML and non-archive cases, both still covered by tests.
  • sniff no longer copies the whole file into memory. It now calls get_seekable_bytes_stream() instead of get_bytes_stream(). Result sets reach ~1GB, and get_bytes_stream() buffers the entire upload — using it in sniff would have silently undone fix: Cut OpenLab CDS peak memory 4x and handle optional ACAML metadata #1254's memory fix on every discovery pass.

Also fixed the Quality Checks failure that predated the merge: from_file returns Mapping[str, Any], not dict[str, Any], so the expected fixture's annotation failed mypy.

Re-verified after the merge: 1498 passed (up from 1496 — main added the two Sirius fixture cases), hatch run lint clean, tests/discover_vendor_test.py green.

OpenLab CDS help docs state that users may compress their .rslt result set
before dropping it in the File Watched directory, but only the "rslt"
extension was accepted, so a .zip upload failed with "Unsupported file
extension 'zip'" (or no vendor found during auto-discovery).

- Accept the "zip" extension in addition to "rslt".
- Replace the unconditional sniff() with a content check, since .zip is
  shared with Cytiva Unicorn and AppBio Absolute Q.
- Unwrap extra layers of compression, so compressing either the .rslt
  folder or the .rslt file itself (which is already an archive) works.
- Raise AllotropeConversionError instead of bare StopIteration/BadZipFile
  when an archive is not a recognizable result set.

Tests synthesize each compression shape from the existing result set
fixture, and assert all of them produce the same ASM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@nathan-stender
nathan-stender requested review from a team and slopez-b as code owners August 13, 2026 17:38
stephenworlow
stephenworlow previously approved these changes Aug 25, 2026
@stephenworlow
stephenworlow self-requested a review August 25, 2026 13:49
…t-zipped-result-sets

# Conflicts:
#	src/allotropy/parsers/agilent_openlab_cds/agilent_openlab_cds_decoder.py
@nathan-stender
nathan-stender merged commit 0508972 into main Aug 25, 2026
16 checks passed
@nathan-stender
nathan-stender deleted the fix/openlab-cds-accept-zipped-result-sets branch August 25, 2026 17:43
nathan-stender pushed a commit that referenced this pull request Aug 25, 2026
### Fixed

- Agilent OpenLab CDS - accept zipped result sets (#1252)
- Tecan Magellan - support compact Magellan Pro 7.5 exports (#1258)
- Cut OpenLab CDS peak memory 4x and handle optional ACAML metadata
(#1254)
- Report custom information keys in a stable order (#1249)
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