sillsdev / sillsdev/python-sil-lift

Media hrefs resolve case-sensitively: Windows-authored folders get false missing-media on Linux

Open
#34 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Python
Stars
1
Forks
0
Avg merge
10d 11h
Merged PRs (30d)
6

Description

Lexicon.missing_media() resolves <media> and <illustration> hrefs with a plain is_file(), so a folder authored on Windows reports files as missing when it is read on a case-sensitive filesystem.

Dict.lift            <illustration href="pictures\SDD.PNG"/>
pictures/sdd.png

Loads clean on Windows; on Linux sil-lift validate warns missing-media, and --strict fails the run. The image is right there.

The lookup is the two-candidate probe in missing_media() (src/sil_lift/_model.py):

candidates = [base / relative, base / subfolder[ref.kind] / relative]
if not any(candidate.is_file() for candidate in candidates):

This is the same Windows-authored/Linux-read mismatch that #19 fixed for .lift-ranges companions, in the one other place the library touches the filesystem.

Why this is not just "call _existing_file here too"

For a companion, folding the name is unambiguously right: resolve it or silently lose every range it defines. For media the opposite argument has real force. If an illustration href says SDD.PNG and the file is sdd.png, a web export, an APK build, or anything else serving that folder from a case-sensitive host will 404. A validator that silently resolves the mismatch reports a clean bill for a dictionary that is genuinely broken downstream — hiding the defect the check exists to surface.

Options:

  • A. Fold silently. ~6 source lines. Consistent with companion resolution, kills the false positives, hides genuine portability defects.
  • B. Fold, but report the mismatch as its own finding (media-case-mismatch, warning). missing-media goes back to meaning "no such file under any spelling"; the new code says "found, but only case-insensitively — this will not survive a case-sensitive host." Costs a new problem code, which is a SemVer-covered interface here.
  • C. Leave it, document it. The status quo is at least honest about the portability problem, just unhelpfully worded and noisy.

B looks right, but it is a real interface decision and wants a deliberate call rather than a drive-by.

Two things to settle either way

  • Only the final path component folds. _existing_file searches one directory listing for a name; it does not fold directory components. Media hrefs routinely include pictures/ and audio/, so Pictures\x.png against an on-disk pictures/ would still misreport. Whether to fold directory components is more pressing here than it was for companions, where hrefs are basenames or same-folder relatives.
  • Cost. missing_media() iterates every media ref in the document — thousands in a real dictionary — and media folders are large. _existing_file's listings cache has to be threaded across the whole loop so it is one directory read per folder per call, not one per reference.

Rough size

Option A: ~50 lines over 3 files. Option B: ~200-250 lines over ~10 — _model.py, _validate.py, _cli.py, docs/en/guides/{validate,cli,lift-export-interop}.md, a negative corpus fixture plus its PROVENANCE.md entry, test_validate.py, test_cli.py, and CHANGELOG.md.

Split out of review discussion on #19, which deliberately kept its scope to companion resolution.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/sil_lift/_model.py at missing_media() and compare its two-candidate probe with _existing_file and the companion-resolution change in #19. Decide between silent folding, a media-case-mismatch finding, or documentation, then trace the required validation, CLI, documentation, fixture, tests, and changelog updates; done means the chosen behavior is covered and cached directory lookup handles the full media loop.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.