# kerykeion.aspects.synastry_aspects

This is part of Kerykeion (C) 2025 Giacomo Battaglia

View Source

      1# -*- coding: utf-8 -*-
      2"""
      3    This is part of Kerykeion (C) 2025 Giacomo Battaglia
      4"""
      5
      6from kerykeion import AstrologicalSubject
      7from pathlib import Path
      8from typing import Union
      9from functools import cached_property
     10
     11from kerykeion.aspects.natal_aspects import NatalAspects
     12from kerykeion.settings.kerykeion_settings import get_settings
     13from kerykeion.aspects.aspects_utils import planet_id_decoder, get_aspect_from_two_points, get_active_points_list
     14from kerykeion.kr_types.kr_models import AstrologicalSubjectModel, AspectModel, ActiveAspect
     15from kerykeion.kr_types.settings_models import KerykeionSettingsModel
     16from kerykeion.settings.config_constants import DEFAULT_ACTIVE_POINTS, DEFAULT_ACTIVE_ASPECTS
     17from kerykeion.kr_types.kr_literals import AxialCusps, Planet
     18from typing import Union, List
     19
     20
     21class SynastryAspects(NatalAspects):
     22    """
     23    Generates an object with all the aspects between two persons.
     24    """
     25
     26    def __init__(
     27        self,
     28        kr_object_one: Union[AstrologicalSubject, AstrologicalSubjectModel],
     29        kr_object_two: Union[AstrologicalSubject, AstrologicalSubjectModel],
     30        new_settings_file: Union[Path, KerykeionSettingsModel, dict, None] = None,
     31        active_points: list[Union[AxialCusps, Planet]] = DEFAULT_ACTIVE_POINTS,
     32        active_aspects: List[ActiveAspect] = DEFAULT_ACTIVE_ASPECTS,
     33    ):
     34        # Subjects
     35        self.first_user = kr_object_one
     36        self.second_user = kr_object_two
     37
     38        # Settings
     39        self.new_settings_file = new_settings_file
     40        self.settings = get_settings(self.new_settings_file)
     41
     42        self.celestial_points = self.settings.celestial_points
     43        self.aspects_settings = self.settings.aspects
     44        self.axes_orbit_settings = self.settings.general_settings.axes_orbit
     45        self.active_points = active_points
     46        self.active_aspects = active_aspects
     47
     48        # Private variables of the aspects
     49        self._all_aspects: Union[list, None] = None
     50        self._relevant_aspects: Union[list, None] = None
     51
     52    @cached_property
     53    def all_aspects(self):
     54        """
     55        Return all the aspects of the points in the natal chart in a dictionary,
     56        first all the individual aspects of each planet, second the aspects
     57        whiteout repetitions.
     58        """
     59
     60        if self._all_aspects is not None:
     61            return self._all_aspects
     62
     63        # Celestial Points Lists
     64        first_active_points_list = get_active_points_list(self.first_user, self.settings, self.active_points)
     65        second_active_points_list = get_active_points_list(self.second_user, self.settings, self.active_points)
     66
     67        # ---> TODO: Clean this up
     68        filtered_settings = []
     69        for a in self.aspects_settings:
     70            for aspect in self.active_aspects:
     71                if a["name"] == aspect["name"]:
     72                    a["orb"] = aspect["orb"]  # Assign the aspect's orb
     73                    filtered_settings.append(a)
     74        self.aspects_settings = filtered_settings
     75        # <--- TODO: Clean this up
     76
     77        self.all_aspects_list = []
     78        for first in range(len(first_active_points_list)):
     79            # Generates the aspects list whitout repetitions
     80            for second in range(len(second_active_points_list)):
     81                aspect = get_aspect_from_two_points(
     82                    self.aspects_settings,
     83                    first_active_points_list[first]["abs_pos"],
     84                    second_active_points_list[second]["abs_pos"],
     85                )
     86
     87                verdict = aspect["verdict"]
     88                name = aspect["name"]
     89                orbit = aspect["orbit"]
     90                aspect_degrees = aspect["aspect_degrees"]
     91                diff = aspect["diff"]
     92
     93                if verdict == True:
     94                    aspect_model = AspectModel(
     95                        p1_name=first_active_points_list[first]["name"],
     96                        p1_owner=self.first_user.name,
     97                        p1_abs_pos=first_active_points_list[first]["abs_pos"],
     98                        p2_name=second_active_points_list[second]["name"],
     99                        p2_owner=self.second_user.name,
    100                        p2_abs_pos=second_active_points_list[second]["abs_pos"],
    101                        aspect=name,
    102                        orbit=orbit,
    103                        aspect_degrees=aspect_degrees,
    104                        diff=diff,
    105                        p1=planet_id_decoder(self.celestial_points, first_active_points_list[first]["name"]),
    106                        p2=planet_id_decoder(self.celestial_points, second_active_points_list[second]["name"]),
    107                    )
    108                    self.all_aspects_list.append(aspect_model)
    109
    110        return self.all_aspects_list
    111
    112
    113if __name__ == "__main__":
    114    from kerykeion.utilities import setup_logging
    115
    116    setup_logging(level="debug")
    117
    118    john = AstrologicalSubject("John", 1940, 10, 9, 10, 30, "Liverpool", "GB")
    119    yoko = AstrologicalSubject("Yoko", 1933, 2, 18, 10, 30, "Tokyo", "JP")
    120
    121    synastry_aspects = SynastryAspects(john, yoko)
    122
    123    # All aspects as a list of dictionaries
    124    print([aspect.dict() for aspect in synastry_aspects.all_aspects])

