Try Astrologer API

Subscribe to support and grow the project.

Migration Guide: v4/v5 to v6 #

This guide provides comprehensive instructions for migrating your code from Kerykeion v4 or v5 to v6. The v5 release introduced a factory-based architecture; v6 removes the v4 backward compatibility layer entirely and adds advanced calculation modules.

The current v6 release is 6.0.3, a stable maintenance release. Use Python 3.12 or newer:

pip install --upgrade "kerykeion"
# Optional CLI, released with and pinned to the same library version:
pip install --upgrade "kerykeion[cli]"

v6 uses libephemeris==3.2.1 by default. Its bundled base data covers 1850–2150 (upper bound exclusive); install a wider data tier before working outside that interval. See backend configuration for data tiers and the optional Swiss Ephemeris backend. Timezone handling uses zoneinfo with tzdata; ambiguous and nonexistent local times require an explicit choice. The is_dst migration notes explain its offset-based contract.

Quick Reference #

v4 (Removed in v6) v6 (Current)
AstrologicalSubject() AstrologicalSubjectFactory.from_birth_data()
KerykeionChartSVG() ChartDataFactory + ChartDrawer
NatalAspects() AspectsFactory.single_chart_aspects()
SynastryAspects() AspectsFactory.dual_chart_aspects()
relationship_score() RelationshipScoreFactory
kerykeion.kr_types kerykeion.schemas
mean_node, true_node mean_north_lunar_node, true_north_lunar_node

Note: kerykeion.kr_types was a deprecated shim throughout v5 and is removed in v6. Import from kerykeion.schemas instead.

Breaking Changes #

1. Subject Creation #

v4 (Deprecated):

# doc-snippet: no-run — legacy v4 example (removed in v6)
from kerykeion import AstrologicalSubject

subject = AstrologicalSubject(
    "John", 1990, 1, 1, 12, 0,
    city="London", nation="GB"
)

v6 (Current):

from kerykeion import AstrologicalSubjectFactory

subject = AstrologicalSubjectFactory.from_birth_data(
    "John", 1990, 1, 1, 12, 0,
    lng=-0.1276, lat=51.5074, tz_str="Europe/London",
    online=False
)

Key differences:

  • Use factory method from_birth_data() instead of direct instantiation
  • nat parameter renamed to nation
  • Recommended: Use offline mode with explicit coordinates

2. Chart Generation (Two-Step Process) #

v4 (Deprecated):

# doc-snippet: no-run — legacy v4 example (removed in v6)
from kerykeion import AstrologicalSubject, KerykeionChartSVG

subject = AstrologicalSubject("John", 1990, 1, 1, 12, 0, "London", "GB")
chart = KerykeionChartSVG(subject)
chart.makeSVG()

v6 (Current):

from pathlib import Path
from kerykeion import AstrologicalSubjectFactory, ChartDataFactory
from kerykeion.charts.drawer import ChartDrawer

# Step 1: Create subject
subject = AstrologicalSubjectFactory.from_birth_data(
    "John", 1990, 1, 1, 12, 0,
    lng=-0.1276, lat=51.5074, tz_str="Europe/London",
    online=False
)

# Step 2: Generate chart data
chart_data = ChartDataFactory.create_natal_chart_data(subject)

# Step 3: Render visualization
drawer = ChartDrawer(chart_data=chart_data)

output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
drawer.save_svg(output_path=output_dir, filename="john-natal")

The new architecture separates:

  • Data calculation (ChartDataFactory) - Computes all astrological data
  • Visualization (ChartDrawer) - Renders the SVG chart

3. Aspects Calculation #

v4 (Deprecated):

# doc-snippet: no-run — legacy v4 example (removed in v6)
from kerykeion import NatalAspects, SynastryAspects

natal_aspects = NatalAspects(subject)
synastry_aspects = SynastryAspects(subject1, subject2)

# Accessing aspects
for aspect in natal_aspects.relevant_aspects:
    print(aspect)

v6 (Current):

from kerykeion import AspectsFactory

# Single chart (natal, composite, return)
natal_result = AspectsFactory.single_chart_aspects(subject)

