Modern Python client library for the Astrology API v3. Get planetary positions, generate charts, analyze transits, and more with a fully typed, developer-friendly interface.
- 🌟 Full API Coverage: Access all 150+ endpoints across 16 category clients
- 🔒 Type-Safe: Complete type hints with Pydantic models for validation
- ♻️ Automatic Retry: Built-in retry logic for transient failures
- 🐍 Modern Python: Requires Python 3.10+ with contemporary type annotations
- ✅ 100% Test Coverage: Comprehensive test suite with full coverage
- 🚀 Zero Dependencies: Only httpx and pydantic as runtime dependencies
- 📖 Rich Documentation: Extensive docstrings and examples
pip install astroapi-pythonfrom astroapi import AstrologyClient, Subject, BirthData
# Initialize client (reads ASTROLOGY_API_KEY from environment)
client = AstrologyClient()
# Or provide API key directly
from astroapi.types import AstrologyClientConfig
config = AstrologyClientConfig(api_key="your_api_key_here")
client = AstrologyClient(config)
# Create a subject
subject = Subject(
name="John Doe",
birth_data=BirthData(
year=1990,
month=1,
day=1,
hour=12,
minute=0,
latitude=40.7128,
longitude=-74.0060,
timezone="America/New_York"
)
)
# Get planetary positions
from astroapi.types import PlanetaryPositionsRequest
positions_request = PlanetaryPositionsRequest(
year=1990, month=1, day=1, hour=12, minute=0,
latitude=40.7128, longitude=-74.0060
)
positions = client.data.get_positions(positions_request)
# Generate natal chart
from astroapi.types import NatalChartRequest
chart_request = NatalChartRequest(subject=subject)
chart = client.charts.get_natal_chart(chart_request)
# Get daily horoscope
from astroapi.types import PersonalizedHoroscopeRequest
horoscope_request = PersonalizedHoroscopeRequest(
subject=subject,
horoscope_type="daily"
)
horoscope = client.horoscope.get_personal_daily_horoscope(horoscope_request)| Variable | Description | Default |
|---|---|---|
ASTROLOGY_API_KEY |
Your API key | Required |
ASTROLOGY_API_BASE_URL |
Custom base URL | https://api.astrology-api.io |
ASTROLOGY_DEBUG |
Enable debug logging | False |
from astroapi import AstrologyClient
from astroapi.types import AstrologyClientConfig, RetryConfig
config = AstrologyClientConfig(
api_key="your_api_key",
base_url="https://api.astrology-api.io",
timeout=10.0, # seconds
retry=RetryConfig(
attempts=3,
delay_ms=250,
retry_status_codes=[408, 429, 500, 502, 503, 504]
),
debug=True,
logger=lambda msg, details: print(f"[LOG] {msg}: {details}")
)
client = AstrologyClient(config)from astroapi import AstrologyClient
# Automatically cleanup resources
with AstrologyClient() as client:
positions = client.data.get_positions(request)
# Client is automatically closed when exiting the contextThe library organizes endpoints into 16 category clients:
| Client | Description | Key Methods |
|---|---|---|
| data | Planetary positions, houses, aspects | get_positions(), get_houses(), get_aspects() |
| charts | Natal, synastry, composite, transit charts | get_natal_chart(), get_synastry_chart() |
| horoscope | Personalized and sun sign horoscopes | get_personal_daily_horoscope(), get_sign_weekly_horoscope() |
| analysis | Interpretations and reports | get_natal_report(), get_synastry_report() |
| glossary | Reference data (cities, planets, signs) | get_cities(), get_planets(), get_zodiac_signs() |
| chinese | BaZi and Chinese zodiac | get_bazi(), get_zodiac_sign() |
| numerology | Numerology calculations | get_life_path_number(), get_expression_number() |
| tarot | Tarot card draws and readings | draw_cards(), get_reading() |
| eclipses | Solar and lunar eclipses | get_eclipses(), get_solar_eclipses() |
| lunar | Moon phases and void of course | get_moon_phase(), get_void_of_course() |
| astrocartography | Location mapping | get_lines(), get_relocated_chart() |
| traditional | Dignities and receptions | get_dignities(), get_receptions() |
| fixed_stars | Fixed star positions | get_positions(), get_conjunctions() |
| insights | Specialized insights | relationship.*, pet.*, wellness.* |
| svg | SVG chart generation | get_natal_chart_svg(), get_synastry_chart_svg() |
| enhanced | Advanced calculations | get_enhanced_natal_chart(), get_patterns() |
from astroapi import AstrologyClient, Subject, BirthData
from astroapi.types import SynastryChartRequest
client = AstrologyClient()
person1 = Subject(
name="Alice",
birth_data=BirthData(year=1985, month=3, day=15, hour=10, minute=30)
)
person2 = Subject(
name="Bob",
birth_data=BirthData(year=1987, month=7, day=22, hour=14, minute=45)
)
request = SynastryChartRequest(subject1=person1, subject2=person2)
synastry = client.charts.get_synastry_chart(request)
print(f"Inter-aspects: {len(synastry.inter_aspects)}")from astroapi.types import TransitChartRequest, DateTimeLocation
natal_subject = Subject(birth_data=BirthData(year=1990, month=1, day=1))
transit_time = DateTimeLocation(
year=2024, month=6, day=15, hour=12, minute=0,
latitude=40.7128, longitude=-74.0060
)
request = TransitChartRequest(
natal_subject=natal_subject,
transit_datetime=transit_time
)
transits = client.charts.get_transit_chart(request)from astroapi.types import BaZiRequest
request = BaZiRequest(
subject=subject,
language="en"
)
bazi = client.chinese.get_bazi(request)
print(f"Day Master: {bazi.day_master}")
print(f"Year Pillar: {bazi.year_pillar.heavenly_stem} {bazi.year_pillar.earthly_branch}")from astroapi.types import RelationshipInsightRequest
request = RelationshipInsightRequest(
subject1=person1,
subject2=person2,
language="en"
)
compatibility = client.insights.relationship.get_compatibility(request)
print(f"Compatibility Score: {compatibility.scores}")from astroapi.types import NatalChartRequest
request = NatalChartRequest(subject=subject)
svg_string = client.svg.get_natal_chart_svg(request)
# Save to file
with open("natal_chart.svg", "w") as f:
f.write(svg_string)from astroapi import AstrologyClient, AstrologyError
from astroapi.types import NatalChartRequest
client = AstrologyClient()
try:
chart = client.charts.get_natal_chart(request)
except AstrologyError as e:
print(f"Error: {e.message}")
print(f"Status Code: {e.status_code}")
print(f"Error Code: {e.code}")
if e.is_client_error():
print("Client error (4xx)")
elif e.is_server_error():
print("Server error (5xx)")The client includes automatic retry for transient failures:
from astroapi.types import AstrologyClientConfig, RetryConfig
config = AstrologyClientConfig(
api_key="your_api_key",
retry=RetryConfig(
attempts=3, # Retry up to 3 times
delay_ms=250, # Wait 250ms between retries
retry_status_codes=[408, 429, 500, 502, 503, 504]
)
)
client = AstrologyClient(config)All request parameters are validated before API calls:
from astroapi import AstrologyError
from astroapi.types import BirthData
try:
# Invalid year (out of range)
birth_data = BirthData(year=1800, month=1, day=1)
except AstrologyError as e:
print(e.message) # "Year must be between 1900 and 2100, got 1800"# Clone repository
git clone https://github.com/astro-api/astroapi-python.git
cd astroapi-python
# Install dev dependencies
pip install -e ".[dev]"
# Install pre-commit hooks
pre-commit installThe project has two test suites: unit tests (fast, mocked HTTP) and integration tests (real API calls or auto-mocked).
# Run all unit tests with coverage (100% branch coverage enforced)
pytest
# Run a specific test file
pytest tests/unit/test_client.py
# Run a single test
pytest tests/unit/test_client.py::TestAstrologyClient::test_client_creation_with_configIntegration tests verify every SDK endpoint against the real API. If the ASTROLOGY_API_KEY environment variable is set, tests call the live API. If not, the HTTP layer is automatically mocked so tests always pass regardless of API access.
# Mock mode (no API key required, runs in ~0.1s)
pytest tests/integration/ -m integration --no-cov
# Live mode (calls real API, runs in ~6 min)
ASTROLOGY_API_KEY=your_key pytest tests/integration/ -m integration --no-cov
# Run a single integration test file
pytest tests/integration/test_horoscope.py -m integration --no-covTests marked with
@pytest.mark.xfailare endpoints known to be unavailable or returning unexpected formats in the current API version. In mock mode these show asxpassed; in live mode they show asxfailed.
# Lint code
ruff check src/ tests/
# Format code
ruff format src/ tests/
# Type check
mypy src/astroapiThis project uses hatch-vcs — the package version is derived automatically from git tags. There is no hardcoded version in the source code.
To release a new version:
git tag v1.2.0
git push origin v1.2.0The release workflow will run CI checks, build the package with the correct version, publish it to PyPI, and create a GitHub Release.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests and linting (
pytest && ruff check && mypy) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Documentation: API Documentation
- PyPI: astroapi-python
- GitHub: astro-api/astroapi-python
- Issues: Bug Reports & Feature Requests
For questions and support:
- 📧 Email: info@procoders.tech
- 🐛 Issues: GitHub Issues
- 📖 API Docs: https://api.astrology-api.io/docs
Made with ❤️ by Procoders