class SynastryAspects(kerykeion.aspects.natal_aspects.NatalAspects): View Source

     22class SynastryAspects(NatalAspects):
     23    """
     24    Generates an object with all the aspects between two persons.
     25    """
     26
     27    def __init__(
     28        self,
     29        kr_object_one: Union[AstrologicalSubject, AstrologicalSubjectModel],
     30        kr_object_two: Union[AstrologicalSubject, AstrologicalSubjectModel],
     31        new_settings_file: Union[Path, KerykeionSettingsModel, dict, None] = None,
     32        active_points: list[Union[AxialCusps, Planet]] = DEFAULT_ACTIVE_POINTS,
     33        active_aspects: List[ActiveAspect] = DEFAULT_ACTIVE_ASPECTS,
     34    ):
     35        # Subjects
     36        self.first_user = kr_object_one
     37        self.second_user = kr_object_two
     38
     39        # Settings
     40        self.new_settings_file = new_settings_file
     41        self.settings = get_settings(self.new_settings_file)
     42
     43        self.celestial_points = self.settings.celestial_points
     44        self.aspects_settings = self.settings.aspects
     45        self.axes_orbit_settings = self.settings.general_settings.axes_orbit
     46        self.active_points = active_points
     47        self.active_aspects = active_aspects
     48
     49        # Private variables of the aspects
     50        self._all_aspects: Union[list, None] = None
     51        self._relevant_aspects: Union[list, None] = None
     52
     53    @cached_property
     54    def all_aspects(self):
     55        """
     56        Return all the aspects of the points in the natal chart in a dictionary,
     57        first all the individual aspects of each planet, second the aspects
     58        whiteout repetitions.
     59        """
     60
     61        if self._all_aspects is not None:
     62            return self._all_aspects
     63
     64        # Celestial Points Lists
     65        first_active_points_list = get_active_points_list(self.first_user, self.settings, self.active_points)
     66        second_active_points_list = get_active_points_list(self.second_user, self.settings, self.active_points)
     67
     68        # ---> TODO: Clean this up
     69        filtered_settings = []
     70        for a in self.aspects_settings:
     71            for aspect in self.active_aspects:
     72                if a["name"] == aspect["name"]:
     73                    a["orb"] = aspect["orb"]  # Assign the aspect's orb
     74                    filtered_settings.append(a)
     75        self.aspects_settings = filtered_settings
     76        # <--- TODO: Clean this up
     77
     78        self.all_aspects_list = []
     79        for first in range(len(first_active_points_list)):
     80            # Generates the aspects list whitout repetitions
     81            for second in range(len(second_active_points_list)):
     82                aspect = get_aspect_from_two_points(
     83                    self.aspects_settings,
     84                    first_active_points_list[first]["abs_pos"],
     85                    second_active_points_list[second]["abs_pos"],
     86                )
     87
     88                verdict = aspect["verdict"]
     89                name = aspect["name"]
     90                orbit = aspect["orbit"]
     91                aspect_degrees = aspect["aspect_degrees"]
     92                diff = aspect["diff"]
     93
     94                if verdict == True:
     95                    aspect_model = AspectModel(
     96                        p1_name=first_active_points_list[first]["name"],
     97                        p1_owner=self.first_user.name,
     98                        p1_abs_pos=first_active_points_list[first]["abs_pos"],
     99                        p2_name=second_active_points_list[second]["name"],
    100                        p2_owner=self.second_user.name,
    101                        p2_abs_pos=second_active_points_list[second]["abs_pos"],
    102                        aspect=name,
    103                        orbit=orbit,
    104                        aspect_degrees=aspect_degrees,
    105                        diff=diff,
    106                        p1=planet_id_decoder(self.celestial_points, first_active_points_list[first]["name"]),
    107                        p2=planet_id_decoder(self.celestial_points, second_active_points_list[second]["name"]),
    108                    )
    109                    self.all_aspects_list.append(aspect_model)
    110
    111        return self.all_aspects_list

Generates an object with all the aspects between two persons.