# Dual chart (synastry, transit) — needs a second subject
subject2 = AstrologicalSubjectFactory.from_birth_data(
    "Jane", 1992, 5, 15, 10, 30,
    lng=12.4964, lat=41.9028, tz_str="Europe/Rome",
    online=False
)
synastry_result = AspectsFactory.dual_chart_aspects(subject, subject2)

# Accessing aspects (unified list)
for aspect in natal_result.aspects:
    print(aspect)

Key changes:

  • relevant_aspects and all_aspects unified into single aspects list
  • Factory methods instead of class instantiation

4. Lunar Node Naming #

All lunar node properties were renamed for clarity:

v4 Property v6 Property
subject.mean_node subject.mean_north_lunar_node
subject.true_node subject.true_north_lunar_node
subject.mean_south_node subject.mean_south_lunar_node
subject.true_south_node subject.true_south_lunar_node

In active_points lists:

v4 String v6 String
"Mean_Node" "Mean_North_Lunar_Node"
"True_Node" "True_North_Lunar_Node"

5. Import Path Changes #

v4 Import v6 Import
from kerykeion.kr_types import * from kerykeion.schemas import *
from kerykeion.kr_types.kr_literals import Planet from kerykeion.schemas.literals import AstrologicalPoint
from kerykeion.kr_types import KerykeionException from kerykeion.schemas import KerykeionException

v5 → v6 module paths #

v6 reorganised the package so that every domain lives in its own directory. If you import only from the top level — from kerykeion import X — nothing changes. These paths matter only if you imported a module directly.

v5 module v6 module
kerykeion.astrological_subject_factory kerykeion.astrological_subject.factory
kerykeion.chart_data_factory kerykeion.chart_data.factory
kerykeion.composite_subject_factory kerykeion.composite_subject.factory
kerykeion.planetary_return_factory kerykeion.planetary_returns.factory
kerykeion.transits_time_range_factory kerykeion.transits.factory
kerykeion.relationship_score_factory kerykeion.relationship_score.factory
kerykeion.relocated_chart_factory kerykeion.relocated_chart.factory
kerykeion.ephemeris_data_factory kerykeion.ephemeris_data.factory
kerykeion.context_serializer kerykeion.context.serializer
kerykeion.fetch_geonames kerykeion.geonames.fetcher
kerykeion.charts.chart_drawer kerykeion.charts.drawer
kerykeion.charts.charts_utils kerykeion.charts.utils
kerykeion.aspects.aspects_factory kerykeion.aspects.factory
kerykeion.aspects.aspects_utils kerykeion.aspects.utils
kerykeion.house_comparison.house_comparison_factory kerykeion.house_comparison.factory
kerykeion.house_comparison.house_comparison_utils kerykeion.house_comparison.utils
kerykeion.schemas.kr_models kerykeion.schemas.models
kerykeion.schemas.kr_literals kerykeion.schemas.literals
kerykeion.schemas.kerykeion_exception kerykeion.schemas.exceptions
kerykeion.settings.kerykeion_settings kerykeion.settings.loader
kerykeion.kr_types (and submodules) kerykeion.schemas

Unchanged, because they became packages under the same name: kerykeion.report, kerykeion.utilities, kerykeion.ephemeris_backend, kerykeion.motion, kerykeion.swisseph_setup.

The same domain packages also renamed their internal factory module (eclipses.eclipse_factoryeclipses.factory, and the same for lunations, midpoints, occultations, heliacal, planetary_nodes, planetary_phenomena, primary_directions, retrograde_stations, sign_ingresses, astro_cartography, fixed_stars, dignities, secondary_progressions). Every one of these classes is also exported from kerykeion directly, which is the import worth switching to.

6. Type Aliases #

The Planet and AxialCusps types were unified into AstrologicalPoint:

# v4 (removed in v6)
# from kerykeion.kr_types.kr_literals import Planet, AxialCusps

# v6 (correct)
from kerykeion.schemas.literals import AstrologicalPoint

The v5 model aliases NatalAspectsModel and SynastryAspectsModel were also removed — use SingleChartAspectsModel and DualChartAspectsModel instead.

7. Removed Parameters #

