kerykeion.relationship_score.relationship_score
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 kerykeion.aspects.synastry_aspects import SynastryAspects 8import logging 9from pathlib import Path 10from typing import Union 11from kerykeion.kr_types.kr_models import AstrologicalSubjectModel 12import warnings 13 14 15class RelationshipScore: 16 """ 17 Calculates the relevance of the relationship between two subjects using the Ciro Discepolo method. 18 19 Results: 20 - 0 to 5: Minimal relationship 21 - 5 to 10: Medium relationship 22 - 10 to 15: Important relationship 23 - 15 to 20: Very important relationship 24 - 20 and 35: Exceptional relationship 25 - 35 and above: Rare Exceptional relationship 26 27 Documentation: http://www.cirodiscepolo.it/Articoli/Discepoloele.htm 28 29 Args: 30 first_subject (AstrologicalSubject): First subject instance 31 second_subject (AstrologicalSubject): Second subject instance 32 """ 33 34 def __init__( 35 self, 36 first_subject: Union[AstrologicalSubject, AstrologicalSubjectModel], 37 second_subject: Union[AstrologicalSubject, AstrologicalSubjectModel], 38 new_settings_file: Union[Path, None] = None, 39 ): 40 warnings.warn( 41 "The RelationshipScore class is deprecated and will be removed in a future version. Use RelationshipScoreFactory instead.", 42 DeprecationWarning, 43 stacklevel=2 44 ) 45 self.first_subject = first_subject 46 self.second_subject = second_subject 47 self.score = 0 48 self.is_destiny_sign = False 49 self.relevant_aspects: list = [] 50 self.relevant_default_aspects: list = [] 51 self.__all_synastry_aspects = SynastryAspects(first_subject, second_subject, new_settings_file=new_settings_file).all_aspects 52 53 # Calculate all aspects at initialization 54 self._calculate_all() 55 56 def __str__(self) -> str: 57 return f"CoupleScoreInstance: {self.first_subject.name} and {self.second_subject.name}, score: {self.score}" 58 59 def __dict__(self) -> dict: # type: ignore 60 return { 61 "first_subject_name": self.first_subject.name, 62 "second_subject_name": self.second_subject.name, 63 "score": self.score, 64 "relevant_aspects": self.relevant_aspects, 65 "relevant_default_aspects": self.relevant_default_aspects, 66 "is_destiny_sign": self.is_destiny_sign, 67 } 68 69 def _log_aspect(self, aspect: dict, points: int) -> None: 70 logging.debug(f"{points} Points: {aspect['p1_name']} {aspect['aspect']} {aspect['p2_name']}, rounded orbit: {int(aspect['orbit'])}") 71 72 def _evaluate_destiny_sign(self) -> int: 73 """ 74 Adds 5 points if the subjects share the same sun sign quality. 75 """ 76 if self.first_subject.sun["quality"] == self.second_subject.sun["quality"]: 77 logging.debug(f'5 points: Destiny sign, {self.first_subject.sun["sign"]} and {self.second_subject.sun["sign"]}') 78 self.is_destiny_sign = True 79 return 5 80 return 0 81 82 def _check_if_sun_sun_aspect(self, aspect: dict) -> int: 83 """ 84 Adds points for Sun-Sun aspects: 85 - 8 points for conjunction/opposition/square 86 - 11 points if the aspect's orbit is <= 2 degrees 87 """ 88 aspect_types = ["conjunction", "opposition", "square"] 89 90 if aspect["p1_name"] == "Sun" and aspect["p2_name"] == "Sun" and aspect["aspect"] in aspect_types: 91 self.relevant_default_aspects.append(aspect) 92 score = 11 if aspect["orbit"] <= 2 else 8 93 94 self._log_aspect(aspect, score) 95 self.relevant_aspects.append(self._create_aspects_dictionary(aspect, score)) 96 97 return score 98 return 0 99 100 def _check_if_sun_moon_conjunction(self, aspect: dict) -> int: 101 """ 102 Adds points for Sun-Moon conjunction: 103 - 8 points for conjunction 104 - 11 points if the aspect's orbit is <= 2 degrees 105 """ 106 planets = {"Moon", "Sun"} 107 108 if {aspect["p1_name"], aspect["p2_name"]} == planets and aspect["aspect"] == "conjunction": 109 self.relevant_default_aspects.append(aspect) 110 score = 11 if aspect["orbit"] <= 2 else 8 111 112 self._log_aspect(aspect, score) 113 self.relevant_aspects.append(self._create_aspects_dictionary(aspect, score)) 114 115 return score 116 return 0 117 118 def _check_if_sun_moon_asc_aspect(self, aspect: dict) -> int: 119 """ 120 Adds 4 points for aspects involving Sun, Moon, and Ascendant. 121 """ 122 planets = ["Sun", "Moon", "First_House"] 123 124 if self._check_if_sun_sun_aspect(aspect) or self._check_if_sun_moon_conjunction(aspect): 125 return 0 126 127 if aspect["p1_name"] in planets and aspect["p2_name"] in planets: 128 self.relevant_default_aspects.append(aspect) 129 score = 4 130 131 self._log_aspect(aspect, score) 132 self.relevant_aspects.append(self._create_aspects_dictionary(aspect, score)) 133 134 return score 135 return 0 136 137 def _check_if_venus_mars_aspect(self, aspect: dict) -> int: 138 """ 139 Adds 4 points for Venus-Mars aspects. 140 """ 141 planets = {"Venus", "Mars"} 142 143 if {aspect["p1_name"], aspect["p2_name"]} == planets: 144 score = 4 145 self.relevant_default_aspects.append(aspect) 146 147 self._log_aspect(aspect, score) 148 self.relevant_aspects.append(self._create_aspects_dictionary(aspect, score)) 149 150 return score 151 return 0 152 153 def _create_aspects_dictionary(self, aspect: dict, score: int) -> dict: 154 """ 155 Creates a dictionary representation of an aspect with its score. 156 """ 157 return { 158 "points": score, 159 "p1_name": aspect["p1_name"], 160 "p2_name": aspect["p2_name"], 161 "aspect": aspect["aspect"], 162 "orbit": aspect["orbit"], 163 } 164 165 def _calculate_all(self) -> None: 166 """ 167 Calculates the total score based on all relevant aspects. 168 """ 169 self.score += self._evaluate_destiny_sign() 170 171 for aspect in self.__all_synastry_aspects: 172 self.score += self._check_if_sun_sun_aspect(aspect) 173 self.score += self._check_if_sun_moon_conjunction(aspect) 174 self.score += self._check_if_sun_moon_asc_aspect(aspect) 175 self.score += self._check_if_venus_mars_aspect(aspect)
class
RelationshipScore:
16class RelationshipScore: 17 """ 18 Calculates the relevance of the relationship between two subjects using the Ciro Discepolo method. 19 20 Results: 21 - 0 to 5: Minimal relationship 22 - 5 to 10: Medium relationship 23 - 10 to 15: Important relationship 24 - 15 to 20: Very important relationship 25 - 20 and 35: Exceptional relationship 26 - 35 and above: Rare Exceptional relationship 27 28 Documentation: http://www.cirodiscepolo.it/Articoli/Discepoloele.htm 29 30 Args: 31 first_subject (AstrologicalSubject): First subject instance 32 second_subject (AstrologicalSubject): Second subject instance 33 """ 34 35 def __init__( 36 self, 37 first_subject: Union[AstrologicalSubject, AstrologicalSubjectModel], 38 second_subject: Union[AstrologicalSubject, AstrologicalSubjectModel], 39 new_settings_file: Union[Path, None] = None, 40 ): 41 warnings.warn( 42 "The RelationshipScore class is deprecated and will be removed in a future version. Use RelationshipScoreFactory instead.", 43 DeprecationWarning, 44 stacklevel=2 45 ) 46 self.first_subject = first_subject 47 self.second_subject = second_subject 48 self.score = 0 49 self.is_destiny_sign = False 50 self.relevant_aspects: list = [] 51 self.relevant_default_aspects: list = [] 52 self.__all_synastry_aspects = SynastryAspects(first_subject, second_subject, new_settings_file=new_settings_file).all_aspects 53 54 # Calculate all aspects at initialization 55 self._calculate_all() 56 57 def __str__(self) -> str: 58 return f"CoupleScoreInstance: {self.first_subject.name} and {self.second_subject.name}, score: {self.score}" 59 60 def __dict__(self) -> dict: # type: ignore 61 return { 62 "first_subject_name": self.first_subject.name, 63 "second_subject_name": self.second_subject.name, 64 "score": self.score, 65 "relevant_aspects": self.relevant_aspects, 66 "relevant_default_aspects": self.relevant_default_aspects, 67 "is_destiny_sign": self.is_destiny_sign, 68 } 69 70 def _log_aspect(self, aspect: dict, points: int) -> None: 71 logging.debug(f"{points} Points: {aspect['p1_name']} {aspect['aspect']} {aspect['p2_name']}, rounded orbit: {int(aspect['orbit'])}") 72 73 def _evaluate_destiny_sign(self) -> int: 74 """ 75 Adds 5 points if the subjects share the same sun sign quality. 76 """ 77 if self.first_subject.sun["quality"] == self.second_subject.sun["quality"]: 78 logging.debug(f'5 points: Destiny sign, {self.first_subject.sun["sign"]} and {self.second_subject.sun["sign"]}') 79 self.is_destiny_sign = True 80 return 5 81 return 0 82 83 def _check_if_sun_sun_aspect(self, aspect: dict) -> int: 84 """ 85 Adds points for Sun-Sun aspects: 86 - 8 points for conjunction/opposition/square 87 - 11 points if the aspect's orbit is <= 2 degrees 88 """ 89 aspect_types = ["conjunction", "opposition", "square"] 90 91 if aspect["p1_name"] == "Sun" and aspect["p2_name"] == "Sun" and aspect["aspect"] in aspect_types: 92 self.relevant_default_aspects.append(aspect) 93 score = 11 if aspect["orbit"] <= 2 else 8 94 95 self._log_aspect(aspect, score) 96 self.relevant_aspects.append(self._create_aspects_dictionary(aspect, score)) 97 98 return score 99 return 0 100 101 def _check_if_sun_moon_conjunction(self, aspect: dict) -> int: 102 """ 103 Adds points for Sun-Moon conjunction: 104 - 8 points for conjunction 105 - 11 points if the aspect's orbit is <= 2 degrees 106 """ 107 planets = {"Moon", "Sun"} 108 109 if {aspect["p1_name"], aspect["p2_name"]} == planets and aspect["aspect"] == "conjunction": 110 self.relevant_default_aspects.append(aspect) 111 score = 11 if aspect["orbit"] <= 2 else 8 112 113 self._log_aspect(aspect, score) 114 self.relevant_aspects.append(self._create_aspects_dictionary(aspect, score)) 115 116 return score 117 return 0 118 119 def _check_if_sun_moon_asc_aspect(self, aspect: dict) -> int: 120 """ 121 Adds 4 points for aspects involving Sun, Moon, and Ascendant. 122 """ 123 planets = ["Sun", "Moon", "First_House"] 124 125 if self._check_if_sun_sun_aspect(aspect) or self._check_if_sun_moon_conjunction(aspect): 126 return 0 127 128 if aspect["p1_name"] in planets and aspect["p2_name"] in planets: 129 self.relevant_default_aspects.append(aspect) 130 score = 4 131 132 self._log_aspect(aspect, score) 133 self.relevant_aspects.append(self._create_aspects_dictionary(aspect, score)) 134 135 return score 136 return 0 137 138 def _check_if_venus_mars_aspect(self, aspect: dict) -> int: 139 """ 140 Adds 4 points for Venus-Mars aspects. 141 """ 142 planets = {"Venus", "Mars"} 143 144 if {aspect["p1_name"], aspect["p2_name"]} == planets: 145 score = 4 146 self.relevant_default_aspects.append(aspect) 147 148 self._log_aspect(aspect, score) 149 self.relevant_aspects.append(self._create_aspects_dictionary(aspect, score)) 150 151 return score 152 return 0 153 154 def _create_aspects_dictionary(self, aspect: dict, score: int) -> dict: 155 """ 156 Creates a dictionary representation of an aspect with its score. 157 """ 158 return { 159 "points": score, 160 "p1_name": aspect["p1_name"], 161 "p2_name": aspect["p2_name"], 162 "aspect": aspect["aspect"], 163 "orbit": aspect["orbit"], 164 } 165 166 def _calculate_all(self) -> None: 167 """ 168 Calculates the total score based on all relevant aspects. 169 """ 170 self.score += self._evaluate_destiny_sign() 171 172 for aspect in self.__all_synastry_aspects: 173 self.score += self._check_if_sun_sun_aspect(aspect) 174 self.score += self._check_if_sun_moon_conjunction(aspect) 175 self.score += self._check_if_sun_moon_asc_aspect(aspect) 176 self.score += self._check_if_venus_mars_aspect(aspect)
Calculates the relevance of the relationship between two subjects using the Ciro Discepolo method.
Results: - 0 to 5: Minimal relationship - 5 to 10: Medium relationship - 10 to 15: Important relationship - 15 to 20: Very important relationship - 20 and 35: Exceptional relationship - 35 and above: Rare Exceptional relationship
Documentation: http://www.cirodiscepolo.it/Articoli/Discepoloele.htm
Args: first_subject (AstrologicalSubject): First subject instance second_subject (AstrologicalSubject): Second subject instance
RelationshipScore( first_subject: Union[kerykeion.astrological_subject.AstrologicalSubject, kerykeion.kr_types.kr_models.AstrologicalSubjectModel], second_subject: Union[kerykeion.astrological_subject.AstrologicalSubject, kerykeion.kr_types.kr_models.AstrologicalSubjectModel], new_settings_file: Optional[pathlib.Path] = None)
35 def __init__( 36 self, 37 first_subject: Union[AstrologicalSubject, AstrologicalSubjectModel], 38 second_subject: Union[AstrologicalSubject, AstrologicalSubjectModel], 39 new_settings_file: Union[Path, None] = None, 40 ): 41 warnings.warn( 42 "The RelationshipScore class is deprecated and will be removed in a future version. Use RelationshipScoreFactory instead.", 43 DeprecationWarning, 44 stacklevel=2 45 ) 46 self.first_subject = first_subject 47 self.second_subject = second_subject 48 self.score = 0 49 self.is_destiny_sign = False 50 self.relevant_aspects: list = [] 51 self.relevant_default_aspects: list = [] 52 self.__all_synastry_aspects = SynastryAspects(first_subject, second_subject, new_settings_file=new_settings_file).all_aspects 53 54 # Calculate all aspects at initialization 55 self._calculate_all()