Skip to main content

openephem

CI PyPI Python License: MIT

A permissive, Swiss-Ephemeris-validated ephemeris & chart engine. MIT-licensed, no AGPL — validated to arcseconds against Swiss Ephemeris across year 0–2500.

Most "open" astrology libraries wrap pyswisseph, which is AGPL: use it in a network service and you must publish your whole app's source (or buy a commercial license). openephem is built entirely on permissive / public-domain sources (Skyfield MIT, JPL/NASA public domain, ESA Hipparcos, IANA tzdata, OSM), so you can ship it in a closed-source product with no copyleft obligation — and it's checked against swisseph so you don't sacrifice accuracy for freedom.

Install

pip install openephem            # core: planets + fixed stars + chart math
pip install "openephem[full]"    # + asteroids (spiceypy) + geocoding (geopy/tz)

Extras: openephem[asteroids] (Chiron/Ceres/Pallas/Juno/Vesta), openephem[geo] (place-name → lat/lon → timezone). Pure Python — no compiler.

Ephemeris data (JPL DE440 ~114 MB, Hipparcos, asteroid SPK kernels) is fetched at runtime, not shipped: Skyfield auto-downloads DE440/Hipparcos on first use; asteroid kernels are generated with openephem-fetch-kernels.

Quick start

from openephem import resolve, assemble, render_svg

moment = resolve(date=(1990, 5, 15), time=(14, 30), place="New York, NY")
chart  = assemble(moment, house_system="Placidus")     # tropical
svg    = render_svg(chart, title="Natal chart")

vedic  = assemble(moment, zodiac="sidereal", ayanamsa="lahiri")  # nakshatras + rashis

Everything degrades gracefully: without the ephemeris data (or the optional deps) you still get houses, angles, and aspects, plus warnings for what's missing.

What it computes

Bodies Sun–Pluto, Moon, mean/true Node, mean/osculating Lilith, Chiron + Ceres/Pallas/Juno/Vesta, 32 named fixed stars
Houses Placidus, Koch, Regiomontanus, Campanus, Whole Sign, Equal, Porphyry, + Asc/MC/Vertex/East Point
Aspects majors + optional minors, configurable orbs, applying/separating
Zodiacs tropical and Vedic sidereal (Lahiri, Fagan-Bradley, Krishnamurti, Raman) + nakshatras/padas/rashis
Time & place timezone/DST/historical/LMT (IANA tzdata), Julian↔Gregorian calendar, offline coord→timezone, place geocoding
Output serializable chart dict, self-contained SVG chart wheel, zero-dep HTTP API

Validation — parity vs swisseph: PASS (year 0–2500)

3044 instants over 2500 years, Skyfield candidate vs swisseph authority with ΔT aligned so the test isolates the ephemeris. Candidate ephemeris in two segments: DE441 part-1 (0–1550, since DE440 starts at 1550) and DE440 (1550–2500). Max ecliptic-longitude error per group (worst case over the full 2500 years):

Group max err Group max err
Sun + Jupiter–Pluto < 0.4" Mean / True Node 2.6" / 2.6"
Mercury / Venus / Mars < 3.6" Mean / Oscu Lilith 18.4" / 1.7"
Moon < 27" (note) 32 fixed stars < 29" (Castor)
Chiron + Ceres/Pallas/Juno/Vesta < 11" (note) Houses (all 7) < 20"

Zero real sign-flips. Within 1900–2100 the whole set agrees to milliarcsec– tenths; the table is the worst case over 2500 years, dominated by physical / documented antiquity effects (all astrologically negligible, none a code error):

  • ΔT diverges past ~2100 (extrapolation) and is ~3 h by year 0 — a real timekeeping uncertainty, aligned out in the parity test; production uses Skyfield's ΔT (agrees with swisseph 1900–2100).
  • Moon / inner planets in deep antiquity — DE431 (swisseph) vs DE441 (candidate) ephemeris-vintage divergence.
  • Asteroids — JPL vs swisseph use different orbit solutions that drift over centuries (≤ 11" = 0.003°).
  • Fixed stars — high-proper-motion multiples (Castor, Altair) as swisseph's vs Hipparcos's proper motions accumulate over 2500 years.

How the tricky quantities match swisseph (all coefficients fit offline vs swisseph — the numbers are astronomical facts, not copyrightable): osculating Node/Lilith from Skyfield's of-date ecliptic; mean Node/Lilith = Meeus mean elements + nutation-in-longitude (+ the 2·(perigee−node) term for Lilith); houses use apparent sidereal time (with a long-term precession correction) + true obliquity; asteroids read Horizons SPK type 21 (which jplephem can't) via spiceypy, then Skyfield does the of-date conversion.

