2025 Aug 27 – Ephem Devlog 02
I released v1 of Ephem, and like a newb immediately patched some graceful error handling for bizarre misuses I only imagined afterward. But! We are here to discuss ayanamsas, SQLite, my nemesis configparser, and plans for v2.
Ayanamsas
There are two zodiacs: the tropical zodiac and the sidereal zodiac.
The tropical zodiac assigns 0 Aries, the beginning of the zodiac, to the physical, celestial coordinate of the equinox. I would say the tropical zodiac is geocentric, and has more to do with our (northern hemisphere) experience of the seasons, and the calendar equinox as the first day of spring.
The sidereal zodiac is used in Indian astrology, by NASA, and a sizeable minority of western astrologers. The 30-degree wedges of each sidereal sign shift incrementally due to axial precession—the earth wobbling itself out of where it was 2,000 years ago—causing the apparent positions of the fixed zodiacal constellations to "move."
However, there is a lack of consensus about where, exactly, sidereal signs begin and end, or more specifically at which sign degrees certain fixed stars are located. Because the tropical zodiac doesn't change, sidereal zodiac offsets (ayanamsa) are calculated by subtraction from the tropical.
The Swiss Ephemeris library, which I import as "swe," has a function for this: swe.set_sid_mode()
, which in Ephem affects the output of swe.split_deg()
and the horoscope module that returns DMS placements. The sky is still the same 360 degrees; the signs are just aliases for arbitrary 30-degree wedges. Without split_deg
, we only get absolute longitude, a decimal degree between 0 an 359.9.
I only check sidereal placements when the whim takes me, but this is a pretty essential and easy feature to add when the world's majority of practicing astrologers likely belong to South Asian traditions. Right now Ephem only accepts an index from 0-46, no string input, so the optional flag --list-offsets
prints their key:value pairs.
SQLite skeleton
My SQL needs for v1 are very simple. For now, I only want to store time and geographic data, no actual chart information, so that pulling saved charts with ephem data load
just runs the ephem cast
command with saved values. The only SQL commands in my database module and thus the ephem data
subcommand are CREATE TABLE
, INSERT
, SELECT
, and DELETE
.
Analysis of the content of each chart is a dream far down the road that probably requires a web API, but the main logical constraint there is the two zodiacs. The database should store decimal degree values for both minimalism and flexibility, but that means if the user prefers sidereal, there should be an easy way to choose or configure the ayanamsa. However! The sort of analysis astrologers want is just like, key:value pairs where they're both strings. So in my (tropical zodiac) dreams, an SQLite row would look like
1 = {
"name": name,
...
"asc": None,
"sun": "sagittarius",
"moon": "cancer",
"mercury": "capricorn"
...
}
How would this ever accommodate sidereal? You see the issue. The database might just be geo/time data forever.
configparser 😠 + argparse
I went with the Python standard library configparser because... I don't know. I use foot on Sway, which also has a .ini config, so I figured it couldn't hurt.
Wrong!!!
I would divide the display options extant in v1 into three imperfect categories:
- Calculation: ayanamsa (
--offset=N
), North Node (--node {true,mean}
<= not a boolean)!,--classical
to exclude trans-saturnian planets - Aesthetic:
--theme {sect,mode,element}
,--format {glyphs,names,short}
,--bare
- ...Geography?: default location, options to hide coordinates and angles
This has flaws that I've only noticed as I use it, mostly to do with ephem data load
. But! configparser has to deal with three data types:
- floats:
--lat
and--lng
; - booleans:
--classial
,--no-angles
,--anonymize
(which i want to change to no-geo or no-coords for v2); - strings:
--node
,--theme
,--format
Something happens between argparse and configparser that I still don't understand. I suspect it has to do with my argparse implementation. Ayanamsa and coordinates are in a parent parser while the rest are in a helper function dropped into my several subparsers. My logic there was that the display options are only relevant to ephem now
, ephem cast
, and ephem data load
, ephem config save
... which is to say most commands except for my pesky, sentimental ephem asc
, a freak of a module that serves only my swaybar clock agenda.
Ephem CLI v2
Here's my roadmap:
- Get rid of
ephem asc
; it's cute but really only for me and confuses argparse. - Replace configparser with tomllib.
- ...maybe partially overhaul my parser because I'm not very happy with the
config
command. - Figure out a YAML front-end to the database! Because one thing I love about Astrolog is its plain text storage of chart data that is basically just commands. Very portable and easy to edit.
That's my progress! I'm very tired but very proud to have learned this much.
I'll say one word on vibe-coding and vibe-debugging, though: this is the ideal baby's first big project because I cannot rely on language models for the domain knowledge that is astrology. I tried! But GPT and Claude do not know shit about about it or the Swiss Ephemeris library. I should have known because one of my clients had previously paid an "astrologer" who gave her a model-generated "report" of her chart that was clearly scraped together from various cookbook-style astrology books like Parker's Astrology and The Only Astrology Book You'll Ever Need. Chart synthesis and knowing what we do with raw data is still up to humans, even if most astrologers never see decimal degrees. It's a multi-millennia old science (as in a system of knowledge) with so many approaches I would be impressed to find encapsulated in a language model.