A modern Python library for astrological chart calculation and visualization, built on the Swiss Ephemeris for astronomical accuracy.
Project description
🌟 Starlight
A modern, extensible Python library for computational astrology
Built on Swiss Ephemeris for NASA-grade astronomical accuracy, Starlight brings professional astrological calculations to Python with a clean, composable architecture that works for everyone—from quick scripts to production applications.
✨ Why Starlight?
For Python Developers
- Fully typed with modern type hints for excellent IDE support
- Protocol-driven architecture - extend with custom engines, no inheritance required
- Fluent builder pattern - chainable, readable, intuitive API
- Modular & composable - mix and match components as needed
- Production-ready with comprehensive test coverage
For Astrologers
- 23+ house systems including Placidus, Whole Sign, Koch, Equal, Regiomontanus, and more
- Sect-aware calculations with proper day/night chart handling
- 25+ Arabic Parts with traditional formulas
- Essential & accidental dignity scoring for both traditional and modern rulerships
- Beautiful visualizations with professional SVG chart rendering
- Notable births and events database for quick exploration and learning
Visual Chart Example
What Makes Starlight Different
Unlike other Python astrology libraries, Starlight is designed for extensibility:
# Other libraries: rigid, hard-coded calculations
chart = AstrologyLibrary(date, location) # That's all you can do
# Starlight: composable, configurable, extensible
chart = (ChartBuilder.from_native(native)
.with_house_systems([PlacidusHouses(), WholeSignHouses()]) # Multiple systems!
.with_aspects(ModernAspectEngine()) # Swap aspect engines
.with_orbs(LuminariesOrbEngine()) # Custom orb rules
.add_component(ArabicPartsCalculator()) # Plugin-style components
.add_component(MidpointCalculator()) # Stack as many as you want
.calculate()) # Lazy evaluation
- Performance - Advanced caching system makes repeated calculations fast
- Flexibility - Calculate multiple house systems simultaneously
- Accuracy - Swiss Ephemeris provides planetary positions accurate to fractions of an arc-second
- Modern Python - Takes full advantage of Python 3.11+ features
Installation
pip install starlight-astro
Requirements
- Python 3.11 or higher
- All dependencies installed automatically (pyswisseph, pytz, geopy, rich, svgwrite)
Quick Start
Your First Chart (3 Lines of Code)
from starlight import ChartBuilder, draw_chart
chart = ChartBuilder.from_notable("Albert Einstein").calculate()
draw_chart(chart, "einstein.svg")
That's it! You now have a professional natal chart SVG for Einstein.
The from_notable() factory method uses our curated database of famous births. Other notables include: "Carl Jung", "Frida Kahlo", "Marie Curie", and more.
Your Own Chart
from datetime import datetime
from starlight import ChartBuilder, Native
# Create a Native (birth data container)
native = Native(
datetime_input=datetime(2000, 1, 6, 12, 00), # Naive or timezone-aware
location_input="Seattle, WA" # City name or (lat, lon)
)
# Build and calculate the chart
chart = ChartBuilder.from_native(native).calculate()
# Access planetary positions
sun = chart.get_object("Sun")
print(sun)
moon = chart.get_object("Moon")
print(moon)
print(moon.phase)
Sun: 0°0' Libra (180°)
Moon: 0°0' Aries (0°)
Phase: Full (100% illuminated)
Key Features:
- Automatic geocoding (city name → coordinates)
- Automatic timezone handling (naive datetimes converted to UTC)
- Default house system is Placidus, default aspects are major (Ptolemaic)
Progressive Examples
Level 1: Exploring Chart Data
from starlight import ChartBuilder, Native
from datetime import datetime
native = Native(datetime(2000, 1, 6, 12, 00), "Seattle, WA")
chart = ChartBuilder.from_native(native).calculate()
# Get all planets
for planet in chart.get_planets():
print(planet)
# Get aspects
for aspect in chart.aspects:
print(aspect)
# Get house cusps
houses = chart.get_houses() # Returns HouseCusps for default (or first) system
print(houses)
Level 2: Custom House Systems & Aspects
from starlight import ChartBuilder, Native
from starlight.engines import WholeSignHouses, ModernAspectEngine, SimpleOrbEngine
from datetime import datetime
native = Native(datetime(2000, 1, 6, 12, 00), "Seattle, WA")
chart = (ChartBuilder.from_native(native)
.with_house_systems([WholeSignHouses()]) # Use Whole Sign houses
.with_aspects(ModernAspectEngine()) # Explicit aspect engine
.with_orbs(SimpleOrbEngine()) # Simple orb rules
.calculate())
print(f"House System: {chart.default_house_system}")
# Access house cusps for the specific system
whole_sign_cusps = chart.get_house_cusps("Whole Sign")
print(whole_sign_cusps.get_description(1)) # First House
Available House Systems: Placidus (default), Whole Sign, Koch, Equal, Regiomontanus, Campanus, Porphyry, Alcabitius, Equal (MC), Vehlow Equal, Topocentric, Morinus, and 11+ more.
Level 3: Multiple House Systems
from starlight import ChartBuilder, Native
from starlight.engines import PlacidusHouses, WholeSignHouses, KochHouses
native = Native(datetime(2000, 1, 6, 12, 00), "Seattle, WA")
chart = (ChartBuilder.from_native(native)
.with_house_systems([
PlacidusHouses(),
WholeSignHouses(),
KochHouses()
])
.calculate())
# Access each system independently
sun = chart.get_object("Sun")
print(f"Sun in Placidus House: {sun.house}")
# House placements are tracked per-system
sun_ws_house = sun.house_placements.get("Whole Sign")
print(f"Sun in Whole Sign House: {sun_ws_house}")
sun_koch_house = sun.house_placements.get("Koch")
print(f"Sun in Koch House: {sun_koch_house}")
Level 4: Arabic Parts & Components
from starlight import ChartBuilder, Native
from starlight.components import ArabicPartsCalculator, MidpointCalculator
from datetime import datetime
native = Native(datetime(2000, 1, 6, 12, 00), "Seattle, WA")
chart = (ChartBuilder.from_native(native)
.add_component(ArabicPartsCalculator())
.add_component(MidpointCalculator())
.calculate())
# Arabic Parts (automatically sect-aware)
arabic_parts = chart.get_component_result("Arabic Parts")
for part in arabic_parts:
print(f"{part.name:25} {part.longitude:6.2f}° {part.sign:12} House {part.house}")
# Midpoints
midpoints = chart.get_component_result("Midpoints")
for mp in midpoints[:5]: # First 5 midpoints
print(f"{mp.object1.name}/{mp.object2.name} midpoint: {mp.longitude:.2f}°")
Available Components:
ArabicPartsCalculator- 25+ traditional lots (Part of Fortune, Spirit, Love, etc.)MidpointCalculator- Direct midpoints for all planet pairsDignityComponent- Essential dignities (rulership, exaltation, triplicity, etc.)AccidentalDignityComponent- House-based accidental dignities
Level 5: Terminal Reports with Rich
from starlight import ChartBuilder, Native, ReportBuilder
from datetime import datetime
native = Native(datetime(2000, 1, 6, 12, 00), "Seattle, WA")
chart = ChartBuilder.from_native(native).calculate()
# Build a beautiful terminal report
report = (ReportBuilder()
.from_chart(chart)
.with_chart_overview() # Chart metadata (date, location, etc.)
.with_planet_positions() # Planetary positions table
.with_aspects(mode="major")) # Major aspects table
report.render(format="rich_table") # Rich terminal formatting
report.render(format="plain_table", file="my_chart.txt") # Export to file
Level 6: Advanced - Custom Visualization
from starlight import ChartBuilder, Native, ChartRenderer
from starlight.visualization.layers import (
ZodiacLayer, HouseCuspLayer, PlanetLayer,
AspectLayer, AngleLayer
)
from datetime import datetime
native = Native(datetime(2000, 1, 6, 12, 00), "Seattle, WA")
chart = ChartBuilder.from_native(native).calculate()
# Manual layer assembly for custom charts
rotation = chart.get_object("ASC").longitude
renderer = ChartRenderer(size=800, rotation=rotation)
dwg = renderer.create_svg_drawing("custom_chart.svg")
# Add layers in order (bottom to top)
layers = [
ZodiacLayer(),
HouseCuspLayer(house_system_name="Placidus"),
AngleLayer(),
AspectLayer(),
PlanetLayer()
]
for layer in layers:
layer.render(renderer, dwg, chart)
dwg.save()
Use Cases for Custom Layers:
- Synastry (bi-wheel) charts
- Transit overlays
- Custom styling and colors
- Educational diagrams
- Research visualizations
Command-Line Interface
Starlight includes a CLI for quick chart generation:
# Generate a chart from the notable database
starlight chart notable "Albert Einstein" --output einstein.svg
# Manage ephemeris data
starlight ephemeris download --years 1000-3000
# Clear calculation cache
starlight cache clear
See starlight --help for full CLI documentation.
🔍 Feature Highlights
Celestial Objects
Calculate positions for 50+ celestial objects:
- Planets: Sun, Moon, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto
- Asteroids: Chiron, Ceres, Pallas, Juno, Vesta
- Lunar Nodes: North Node, South Node, True Node, Mean Node
- Lunar Apogee: Lilith (Mean, True, Osculating, Interpolated)
- Chart Points: Ascendant, Midheaven, Descendant, IC, Vertex, East Point
Aspect Calculations
- Major Aspects (Ptolemaic): Conjunction (0°), Opposition (180°), Square (90°), Trine (120°), Sextile (60°)
- Minor Aspects: Semi-sextile (30°), Semi-square (45°), Sesquiquadrate (135°), Quincunx (150°)
- Harmonic Aspects: Quintile (72°), Bi-quintile (144°), Septile (51.43°), Novile (40°), and more
- Configurable Orbs: Simple, Luminaries-specific, or Complex (aspect-and-planet-pair-specific) orb engines
Dignities
- Essential Dignities: Ruler, Exaltation, Triplicity (by sect), Bound, Decan, Detriment, Fall
- Accidental Dignities: House placement, angular/succedent/cadent, joy
- Both Traditional & Modern rulerships supported
Data Export
# Export to dictionary for JSON serialization
data = chart.to_dict()
# Includes:
# - All planetary positions with coordinates
# - House cusps for all calculated systems
# - All aspects with orbs
# - Component results (Arabic Parts, midpoints, etc.)
# - Chart metadata (date, location, timezone)
Performance
from starlight.utils.cache import enable_cache, get_cache_stats
enable_cache(max_age_seconds=604800) # 1 week cache
# First calculation: ~200ms
chart1 = ChartBuilder.from_native(native).calculate()
# Subsequent calculations: ~10ms (20x faster!)
chart2 = ChartBuilder.from_native(native).calculate()
stats = get_cache_stats()
print(f"Cache hits: {stats['hits']}, misses: {stats['misses']}")
📖 Documentation & Learning
Examples
The /examples directory contains runnable code:
viz_examples.py- Chart visualization techniquesreport_examples.py- Terminal report generationchart_examples/- Gallery of generated charts
Additional Documentation
- CONTRIBUTING.md - How to contribute (development guide)
- CHANGELOG.md - Release history
Interactive Learning
# Install with examples
git clone https://github.com/katelouie/starlight.git
cd starlight
pip install -e .
# Run examples
python examples/viz_examples.py
python examples/report_examples.py
Architecture Philosophy
Starlight is built on three core principles:
1. Protocols over Inheritance
Extend functionality by implementing protocols, not subclassing:
from starlight.core.protocols import ChartComponent
from typing import Protocol
class MyCustomComponent:
"""Add custom calculations without inheritance."""
@property
def component_name(self) -> str:
return "My Feature"
def calculate(self, chart_data, config):
# Your calculations here
return results
# Use it:
chart = ChartBuilder.from_native(native).add_component(MyCustomComponent()).calculate()
2. Composability
Mix and match components freely:
# Every piece is optional and interchangeable
chart = (ChartBuilder.from_native(native)
.with_house_systems([PlacidusHouses(), WholeSignHouses()]) # Multiple systems
.with_aspects(ModernAspectEngine()) # Choose aspect engine
.with_orbs(LuminariesOrbEngine()) # Choose orb calculator
.add_component(ArabicPartsCalculator()) # Add components
.add_component(MidpointCalculator()) # Stack them up
.calculate())
3. Immutability
All calculation results are immutable dataclasses:
# Results are frozen - safe to cache and share
sun = chart.get_object("Sun")
sun.longitude = 100 # ❌ Error: frozen dataclass
# This makes caching safe and reliable
cached_chart = chart # Safe to reuse
Benefits:
- Thread-safe calculations
- Reliable caching
- No accidental mutations
- Easy to reason about
Testing
Starlight has comprehensive test coverage:
# Run all tests
pytest
# Run with coverage
pytest --cov=src --cov-report=term-missing
# Run specific test categories
pytest tests/test_chart_builder.py
pytest tests/test_integration.py
🗺️ Roadmap
Coming Soon
- Synastry Charts: Bi-wheel visualizations and inter-chart aspects
- Transit Calculations: Current planetary positions against natal chart
- Progressions: Secondary progressions and solar arc directions
- Additional Chart Types: Returns, composites, and harmonic charts
- Sidereal Support: Sidereal zodiac calculations
- Enhanced Visualizations: More chart styles and customization options
See TODO.md for the full development roadmap.
Contributing
We welcome contributions from both Python developers and astrologers! Whether you want to:
- Add new calculation engines
- Improve documentation
- Fix bugs
- Add new features
- Share examples
Please see CONTRIBUTING.md for detailed guidelines.
Quick Start for Contributors:
git clone https://github.com/katelouie/starlight.git
cd starlight
pip install -e ".[dev]" # Install with dev dependencies
pre-commit install # Set up pre-commit hooks
pytest # Run tests
License
Starlight is released under the MIT License. See LICENSE for details.
Note on Swiss Ephemeris: This library uses the Swiss Ephemeris, which has its own licensing terms for commercial use. See the Swiss Ephemeris website for details.
Acknowledgments
- Swiss Ephemeris - Astronomical calculations of exceptional accuracy
- Astro.com - Ephemeris data and astrological resources
- PySwissEph - Python bindings for Swiss Ephemeris
Community & Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: katehlouie@gmail.com
Built with precision, designed for everyone ✨
Whether you're building a professional astrology application, researching astrological patterns, or learning computational astrology—Starlight provides the tools you need with a modern, extensible architecture.
Star the repo if you find it useful! ⭐
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file starlight_astro-0.2.0.tar.gz.
File metadata
- Download URL: starlight_astro-0.2.0.tar.gz
- Upload date:
- Size: 3.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1276b41dfcb2aa63b1d48c89d401cf4c6e120b0f9ccef0aae711d5d57187a312
|
|
| MD5 |
e4a1478606a7b801c44329cde4abd377
|
|
| BLAKE2b-256 |
c64676347ce3eab3b9cb03bd5e07dbb6c7bd9e628772d887ee80fd1359265bdb
|
File details
Details for the file starlight_astro-0.2.0-py3-none-any.whl.
File metadata
- Download URL: starlight_astro-0.2.0-py3-none-any.whl
- Upload date:
- Size: 110.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
561fea90bdfa780d477e8ea82702c8ef5ed45eb38b6d5ecd08ab4fac58e34bcc
|
|
| MD5 |
9665bb19f9298b0170dd07543ce2280c
|
|
| BLAKE2b-256 |
75b9ddd764abf5007024cbe8ca56f6ddd18df735edc4531a13c14b6a97938ab7
|