SynastryAspects( kr_object_one: Union[kerykeion.astrological_subject.AstrologicalSubject, kerykeion.kr_types.kr_models.AstrologicalSubjectModel], kr_object_two: Union[kerykeion.astrological_subject.AstrologicalSubject, kerykeion.kr_types.kr_models.AstrologicalSubjectModel], new_settings_file: Union[pathlib._local.Path, kerykeion.kr_types.settings_models.KerykeionSettingsModel, dict, NoneType] = None, active_points: list[typing.Union[typing.Literal['Ascendant', 'Medium_Coeli', 'Descendant', 'Imum_Coeli'], typing.Literal['Sun', 'Moon', 'Mercury', 'Venus', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto', 'Mean_Node', 'True_Node', 'Mean_South_Node', 'True_South_Node', 'Chiron', 'Mean_Lilith']]] = ['Sun', 'Moon', 'Mercury', 'Venus', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto', 'Mean_Node', 'Chiron', 'Ascendant', 'Medium_Coeli', 'Mean_Lilith', 'Mean_South_Node'], active_aspects: List[kerykeion.kr_types.kr_models.ActiveAspect] = [{'name': 'conjunction', 'orb': 10}, {'name': 'opposition', 'orb': 10}, {'name': 'trine', 'orb': 8}, {'name': 'sextile', 'orb': 6}, {'name': 'square', 'orb': 5}, {'name': 'quintile', 'orb': 1}]) View Source

    27    def __init__(
    28        self,
    29        kr_object_one: Union[AstrologicalSubject, AstrologicalSubjectModel],
    30        kr_object_two: Union[AstrologicalSubject, AstrologicalSubjectModel],
    31        new_settings_file: Union[Path, KerykeionSettingsModel, dict, None] = None,
    32        active_points: list[Union[AxialCusps, Planet]] = DEFAULT_ACTIVE_POINTS,
    33        active_aspects: List[ActiveAspect] = DEFAULT_ACTIVE_ASPECTS,
    34    ):
    35        # Subjects
    36        self.first_user = kr_object_one
    37        self.second_user = kr_object_two
    38
    39        # Settings
    40        self.new_settings_file = new_settings_file
    41        self.settings = get_settings(self.new_settings_file)
    42
    43        self.celestial_points = self.settings.celestial_points
    44        self.aspects_settings = self.settings.aspects
    45        self.axes_orbit_settings = self.settings.general_settings.axes_orbit
    46        self.active_points = active_points
    47        self.active_aspects = active_aspects
    48
    49        # Private variables of the aspects
    50        self._all_aspects: Union[list, None] = None
    51        self._relevant_aspects: Union[list, None] = None

first_user
second_user
new_settings_file = None
settings
celestial_points
aspects_settings
axes_orbit_settings
active_points
active_aspects
all_aspects View Source

     53    @cached_property
     54    def all_aspects(self):
     55        """
     56        Return all the aspects of the points in the natal chart in a dictionary,
     57        first all the individual aspects of each planet, second the aspects
     58        whiteout repetitions.
     59        """
     60
     61        if self._all_aspects is not None:
     62            return self._all_aspects
     63
     64        # Celestial Points Lists
     65        first_active_points_list = get_active_points_list(self.first_user, self.settings, self.active_points)
     66        second_active_points_list = get_active_points_list(self.second_user, self.settings, self.active_points)
     67
     68        # ---> TODO: Clean this up
     69        filtered_settings = []
     70        for a in self.aspects_settings:
     71            for aspect in self.active_aspects:
     72                if a["name"] == aspect["name"]:
     73                    a["orb"] = aspect["orb"]  # Assign the aspect's orb
     74                    filtered_settings.append(a)
     75        self.aspects_settings = filtered_settings
     76        # <--- TODO: Clean this up
     77
     78        self.all_aspects_list = []
     79        for first in range(len(first_active_points_list)):
     80            # Generates the aspects list whitout repetitions
     81            for second in range(len(second_active_points_list)):
     82                aspect = get_aspect_from_two_points(
     83                    self.aspects_settings,
     84                    first_active_points_list[first]["abs_pos"],
     85                    second_active_points_list[second]["abs_pos"],
     86                )
     87
     88                verdict = aspect["verdict"]
     89                name = aspect["name"]
     90                orbit = aspect["orbit"]
     91                aspect_degrees = aspect["aspect_degrees"]
     92                diff = aspect["diff"]
     93
     94                if verdict == True:
     95                    aspect_model = AspectModel(
     96                        p1_name=first_active_points_list[first]["name"],
     97                        p1_owner=self.first_user.name,
     98                        p1_abs_pos=first_active_points_list[first]["abs_pos"],
     99                        p2_name=second_active_points_list[second]["name"],
    100                        p2_owner=self.second_user.name,
    101                        p2_abs_pos=second_active_points_list[second]["abs_pos"],
    102                        aspect=name,
    103                        orbit=orbit,
    104                        aspect_degrees=aspect_degrees,
    105                        diff=diff,
    106                        p1=planet_id_decoder(self.celestial_points, first_active_points_list[first]["name"]),
    107                        p2=planet_id_decoder(self.celestial_points, second_active_points_list[second]["name"]),
    108                    )
    109                    self.all_aspects_list.append(aspect_model)
    110
    111        return self.all_aspects_list

Return all the aspects of the points in the natal chart in a dictionary, first all the individual aspects of each planet, second the aspects whiteout repetitions.

##### Inherited Members

kerykeion.aspects.natal_aspects.NatalAspects
  user
  relevant_aspects