Reproduce it yourself — see Development & validation below.

Chart API + SVG

openephem-serve --port 8080          # zero-dependency stdlib HTTP service

POST /chart → chart JSON + embedded SVG; POST /chart.svg → image; GET /health. Body:

{"date":[1990,5,15],"time":[14,30],"place":"New York, NY","house_system":"Placidus",
 "zodiac":"tropical"}

Run it behind your web server and add auth there — the service does none itself.

Layout

src/openephem/        # the installable, MIT, swisseph-free package
  planets_skyfield  asteroids_skyfield  fixed_stars   # position engines
  houses  aspects  vedic                              # chart math (pure stdlib)
  timeplace  chart  wheel  service  fetch_kernels     # pipeline + output
validation/           # dev tools — NOT installed; import pyswisseph (AGPL)
  generate_oracle.py  run_parity.py

Development & validation

The validation harness compares the permissive engines against swisseph. It is not part of the shipped package; running it is your own choice and needs pyswisseph (AGPL) installed separately:

pip install -e ".[full]" pyswisseph        # editable install + swisseph, locally
openephem-fetch-kernels --out ./kernels    # asteroid SPK kernels (Horizons)
# generate the swisseph oracle, then check the permissive engines against it:
python validation/generate_oracle.py --ephe-path ./ephe --fixed-stars \
    --start 0 --end 2500 --step-days 120 --out ./fixtures
python validation/run_parity.py --fixtures ./fixtures --de440 de440.bsp --kernel-dir ./kernels

Swiss Ephemeris .se1 data and sefstars.txt (for the oracle authority) are not included — download them from the swisseph distribution. No AGPL code or data is redistributed in this repo.

Tests

pip install -e ".[test]" && pytest

A fast, offline, data-free suite (houses, aspects, vedic, timeplace, wheel, chart — no network, no ephemeris files). Exactness tests that compare the house systems against swe_houses run automatically when pyswisseph is installed and skip otherwise, so the MIT test run needs no AGPL dependency. CI (GitHub Actions) runs it on Python 3.10–3.13 (Linux + Windows) and proves the wheel builds and installs.

Licensing

MIT (see LICENSE). Third-party libraries/data keep their own licenses (Skyfield MIT, spiceypy/CSPICE, Moshier PD, JPL/NASA PD, ESA Hipparcos, OpenStreetMap ODbL, IANA tzdata PD) — full notices in references.txt. Swiss Ephemeris (AGPL) is not distributed here; it is used only by the optional offline validation tools.

Out of scope (by design)

  • Interpretation / "reading" layer — turning a computed chart into meaning is editorial content, not computation; it belongs to the consuming application.
  • Site integration (WordPress, auth, hosting) — this is a self-contained engine + service; wiring it into a website is the consumer's job.

Authors

© 2026 Elizabeth Huston, Ph.D. and Noah Christian, Ph.D.
Contact: elpisastrology@gmail.com · elpisastrology.com and noahchristian@gmail.com

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openephem-0.1.0.tar.gz (60.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openephem-0.1.0-py3-none-any.whl (53.8 kB view details)

Uploaded Python 3

File details

Details for the file openephem-0.1.0.tar.gz.

File metadata

  • Download URL: openephem-0.1.0.tar.gz
  • Upload date:
  • Size: 60.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for openephem-0.1.0.tar.gz
Algorithm Hash digest
SHA256 34e93dda9f4ce9ac9937e6fcba173c515979f7b2f069997c50e3f155f385d11e
MD5 ac2892803e3e5dd2b0e2ad04e8315cba
BLAKE2b-256 d73a01fa055568ea59c20413d7ff6456589ce971f652f38897c925e12845d98c

See more details on using hashes here.

Provenance

The following attestation bundles were made for openephem-0.1.0.tar.gz:

Publisher: publish.yml on NoahChristian/openephem

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file openephem-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: openephem-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 53.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for openephem-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 df9f654fa807c5f6a0bc53247e41b589aaa6ad4204637d102602828c7a48e1b9
MD5 c645ca32e7287cfa2424c4864b381d8d
BLAKE2b-256 74b39d1976e28fc16234e6cff752edd5505cc2fb89ed6676e89e03fd4bcd7cf2

See more details on using hashes here.

Provenance

The following attestation bundles were made for openephem-0.1.0-py3-none-any.whl:

Publisher: publish.yml on NoahChristian/openephem

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page