kerykeion.aspects.synastry_aspects

This is part of Kerykeion (C) 2025 Giacomo Battaglia

  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_abs_pos=first_active_points_list[first]["abs_pos"],
 97                        p2_name=second_active_points_list[second]["name"],
 98                        p2_abs_pos=second_active_points_list[second]["abs_pos"],
 99                        aspect=name,
100                        orbit=orbit,
101                        aspect_degrees=aspect_degrees,
102                        diff=diff,
103                        p1=planet_id_decoder(self.celestial_points, first_active_points_list[first]["name"]),
104                        p2=planet_id_decoder(self.celestial_points, second_active_points_list[second]["name"]),
105                    )
106                    self.all_aspects_list.append(aspect_model)
107
108        return self.all_aspects_list
109
110
111if __name__ == "__main__":
112    from kerykeion.utilities import setup_logging
113
114    setup_logging(level="debug")
115
116    john = AstrologicalSubject("John", 1940, 10, 9, 10, 30, "Liverpool", "GB")
117    yoko = AstrologicalSubject("Yoko", 1933, 2, 18, 10, 30, "Tokyo", "JP")
118
119    synastry_aspects = SynastryAspects(john, yoko)
120
121    # All aspects as a list of dictionaries
122    print([aspect.dict() for aspect in synastry_aspects.all_aspects])
class SynastryAspects(kerykeion.aspects.natal_aspects.NatalAspects):
 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_abs_pos=first_active_points_list[first]["abs_pos"],
 98                        p2_name=second_active_points_list[second]["name"],
 99                        p2_abs_pos=second_active_points_list[second]["abs_pos"],
100                        aspect=name,
101                        orbit=orbit,
102                        aspect_degrees=aspect_degrees,
103                        diff=diff,
104                        p1=planet_id_decoder(self.celestial_points, first_active_points_list[first]["name"]),
105                        p2=planet_id_decoder(self.celestial_points, second_active_points_list[second]["name"]),
106                    )
107                    self.all_aspects_list.append(aspect_model)
108
109        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.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}])
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
 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_abs_pos=first_active_points_list[first]["abs_pos"],
 98                        p2_name=second_active_points_list[second]["name"],
 99                        p2_abs_pos=second_active_points_list[second]["abs_pos"],
100                        aspect=name,
101                        orbit=orbit,
102                        aspect_degrees=aspect_degrees,
103                        diff=diff,
104                        p1=planet_id_decoder(self.celestial_points, first_active_points_list[first]["name"]),
105                        p2=planet_id_decoder(self.celestial_points, second_active_points_list[second]["name"]),
106                    )
107                    self.all_aspects_list.append(aspect_model)
108
109        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.