Parameter Status Replacement
disable_chiron Removed Use active_points to exclude
disable_chiron_and_lilith Removed Use active_points to exclude
new_settings_file Removed Use language_pack parameter

What Changes in the Results #

Everything above is about code that stops working: you get an ImportError, you fix the call, you move on. This section is about the opposite — code that keeps working and quietly returns different numbers.

It applies even if you were already using the v5 factory API correctly. Nothing raises, nothing warns; the output is simply not the same as before.

What v5 v6 What you see
Default active points 18 14 Fewer points in charts and aspects
Default aspect orbs conj/opp 10°, trine 8°, sextile 6°, square 5°, quintile 1° conj/opp/trine/square 6°, sextile 5° Markedly fewer aspects; quintiles disappear entirely
Orbs on non-natal charts same defaults as natal flat 3° (PREDICTIVE_ACTIVE_ASPECTS) Transits, returns and progressions report far fewer aspects
Sun/Moon orb bonus none +1.5°, natal-family charts only Slightly wider orbs for luminaries
Chart style "classic" "modern" A different drawing, and a different filename
Nakshatras on a non-sidereal chart tropical longitude used as-is rotated by nakshatra_ayanamsa (default "LAHIRI") Different nakshatra, pada and lord — about two nakshatras’ worth
Lunar phase name 28 fixed bins windows centred on the syzygies moon_phase_name and moon_emoji change near a boundary; moon_phase (1-28) does not
Moon’s apsides perihelion / aphelion only periapsis / apoapsis / apsis_kind Old fields still populated; new ones are correct for the Moon

These are deliberate v6 choices, not oversights. What follows is how to opt back into the old behaviour where you need continuity.

Active points: 18 → 14 #

Four points left the default set: Descendant, Imum_Coeli, True_South_Lunar_Node and Mean_Lilith. They still exist — they are simply no longer computed unless you ask for them.

from kerykeion import AstrologicalSubjectFactory
from kerykeion.settings import V5_DEFAULT_ACTIVE_POINTS

# v6 defaults: 14 points
subject = AstrologicalSubjectFactory.from_birth_data(
    "John", 1990, 1, 1, 12, 0,
    lng=-0.1276, lat=51.5074, tz_str="Europe/London", online=False,
)

# The v5 set, restored explicitly
subject_v5 = AstrologicalSubjectFactory.from_birth_data(
    "John", 1990, 1, 1, 12, 0,
    lng=-0.1276, lat=51.5074, tz_str="Europe/London", online=False,
    active_points=V5_DEFAULT_ACTIVE_POINTS,
)

print(len(subject.active_points), len(subject_v5.active_points))

V5_DEFAULT_ACTIVE_POINTS is a frozen historical record: it will not track future changes to the default set. If you want the current defaults plus one point, build the list from DEFAULT_ACTIVE_POINTS instead.

Aspect orbs #

This is the largest silent change, and it has three separate parts. Expect fewer aspects after upgrading, not more.

The default orbs shrank. DEFAULT_ACTIVE_ASPECTS was rewritten:

Aspect v5 orb v6 orb
conjunction 10°
opposition 10°
trine
sextile
square
quintile removed from the defaults

Non-natal charts moved to a flat 3°. In v5 every chart type used the same defaults. In v6 only the natal family (Natal, Synastry, Composite) uses DEFAULT_ACTIVE_ASPECTS; transits, returns and progressions use PREDICTIVE_ACTIVE_ASPECTS, which is 3° for all five aspects. Both presets live in kerykeion.settings.config_constants.

The difference is small on a natal chart and large everywhere else. On one sample chart: 38 natal aspects under v6 against 40 with the v5 orbs — but 19 transit aspects against 51. If your code reads transits, returns or progressions, this is the change to look at first.

Luminaries gained a 1.5° bonus — natal family only. DEFAULT_NATAL_POINT_ORB_ADJUSTMENTS (also in kerykeion.settings.config_constants) widens aspects involving the Sun or the Moon. It applies only where chart_type is in the natal family; every other create_*_chart_data already uses no adjustment, so point_orb_adjustments={} is a no-op there.

To restore v5 orbs, pass the aspect list explicitly — this is the part V5_DEFAULT_ACTIVE_POINTS does not cover:

from kerykeion import ChartDataFactory

V5_DEFAULT_ACTIVE_ASPECTS = [
    {"name": "conjunction", "orb": 10},
    {"name": "opposition", "orb": 10},
    {"name": "trine", "orb": 8},
    {"name": "sextile", "orb": 6},
    {"name": "square", "orb": 5},
    {"name": "quintile", "orb": 1},
]

# v6 defaults
chart_data = ChartDataFactory.create_natal_chart_data(subject)

# v5-equivalent orbs: the old aspect list, and no luminary bonus
chart_data_v5 = ChartDataFactory.create_natal_chart_data(
    subject,
    active_aspects=V5_DEFAULT_ACTIVE_ASPECTS,
    point_orb_adjustments={},
)

print(len(chart_data.aspects), len(chart_data_v5.aspects))

For a transit chart, pass the same active_aspects to create_transit_chart_data — there point_orb_adjustments is already empty, so only the aspect list matters.

AspectsFactory.single_chart_aspects applies no orb adjustment by default, so it and ChartDataFactory can disagree on the same subject unless you pass the same arguments to both.

Nakshatras on a non-sidereal chart #

Nakshatras divide the sidereal zodiac. In v5 a tropical chart’s longitudes were handed to the 27-fold division as they were, so every nakshatra, nakshatra_pada and nakshatra_lord came out about two nakshatras off. In v6 a non-sidereal chart’s longitudes are rotated by nakshatra_ayanamsa (default "LAHIRI") for the division only: the chart stays tropical, and its nakshatras agree exactly with the sidereal chart cast in the same mode.

If you stored v5 values and need to reproduce them, pass nakshatra_ayanamsa=None. That is the legacy path; it logs one warning per subject.

from kerykeion import AstrologicalSubjectFactory

corrected = AstrologicalSubjectFactory.from_birth_data(
    "John", 1990, 1, 1, 12, 0,
    lng=-0.1276, lat=51.5074, tz_str="Europe/London", online=False,
    calculate_nakshatra=True,
)
legacy = AstrologicalSubjectFactory.from_birth_data(
    "John", 1990, 1, 1, 12, 0,
    lng=-0.1276, lat=51.5074, tz_str="Europe/London", online=False,
    calculate_nakshatra=True, nakshatra_ayanamsa=None,   # the v5 numbers
)
print(corrected.moon.nakshatra, "vs", legacy.moon.nakshatra)

A sidereal chart is unaffected: nakshatra_ayanamsa is ignored there, and subject.nakshatra_ayanamsa reads None.

Lunar phase names moved onto the event #

moon_phase_name and moon_emoji used to come from 28 equal bins, which put the label a little ahead of or behind the event it names. They now come from windows centred on the syzygies: New and Full span ±6.4286° of the exact aspect, the two quarters ±19.2857°, and the four crescent/gibbous names fill the rest. A moment near a boundary can therefore report a different name than it did in v5 — a closer one.

The moon_phase index (1-28) is unchanged, and so are get_moon_phase_name_from_phase_int / get_moon_emoji_from_phase_int, which only ever see that index: they remain the 28-bin approximation and can disagree with the model near a boundary. LunarPhaseModel also gained major_phase (the nearest of the four syzygy/quadrature events) and stage ("waxing" / "waning").

perihelion / aphelion are deprecated #

PlanetaryNodeModel now exposes the apsides as periapsis and apoapsis, with apsis_kind saying which body they are measured against. The old perihelion / aphelion name the Sun — right for the eight planets, wrong for the Moon, which goes round the Earth. They are still populated with the same objects, so nothing that reads them breaks; new code should read the generic pair.

Chart style #

ChartDrawer now defaults to style="modern". The v5 drawing is still available, and the saved filename reflects the style ("... - Classic.svg" vs "... - Modern.svg"), so scripts that look for a fixed filename need updating either way.

from kerykeion import ChartDrawer

drawer = ChartDrawer(chart_data, style="classic")  # the v5 look
svg = drawer.generate_svg_string()

Note that external_view only takes effect in the classic style.

Backward Compatibility Layer (Removed in v6) #

v5 included a compatibility layer in kerykeion.backword that allowed gradual migration. This layer has been removed in v6.0.

# v5 ONLY (no longer works in v6):
# from kerykeion import AstrologicalSubject, KerykeionChartSVG, NatalAspects
# These imports now raise ImportError in v6.

Warning: The backward compatibility layer has been removed in v6.0. The legacy imports (AstrologicalSubject, KerykeionChartSVG, NatalAspects, SynastryAspects) will raise ImportError. Use the factory-based API shown above.

Step-by-Step Migration #

Step 1: Update Imports #

# Old (removed in v6)
# from kerykeion import AstrologicalSubject, KerykeionChartSVG

# New
from pathlib import Path

from kerykeion import (
    AspectsFactory,
    AstrologicalSubjectFactory,
    ChartDataFactory,
    ChartDrawer,
)

Step 2: Update Subject Creation #

# Old (removed in v6)
# subject = AstrologicalSubject("John", 1990, 1, 1, 12, 0, "London", "GB")

# New
subject = AstrologicalSubjectFactory.from_birth_data(
    "John", 1990, 1, 1, 12, 0,
    lng=-0.1276, lat=51.5074, tz_str="Europe/London",
    online=False
)

Step 3: Update Chart Generation #

# Old (removed in v6)
# chart = KerykeionChartSVG(subject)
# chart.makeSVG()

# New
chart_data = ChartDataFactory.create_natal_chart_data(subject)
drawer = ChartDrawer(chart_data=chart_data)
output_dir = Path("charts_output")
output_dir.mkdir(exist_ok=True)
drawer.save_svg(output_path=output_dir, filename="chart")

Step 4: Update Lunar Node References #

# Old (removed in v6)
# mean_node = subject.mean_node

# New
mean_node = subject.mean_north_lunar_node

Step 5: Update Aspect Access #

# Old (removed in v6)
# aspects = NatalAspects(subject)
# for a in aspects.relevant_aspects:
#     print(a)

# New
result = AspectsFactory.single_chart_aspects(subject)
for a in result.aspects:
    print(a)

Automated Migration Script #

Use this bash script to update common patterns:

#!/bin/bash
# Update lunar node references
find . -name "*.py" -type f -exec sed -i.bak \
    -e 's/\.mean_node/.mean_north_lunar_node/g' \
    -e 's/\.true_node/.true_north_lunar_node/g' \
    -e 's/\.mean_south_node/.mean_south_lunar_node/g' \
    -e 's/\.true_south_node/.true_south_lunar_node/g' \
    -e 's/"Mean_Node"/"Mean_North_Lunar_Node"/g' \
    -e 's/"True_Node"/"True_North_Lunar_Node"/g' \
    {} \;

echo "Migration complete. Review changes before committing."

Important: Always review automated changes and test thoroughly.

Migration Checklist #

  • [ ] Update imports to use new module paths
  • [ ] Use Python 3.12+ and install the stable v6 release
  • [ ] Provision the ephemeris tier needed for your date range
  • [ ] Review active points, aspect orbs, chart style and timezone behavior
  • [ ] Replace AstrologicalSubject with AstrologicalSubjectFactory.from_birth_data()
  • [ ] Replace KerykeionChartSVG with ChartDataFactory + ChartDrawer
  • [ ] Replace NatalAspects with AspectsFactory.single_chart_aspects()
  • [ ] Replace SynastryAspects with AspectsFactory.dual_chart_aspects()
  • [ ] Update lunar node property names
  • [ ] Update kr_types imports to schemas
  • [ ] Remove deprecated parameters (disable_chiron, etc.)
  • [ ] Update aspect access from relevant_aspects to aspects
  • [ ] Test all chart generation and data access

Timeline #

Version Status
v5.x Legacy - Backward compatibility was available
v6.0.0 Stable - The v4 compatibility layer and deprecated v5 aliases have been removed

Getting Help #

If you encounter issues during migration:

  1. Check the Troubleshooting & FAQ page
  2. Review the API documentation
  3. Open an issue on GitHub