Skip to main content

pyswisseph-rs

Python bindings for the swisseph-rs crate — a pure-Rust reimplementation of the Swiss Ephemeris.

Why this package? Every method on Ephemeris releases the GIL, so a single shared instance can drive a ThreadPoolExecutor at full core utilization with zero coordination. No global state, no swe_close(), no mutex — just pass the same object to every thread.

pip install pyswisseph-rs     # or: uv add pyswisseph-rs

Quickstart (zero files, Moshier ephemeris)

The built-in Moshier analytical ephemeris covers all planets for any date without ephemeris files. Accuracy is ~1 arc-second for modern dates.

from swisseph_rs import Body, CalcFlags, Ephemeris, EphemerisConfig

eph = Ephemeris(EphemerisConfig())   # Moshier by default, no files needed
result = eph.calc_ut(2451545.0, Body.SUN, CalcFlags.SPEED)

lon, lat, dist, lon_speed, lat_speed, dist_speed = result.data
print(f"Sun longitude at J2000: {lon:.6f}°")

Using Swiss Ephemeris data files

For sub-arc-second precision, point EphemerisConfig at a directory containing the Swiss Ephemeris data files:

from swisseph_rs import Ephemeris, EphemerisConfig, EphemerisSource

eph = Ephemeris(EphemerisConfig(
    ephemeris_source=EphemerisSource.SWISS,
    ephe_path="/path/to/ephe",
))

Data files (sepl*.se1, semo*.se1, seas*.se1, etc.) are available from Astrodienst. Download the files covering your date range and place them in the directory you point ephe_path to.

For JPL ephemerides, set ephemeris_source=EphemerisSource.JPL and optionally jpl_filename="de441.eph".

Threading

pyswisseph-rs is designed for concurrent workloads. Every Ephemeris method releases the GIL around the Rust computation, so multiple Python threads run in true parallel on separate cores.

import concurrent.futures
from swisseph_rs import Body, CalcFlags, Ephemeris, EphemerisConfig

eph = Ephemeris(EphemerisConfig())
bodies = [Body.SUN, Body.MOON, Body.MERCURY, Body.VENUS, Body.MARS,
          Body.JUPITER, Body.SATURN]

def calc_year(year_offset):
    """Calculate daily positions for one year."""
    jd_start = 2451545.0 + year_offset * 365.25
    results = []
    for day in range(365):
        for body in bodies:
            r = eph.calc_ut(jd_start + day, body, CalcFlags.SPEED)
            results.append(r.data[0])  # longitude
    return results

# Same Ephemeris instance shared across all threads — no copies, no locks
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool:
    futures = [pool.submit(calc_year, y) for y in range(20)]
    all_results = [f.result() for f in futures]

This consistently achieves near-linear speedup (e.g. ~3.5x on 4 cores). Results are bit-identical to serial execution.

What about multiprocessing?

Ephemeris is not picklable. For process-based parallelism, construct a separate Ephemeris in each worker. But threading is usually the better choice here — there is no GIL contention, so threads give you the speedup without the IPC overhead.

Sidereal mode and topographic position

Configuration that the C library sets via global state (swe_set_sid_mode, swe_set_topo) is passed through EphemerisConfig instead:

from swisseph_rs import (
    Ephemeris, EphemerisConfig, SiderealMode, TopoPosition,
)

eph = Ephemeris(EphemerisConfig(
    sidereal_mode=SiderealMode.LAHIRI,
    topographic=TopoPosition(longitude=-74.006, latitude=40.7128, altitude=10.0),
))

The config is frozen after construction — no mutable global state, no ordering bugs between set_* calls.

Migrating from C pyswisseph

pyswisseph-rs wraps the same Swiss Ephemeris engine but replaces the C library's global-state API with an object-oriented, stateless design. The key differences:

  1. No global state. swe_set_ephe_path, swe_set_sid_mode, swe_set_topo become fields on EphemerisConfig. swe_close is unnecessary.
  2. Methods on Ephemeris. Functions like swe_calc become eph.calc().
  3. Named types. Flags are CalcFlags.SPEED, bodies are Body.SUN, not raw integers.

Every method's docstring includes the corresponding swe_* name. Use help(eph.calc) or check the type stubs for the mapping.

Function mapping (top 25)

