Skip to content

Add pyjhora_batch: headless batch horoscope reports (PDF/TXT/JHD) - #64

Open
jivrajss wants to merge 2 commits into
naturalstupid:mainfrom
jivrajss:feat/pyjhora-batch
Open

Add pyjhora_batch: headless batch horoscope reports (PDF/TXT/JHD)#64
jivrajss wants to merge 2 commits into
naturalstupid:mainfrom
jivrajss:feat/pyjhora-batch

Conversation

@jivrajss

Copy link
Copy Markdown

Summary

Adds pyjhora_batch, a headless batch layer that turns a CSV/Excel of birth
details into per-person horoscope reports. It reuses PyJHora's engine
throughout and reimplements no calculations.

The report is extracted once as structured data (report_data.build_report)
and then rendered, so no output path needs Qt on screen:

Output Written by Notes
.txt text_writer wrapped plain-text report
.pdf pdf_writer vector PDF via reportlab — ~150 KB, searchable, selectable
.jhd jhd_writer Jagannatha Hora seed file, importable into the app

Notable points

Vector PDF instead of a widget screenshot. The original path captured the
Qt widget at ~130 DPI and embedded it as JPEG — roughly 10 MB per person,
blurry, not searchable. Typesetting the same data as real text gives ~150 KB.
The screenshot path remains as --pdf-mode screenshot, since it is the only
one that includes the drawn chart diagrams.

.jhd encoding. Every angular/temporal field packs as sexagesimal
D.MMSS (the digits after the point are literally minutes and seconds),
longitude and timezone are East-negative, latitude is North-positive, and
lines are CRLF. The person's name is never written to the file — JHora keeps it
in the filename. Derived byte-for-byte from a real export read back against the
app's own rendering of it.

Yoga tables report the rule, not a verdict. yoga_msgs_<lang>.json carries
a third field per yoga alongside name and condition. It is fixed boilerplate
keyed on the yoga name — identical for every chart the yoga fires in — and
several yogas match very loosely. _matrunasa_yoga_198_calculation returns
true whenever the Moon is hemmed by, associated with, or aspected by any
natural malefic, which covers a large majority of charts;
mathibhramana_yoga_294 ends in "aspected by or conjoined with any other
planet". Rendered per person next to a name and birth time, "The person's
mother will have a very early death" and "The person becomes insane" read as an
individual prognosis rather than as the classical rule text they are. The
tables show the yoga and the condition that matched, and note that only present
yogas are listed.

Happy to make that last one opt-in behind a flag instead if you'd rather keep
the current output as the default.

CLI

python -m pyjhora_batch births.csv -o reports

--no-pdf / --no-jhd / --no-txt to skip outputs, --pdf-mode {vector,screenshot}, repeatable --dhasa NAME (default vimsottari;
--dhasa all for every system PyJHora exposes), -w N for parallel workers.
Per-record failures are isolated and summarised rather than aborting the batch.

Dependencies

reportlab>=4.0 for the vector PDF. openpyxl (Excel input), pytest and
pypdf (test suite) stay optional — .txt and .jhd need nothing beyond
PyJHora itself.

Testing

169 passed, 1 skipped. Fixtures use a synthetic reference chart. The panchanga
and D1 expectations are captured from ChartTabbed.compute_horoscope rather
than from this code's own output, so they cross-check the headless path against
the GUI — in particular they catch a skipped drik.set_ayanamsa_mode, which
otherwise shifts every longitude silently.

jivrajss and others added 2 commits July 28, 2026 01:02
Two bugs prevented driving ChartTabbed without the interactive GUI:

1. compute_horoscope() calls config.initialize_runtime(), but `config`
   was only imported deep in the module under a __main__ guard, so at
   runtime it raised `NameError: name 'config' is not defined`. The
   exception was caught and logged, leaving self._horo unset and
   producing an empty PDF. Import `config` at module scope.

2. During construction, combo-box currentIndexChanged signals fire
   _kundali_chart_selection_changed -> _update_tab_chart_information ->
   _fill_panchangam_info, which dereference self._horo before the
   horoscope is computed (self._horo is None). Under PyQt6 an unhandled
   exception in a slot aborts the process. Guard both methods to return
   early when self._horo is None.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A batch layer over PyJHora's engine: a CSV/Excel of birth details in,
per-person reports out. Reimplements no calculations.

The report is extracted once as structured data (report_data.build_report)
and then rendered, so no output path needs Qt on screen:

* text_writer  -> wrapped plain-text report
* pdf_writer   -> vector PDF via reportlab, ~150 KB and searchable, versus
                  ~10 MB of 130-DPI JPEG for the Qt widget capture. That
                  capture is still available as --pdf-mode screenshot, since
                  it alone includes the drawn chart diagrams.
* jhd_writer   -> Jagannatha Hora .jhd, importable into the app. Every field
                  packs D.MMSS, longitude is East-negative, lines are CRLF;
                  the layout was derived byte-for-byte from a real export.

The Yoga and Raja Yoga tables report the yoga and the condition that matched,
and nothing else. The language resources carry a third "prediction" field, but
it is fixed boilerplate keyed on the yoga name -- identical for every chart the
yoga fires in -- and several yogas match very loosely, e.g.
_matrunasa_yoga_198_calculation is true whenever the Moon is hemmed by,
associated with, or aspected by any natural malefic, which covers most charts.
Printed next to a person's name and birth time, "The person's mother will have
a very early death" reads as an individual prognosis rather than as the
classical rule text it is.

CLI: --no-pdf / --no-jhd / --no-txt, --pdf-mode {vector,screenshot},
repeatable --dhasa (default vimsottari, 'all' for every system), -w N workers.

reportlab is required for the vector PDF; openpyxl (Excel input), pytest and
pypdf (tests) stay optional. Fixtures use a synthetic reference chart, and
the panchanga and D1 expectations are captured from ChartTabbed so they
cross-check the headless path rather than restating its own output.

169 passed, 1 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant