Skip to content

fix: harden error handling, argument validation and setup file handling - #37

Merged
moheladwy merged 2 commits into
mainfrom
fix/robustness-and-arg-validation
Aug 27, 2026
Merged

moheladwy merged 2 commits into
mainfrom
fix/robustness-and-arg-validation

Conversation

@moheladwy

@moheladwy moheladwy commented Aug 13, 2026 •

Copy link
Copy Markdown
Owner

Summary

Fixes the robustness issues found while auditing the repo. No feature changes — every fix turns a silent-wrong-behaviour path into either correct behaviour or a clear error.

What was broken

OCR4Linux.py

  • pytesseract.get_languages() ran outside any try/except in TesseractConfig.__init__, so a missing or misconfigured tesseract raised before main()'s try block was reached — raw traceback, no handling.
  • Argument parsing accepted any 4- or 5-argument invocation but only recognised exactly --langs value / --langs=value. A typo like --langz=eng was silently reinterpreted as "no languages specified" rather than erroring.
  • Requested languages were passed straight to tesseract, so an uninstalled language surfaced as a confusing downstream pytesseract error.
  • Header and class docstring described a preprocess_image() method and OpenCV/numpy dependencies that do not exist anywhere in the file.

OCR4Linux.sh

  • No set -euo pipefail and no exit-code checks. If the screenshot was cancelled or OCR failed, the script still ran the clipboard copy against a stale or nonexistent file and then unconditionally rm'd it.
  • A cancelled area selection can exit 0 while producing no file — that case was completely undetected.
  • Unavailable languages only produced a warning, then ran anyway.
  • --lang "" set LANG_SPECIFIED=true with an empty value, yielding an empty language array instead of falling back or erroring. -d and --lang with no value at all ran shift 2 off the end of the argument list.

setup.sh

  • Cloned yay into whatever directory the script was run from, with no collision check and no cleanup.
  • cp -r ./* ~/.config/OCR4Linux copied the whole working directory — PKGBUILD, setup.sh, the cloned yay/ — into the config directory, and silently did the wrong thing when run from outside the repo root.

Validation

shellcheck clean on both scripts, bash -n and python3 -m py_compile pass.

Ran 25 end-to-end scenarios against a real tesseract with stubbed desktop tools (scrot, rofi, xclip) — all pass:

  • Happy paths: default languages, --langs eng, --langs=eng+ara, --lang all, interactive rofi selection, -h, -v, -l, -r
  • Now caught (previously silent or crashing): typo'd flag, bare --langs, empty --langs value, uninstalled language, missing image, too many args, tesseract not on PATH, screenshot tool exiting non-zero, screenshot cancelled while exiting 0, -d/--lang without a value

Confirmed against main that the three headline bugs were real: the typo'd flag was silently ignored, eng+klingon was accepted, and a cancelled screenshot exited 0 and still invoked xclip.

Also verified setup.sh installs only the two runtime files, works when run from an unrelated working directory, leaves no junk behind, and that the installed copy runs standalone from the config directory.

Note, not addressed here

PKGBUILD and setup.sh still list python-numpy and python-opencv as dependencies, but the Python script imports only PIL and pytesseract. Dropping them looks safe but changes a published AUR package's dependency set, so I left that call to you.

Fixes a set of robustness bugs found while auditing the repo.

OCR4Linux.py:
- Wrap the Tesseract language query so a missing or misconfigured tesseract
  produces a clear error instead of an unhandled traceback thrown before
  main()'s try block is reached.
- Reject malformed trailing arguments. Previously any 4- or 5-argument
  invocation that was not exactly "--langs value" or "--langs=value" fell
  through silently as "no languages specified", so a typo changed behaviour
  without warning.
- Validate requested languages against the installed ones and fail with an
  actionable message instead of letting pytesseract raise downstream.
- Drop the stale header/docstring references to a preprocess_image() method
  and to OpenCV/numpy, none of which exist in the file.

OCR4Linux.sh:
- Enable "set -euo pipefail".
- Detect screenshot capture failure, including a cancelled selection that
  exits 0 without producing a file. Previously the script carried on and
  pushed a stale or nonexistent output file to the clipboard.
- Detect OCR failure, remove any stale output file before extraction, verify
  the output exists before copying, and guard the deletions with "rm -f".
- Fail fast on languages that are not installed instead of only warning.
- Reject "-d" and "--lang" without a value, and an empty "--lang" value that
  previously produced an empty language list.
- Buffer the newest cliphist entry instead of piping into head, which exits
  non-zero under pipefail.
- Handle an unset XDG_SESSION_TYPE under "set -u", and never let logging
  abort the run.

setup.sh:
- Enable "set -euo pipefail".
- Build yay in a temporary directory instead of cloning into the caller's
  working directory, and clean it up afterwards.
- Install only OCR4Linux.sh and OCR4Linux.py into the config directory,
  resolved from the script's own location, rather than copying the entire
  working directory.

README.md:
- Drop the image preprocessing claims to match what the code does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@moheladwy moheladwy self-assigned this Aug 13, 2026
@codacy-production

codacy-production Bot commented Aug 13, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 14 complexity · 0 duplication

Metric Results
Complexity 14
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

The added error handling pushed Program.main to 7 return statements, one
over pylint's limit of 6, failing the Python Lint workflow.

- Collapse the two identical except clauses into a single
  "except (TesseractUnavailableError, ValueError)" since both are handled
  the same way.
- Return check_arguments()'s code directly instead of branching on it,
  as anything other than 2 is already the final exit code.

Behaviour is unchanged; pylint now scores 10.00/10.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@moheladwy
moheladwy merged commit a7b2dfc into main Aug 27, 2026
6 checks passed
@moheladwy
moheladwy deleted the fix/robustness-and-arg-validation branch August 27, 2026 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant