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])
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
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.