Drafts Helpers

Fifteen small utility scripts that exist because OpenSlide is hard to install on Windows and Aperio hides its metadata in a pipe-delimited string — the least glamorous folder in the drafts and the one whose contents other projects quietly depend on.

Purpose

Nothing here is a project; it is the accumulated residue of getting other things to work. Four groups: openslide_fixes/, svs_info_extraction/, directory_structure/, and a one-line cuda/ check. It earns a page because the second group is the concrete implementation of a route that Slide Metadata Extraction describes but does not pin to code, and because the first group documents a real environment problem the group hits repeatedly.

Seven commits, last 2025-06-13 — more revision than most folders in Digital Pathology Drafts get, which is what a utility drawer in active use looks like.

Data used

None. The scripts read slide files in place and emit JSON or text.

Methods

svs_info_extraction/ — the raw-string route to slide metadata. extract_svs_fields.py opens a slide with OpenSlide, takes the tiff.ImageDescription property, strips newlines, splits on |, then splits each part on = to build a key/value dictionary, and pulls Date and Time out of it. extract_all_description_parts.py does the same without selecting fields.

This matters because it is the other route. metadata-qupath reads named properties through an API; this reads the vendor’s description blob and parses it by hand. The blob carries fields the property API does not surface, which is exactly why the script exists — but the trade is that everything comes back as an unvalidated string.

And one of those strings is ambiguous in a way nothing here resolves. The parsed Date value is a bare numeric date. Aperio writes it in US convention, the surrounding Turkish filenames and folder names use day-first convention, and the extractor stores whichever it finds verbatim into a field called scan_date without normalising or recording which convention it assumed. For most days of the month both readings parse successfully and give different dates. This is the same ambiguity already flagged on ScanTools, now found independently in the group’s own code — which makes it a pattern worth fixing once, centrally, rather than twice. It should be stated as a conflict and settled by checking a slide whose scan date is known from another source, not by picking the reading that looks right. [unverified] which convention the local scanner actually writes.

And there is a third extractor that does it properly. extract_svs_metadata.py uses OpenSlide’s named properties — vendor, objective power (falling back to aperio.AppMag), mpp-x/mpp-y, tile dimensions, level count and downsamples — and drops to raw-string sniffing only for compression type, which OpenSlide genuinely does not expose. That is the right split, and it is the file to build on rather than the two that parse the blob. Its existence is easy to miss because the folder name suggests the raw route is the only one here.

openslide_fixes/ — two different problems, one real workaround. The interesting file is patch_openslide.py, and it is not a config tweak: it locates the installed openslide.lowlevel module on disk, backs it up, and rewrites its source in place, wrapping the line version = _lib.openslide_get_version_string() in a try/except AttributeError that returns success instead of raising. The underlying problem is a genuine incompatibility — that version of openslide-python calls a native entry point that behaves differently against OpenSlide C library 4.x, and the check fails on every slide open, so the package is unusable until it is neutered. Recording it because it is a real, diagnosable upstream mismatch rather than a superstition.

It is also fragile in a way worth stating: it matches on an exact source line, so it silently does nothing if upstream changes that line, and it must be reapplied after every reinstall or upgrade of the package. Patching a third-party package’s installed source is a last resort, and the durable fix is a pinned pair of versions known to work together.

fix_openslide.py addresses a separate problem — adding one of three hardcoded Windows directories to the DLL search path so the native libraries are found at all. check-openslide-reads-wsi.py is a smoke test hardcoded to one slide, and install_openslide.py is the only portable file of the four.

directory_structure/ holds tree-dumping utilities plus Groovy scripts that enumerate a QuPath project’s contents, and the local_models.txt inventories that appear throughout the umbrella. Worth knowing that these are tree dumps, not path lists — a distinction that has already caused a real failure: stain-normalisation-qupath tries to parse one as a list of file paths and can never match a line, which is why its reference target never loads.

Current state / open questions

Active in the sense that it keeps being added to, unowned in the sense that nothing here has a test or a stated contract.

  • The date convention should be settled and written down, then applied in both this and metadata-qupath. It is a small fix with a silent, high-consequence failure mode: a misread scan date corrupts any turnaround-time or scanner-drift analysis built on it, and nothing downstream would flag it.
  • Consolidate the four OpenSlide fixes into one that reports what it did. The current set is a record of four attempts, not a solution.
  • local_models.txt is being used as an interface and is not one. It is produced as human reading and consumed as machine input in at least one place, where it silently fails. Either emit a real manifest (JSON, explicit paths) or stop parsing it.

Related: Slide Metadata Extraction — the method page this is the raw-description half of; the measured-versus-computed distinction there is what makes both routes necessary. Related: metadata-qupath — the QuPath-side counterpart, which reads named properties rather than parsing the blob. Related: ScanTools — where the same ambiguous-date problem was first recorded, in someone else’s code. Related: stain-normalisation-qupath — depends on a local_models.txt tree dump as if it were a path list, and fails silently because of it. Related: Digital Pathology Drafts — the umbrella this is a plain directory in.

Derived from: repository source read 2026-07-27 — svs_info_extraction/extract_svs_fields.py read in full, extract_all_description_parts.py, the four openslide_fixes/ scripts and directory_structure/ listings, including local_models.txt format; git log for currency.