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.1

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.1
File Size Uploaded
pyswisseph_rs-0.1.1.tar.gz 148.8 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for pyswisseph-rs 0.1.1
File
pyswisseph_rs-0.1.1-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details
pyswisseph_rs-0.1.1-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.1-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.11 abi3 Linux glibc 2.17+ ARM64 Details
pyswisseph_rs-0.1.1-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl CPython 3.11 abi3 macOS 10.12+ universal2 (ARM64, x86-64), macOS 10.12+ x86-64, macOS 11.0+ ARM64 Details

Total release size: 5.3 MB

Release files / pyswisseph_rs-0.1.1.tar.gz

Download URL pyswisseph_rs-0.1.1.tar.gz
Size 148.8 kB
Tags Source
SHA-256 checksum
How to use checksums
a655ba9eaf9a6a546e50a84e9c88e03abad21903593cb9e9ac81ac39be53e6e8
BLAKE2b-256 checksum
How to use checksums
1b9c533f09d8a15d307b124ca84997b2721e42a67a7c785dd57fa5016dbb229c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

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

Download URL pyswisseph_rs-0.1.1-cp311-abi3-win_amd64.whl
Size 920.9 kB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
b083b86aba6136dc308a3c39d4dfbbbe31733ac9b693b0e4b19f2e1c1b0f3fed
BLAKE2b-256 checksum
How to use checksums
435f09be8053adc085ee5beebb95f4fd111448022539e6294b08d6de685675ee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

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

Download URL pyswisseph_rs-0.1.1-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
4945a7628fda9e63ceeeae6cafc9070d75b564bc8c3f059190f5b0913059ff6b
BLAKE2b-256 checksum
How to use checksums
939f09c262df4669245a1f385cd385f720eff6cc4fa44f8bc8c32308560b554a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

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

Download URL pyswisseph_rs-0.1.1-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
d2ebd575dcbdb558cb63275089877a49d720c24fd6a1a3db235d7d035dddbc50
BLAKE2b-256 checksum
How to use checksums
7230f42956f9cc3576964f2959713932e068065d76905253d5f86a5328ac48d8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

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

Download URL pyswisseph_rs-0.1.1-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
941416761f3b6609f6490fb01679b02d593d4025b9897ad30e4b359701f87c8a
BLAKE2b-256 checksum
How to use checksums
370ac7008dff9e2ef940c9a6efccf95574aa3f6da680fb44ba6bf80e45b57f54
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.1.2

5 release files

This release

0.1.1 This release

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