C pyswisseph pyswisseph-rs
swe_calc(jd, ipl, iflag) eph.calc(jd, body, flags)
swe_calc_ut(jd, ipl, iflag) eph.calc_ut(jd, body, flags)
swe_calc_pctr(jd, ipl, ictr, iflag) eph.calc_pctr(jd, body, center, flags)
swe_fixstar2(star, jd, iflag) eph.fixstar2(star, jd, flags)
swe_fixstar2_ut(star, jd, iflag) eph.fixstar2_ut(star, jd, flags)
swe_fixstar2_mag(star) eph.fixstar2_mag(star)
swe_houses(jd, lat, lon, hsys) eph.houses(jd, lat, lon, hsys)
swe_houses_ex(jd, iflag, lat, lon, hsys) eph.houses_ex(jd, flags, lat, lon, hsys)
swe_house_pos(armc, lat, eps, hsys, ...) houses.house_pos(armc, lat, eps, hsys, xpin)
swe_get_ayanamsa_ex(jd, iflag) eph.get_ayanamsa_ex(jd, flags)
swe_julday(y, m, d, h, cal) date.julday(y, m, d, h, cal)
swe_revjul(jd, cal) date.revjul(jd, cal)
swe_utc_to_jd(y,m,d,h,mi,s, cal) date.utc_to_jd(utc, cal, eph)
swe_day_of_week(jd) date.day_of_week(jd)
swe_rise_trans(...) eph.rise_trans(...)
swe_pheno_ut(jd, ipl, iflag) eph.pheno_ut(jd, body, flags)
swe_nod_aps_ut(jd, ipl, iflag, method) eph.nod_aps_ut(jd, body, flags, method)
swe_sol_eclipse_when_glob(jd, iflag, ifltype, bwd) eph.sol_eclipse_when_glob(jd, flags, ifltype, backward)
swe_lun_eclipse_when(jd, iflag, ifltype, bwd) eph.lun_eclipse_when(jd, flags, ifltype, backward)
swe_get_orbital_elements(jd, ipl, iflag) eph.get_orbital_elements(jd, body, flags)
swe_split_deg(ddeg, roundflag) math.split_degrees(ddeg, flags)
swe_sidtime(jd) sidereal_time.sidereal_time(jd, config)
swe_refrac(inalt, atpress, attemp, dir) azalt.refrac(inalt, atpress, attemp, dir)
swe_set_ephe_path(path) EphemerisConfig(ephe_path=path)
swe_set_sid_mode(sid_mode, t0, ayan_t0) EphemerisConfig(sidereal_mode=..., sidereal_t0=..., sidereal_ayan_t0=...)
swe_set_topo(lon, lat, alt) EphemerisConfig(topographic=TopoPosition(...))
swe_close() (not needed — no global state)

Module structure

Free functions live in submodules mirroring the Rust crate's module tree:

from swisseph_rs import date, math, houses, azalt, sidereal_time

Types and flags are re-exported at the top level:

from swisseph_rs import Body, CalcFlags, EphemerisConfig, Ephemeris

Design and transliteration discipline

pyswisseph-rs maintains a strict 1:1 correspondence with the underlying Rust crate's public API. Every Python class, enum, and function mirrors exactly one Rust symbol. This is a deliberate design choice documented in CONTEXT.md and the architecture decision records in docs/adr/:

  • ADR 0001 — PyO3 on the lib crate, not the C FFI layer
  • ADR 0002 — strict 1:1 transliteration from Rust to Python

License

This project is licensed under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later). See LICENSE for the full text.

The wheel statically links the swisseph-rs crate, which is a derivative work of the Swiss Ephemeris by Astrodienst AG, also licensed under AGPL-3.0-or-later.

Release files for pyswisseph-rs 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyswisseph-rs 0.1.2
File Size Uploaded
pyswisseph_rs-0.1.2.tar.gz 149.2 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for pyswisseph-rs 0.1.2
File
pyswisseph_rs-0.1.2-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details
pyswisseph_rs-0.1.2-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 abi3 Linux glibc 2.17+ x86-64 Details
pyswisseph_rs-0.1.2-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.11 abi3 Linux glibc 2.17+ ARM64 Details
pyswisseph_rs-0.1.2-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl CPython 3.11 abi3 macOS 10.12+ x86-64, macOS 11.0+ ARM64, macOS 10.12+ universal2 (ARM64, x86-64) Details

Total release size: 5.3 MB

Release files / pyswisseph_rs-0.1.2.tar.gz

Download URL pyswisseph_rs-0.1.2.tar.gz
Size 149.2 kB
Tags Source
SHA-256 checksum
How to use checksums
21ffb32ebf71ce10ffbf5012898e6ff33b7b4cdd3902afd0686c54e75aaf3241
BLAKE2b-256 checksum
How to use checksums
f33ad78cece6682167bbf21cf5897f521e1ec7d79d49b4176a3092165adf3cc3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / pyswisseph_rs-0.1.2-cp311-abi3-win_amd64.whl

Download URL pyswisseph_rs-0.1.2-cp311-abi3-win_amd64.whl
Size 924.3 kB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
e3930e549abf4af701ffb518a70812290a4e32ef4343f7ee8bdff64efb530220
BLAKE2b-256 checksum
How to use checksums
a219d8fdbb4b1fd48a64d52660dbaed740d99f109ff426ea045a4c471ab856b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / pyswisseph_rs-0.1.2-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL pyswisseph_rs-0.1.2-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.1 MB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
38626e3fba04e3dc087d84df174a6b9fdc9728639663ef3cfd7eb1daaaed060e
BLAKE2b-256 checksum
How to use checksums
e4ab3554281283ca2d82845d46340033ae753b073e65e0064fd2b0464926c86f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / pyswisseph_rs-0.1.2-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL pyswisseph_rs-0.1.2-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 1.1 MB
Tags CPython 3.11 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
dc1cbc640c036b9ad2ce39972bb09421313de24aed43438220b81ff86ed4644a
BLAKE2b-256 checksum
How to use checksums
920823a0cf54d42a985609f20e099320d157ac5cf6198b7425209d8fc58ea671
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / pyswisseph_rs-0.1.2-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl

Download URL pyswisseph_rs-0.1.2-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Size 2.0 MB
Tags CPython 3.11 abi3 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
5fa8bf346ad8574de9cd5c8570f295c5880568b6340aad011c9e3f7df0ccc669
BLAKE2b-256 checksum
How to use checksums
5fdf027c77462d3aec80d4cfaf0f31946bfab100cb580fcaab9e933c368f807e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.1.2 This release

5 release files

0.1.1

5 release files

0.1.0

5 release 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