kerykeion.utilities
1from kerykeion.kr_types import KerykeionPointModel, KerykeionException, KerykeionSettingsModel, AstrologicalSubjectModel 2from kerykeion.kr_types.kr_literals import LunarPhaseEmoji, LunarPhaseName, PointType, Planet 3from typing import Union 4import logging 5import math 6 7 8 9def get_number_from_name(name: Planet) -> int: 10 """Utility function, gets planet id from the name.""" 11 12 if name == "Sun": 13 return 0 14 elif name == "Moon": 15 return 1 16 elif name == "Mercury": 17 return 2 18 elif name == "Venus": 19 return 3 20 elif name == "Mars": 21 return 4 22 elif name == "Jupiter": 23 return 5 24 elif name == "Saturn": 25 return 6 26 elif name == "Uranus": 27 return 7 28 elif name == "Neptune": 29 return 8 30 elif name == "Pluto": 31 return 9 32 elif name == "Mean_Node": 33 return 10 34 elif name == "True_Node": 35 return 11 36 elif name == "Chiron": 37 return 15 38 else: 39 raise KerykeionException(f"Error in getting number from name! Name: {name}") 40 41 42def calculate_position( 43 degree: Union[int, float], number_name: str, point_type: PointType 44) -> KerykeionPointModel: 45 """Utility function to create a dictionary dividing the houses or the planets list.""" 46 47 if degree < 30: 48 dictionary = { 49 "name": number_name, 50 "quality": "Cardinal", 51 "element": "Fire", 52 "sign": "Ari", 53 "sign_num": 0, 54 "position": degree, 55 "abs_pos": degree, 56 "emoji": "♈️", 57 "point_type": point_type, 58 } 59 60 elif degree < 60: 61 result = degree - 30 62 dictionary = { 63 "name": number_name, 64 "quality": "Fixed", 65 "element": "Earth", 66 "sign": "Tau", 67 "sign_num": 1, 68 "position": result, 69 "abs_pos": degree, 70 "emoji": "♉️", 71 "point_type": point_type, 72 } 73 elif degree < 90: 74 result = degree - 60 75 dictionary = { 76 "name": number_name, 77 "quality": "Mutable", 78 "element": "Air", 79 "sign": "Gem", 80 "sign_num": 2, 81 "position": result, 82 "abs_pos": degree, 83 "emoji": "♊️", 84 "point_type": point_type, 85 } 86 elif degree < 120: 87 result = degree - 90 88 dictionary = { 89 "name": number_name, 90 "quality": "Cardinal", 91 "element": "Water", 92 "sign": "Can", 93 "sign_num": 3, 94 "position": result, 95 "abs_pos": degree, 96 "emoji": "♋️", 97 "point_type": point_type, 98 } 99 elif degree < 150: 100 result = degree - 120 101 dictionary = { 102 "name": number_name, 103 "quality": "Fixed", 104 "element": "Fire", 105 "sign": "Leo", 106 "sign_num": 4, 107 "position": result, 108 "abs_pos": degree, 109 "emoji": "♌️", 110 "point_type": point_type, 111 } 112 elif degree < 180: 113 result = degree - 150 114 dictionary = { 115 "name": number_name, 116 "quality": "Mutable", 117 "element": "Earth", 118 "sign": "Vir", 119 "sign_num": 5, 120 "position": result, 121 "abs_pos": degree, 122 "emoji": "♍️", 123 "point_type": point_type, 124 } 125 elif degree < 210: 126 result = degree - 180 127 dictionary = { 128 "name": number_name, 129 "quality": "Cardinal", 130 "element": "Air", 131 "sign": "Lib", 132 "sign_num": 6, 133 "position": result, 134 "abs_pos": degree, 135 "emoji": "♎️", 136 "point_type": point_type, 137 } 138 elif degree < 240: 139 result = degree - 210 140 dictionary = { 141 "name": number_name, 142 "quality": "Fixed", 143 "element": "Water", 144 "sign": "Sco", 145 "sign_num": 7, 146 "position": result, 147 "abs_pos": degree, 148 "emoji": "♏️", 149 "point_type": point_type, 150 } 151 elif degree < 270: 152 result = degree - 240 153 dictionary = { 154 "name": number_name, 155 "quality": "Mutable", 156 "element": "Fire", 157 "sign": "Sag", 158 "sign_num": 8, 159 "position": result, 160 "abs_pos": degree, 161 "emoji": "♐️", 162 "point_type": point_type, 163 } 164 elif degree < 300: 165 result = degree - 270 166 dictionary = { 167 "name": number_name, 168 "quality": "Cardinal", 169 "element": "Earth", 170 "sign": "Cap", 171 "sign_num": 9, 172 "position": result, 173 "abs_pos": degree, 174 "emoji": "♑️", 175 "point_type": point_type, 176 } 177 elif degree < 330: 178 result = degree - 300 179 dictionary = { 180 "name": number_name, 181 "quality": "Fixed", 182 "element": "Air", 183 "sign": "Aqu", 184 "sign_num": 10, 185 "position": result, 186 "abs_pos": degree, 187 "emoji": "♒️", 188 "point_type": point_type, 189 } 190 elif degree < 360: 191 result = degree - 330 192 dictionary = { 193 "name": number_name, 194 "quality": "Mutable", 195 "element": "Water", 196 "sign": "Pis", 197 "sign_num": 11, 198 "position": result, 199 "abs_pos": degree, 200 "emoji": "♓️", 201 "point_type": point_type, 202 } 203 else: 204 raise KerykeionException(f"Error in calculating positions! Degrees: {degree}") 205 206 return KerykeionPointModel(**dictionary) 207 208 209def setup_logging(level: str) -> None: 210 """ 211 Setup logging for testing. 212 213 Args: 214 level: Log level as a string, options: debug, info, warning, error 215 """ 216 logging_options: dict[str, int] = { 217 "debug": logging.DEBUG, 218 "info": logging.INFO, 219 "warning": logging.WARNING, 220 "error": logging.ERROR, 221 } 222 format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" 223 loglevel: int = logging_options.get(level, logging.INFO) 224 logging.basicConfig(format=format, level=loglevel) 225 226def check_if_point_between( 227 start_point: Union[int, float], end_point: Union[int, float], evaluated_point: Union[int, float] 228) -> bool: 229 """ 230 Finds if a point is between two other in a circle. 231 232 Args: 233 - start_point: The first point 234 - end_point: The second point 235 - point: The point to check if it is between start_point and end_point 236 237 Returns: 238 - True if point is between start_point and end_point, False otherwise 239 """ 240 241 p1_p2 = math.fmod(end_point - start_point + 360, 360) 242 p1_p3 = math.fmod(evaluated_point - start_point + 360, 360) 243 244 if (p1_p2 <= 180) != (p1_p3 > p1_p2): 245 return True 246 else: 247 return False 248 249 250def get_planet_house(planet_position_degree: Union[int, float], houses_degree_ut_list: list) -> str: 251 """ 252 Returns the house in which a planet is located. 253 254 Args: 255 - planet_position_degree: The position of the planet in degrees 256 - houses_degree_ut_list: A list of the houses in degrees (0-360) 257 258 Returns: 259 - The house in which the planet is located 260 """ 261 262 house = None 263 if check_if_point_between(houses_degree_ut_list[0], houses_degree_ut_list[1], planet_position_degree) == True: 264 house = "First_House" 265 elif check_if_point_between(houses_degree_ut_list[1], houses_degree_ut_list[2], planet_position_degree) == True: 266 house = "Second_House" 267 elif check_if_point_between(houses_degree_ut_list[2], houses_degree_ut_list[3], planet_position_degree) == True: 268 house = "Third_House" 269 elif check_if_point_between(houses_degree_ut_list[3], houses_degree_ut_list[4], planet_position_degree) == True: 270 house = "Fourth_House" 271 elif check_if_point_between(houses_degree_ut_list[4], houses_degree_ut_list[5], planet_position_degree) == True: 272 house = "Fifth_House" 273 elif check_if_point_between(houses_degree_ut_list[5], houses_degree_ut_list[6], planet_position_degree) == True: 274 house = "Sixth_House" 275 elif check_if_point_between(houses_degree_ut_list[6], houses_degree_ut_list[7], planet_position_degree) == True: 276 house = "Seventh_House" 277 elif check_if_point_between(houses_degree_ut_list[7], houses_degree_ut_list[8], planet_position_degree) == True: 278 house = "Eighth_House" 279 elif check_if_point_between(houses_degree_ut_list[8], houses_degree_ut_list[9], planet_position_degree) == True: 280 house = "Ninth_House" 281 elif check_if_point_between(houses_degree_ut_list[9], houses_degree_ut_list[10], planet_position_degree) == True: 282 house = "Tenth_House" 283 elif check_if_point_between(houses_degree_ut_list[10], houses_degree_ut_list[11], planet_position_degree) == True: 284 house = "Eleventh_House" 285 elif check_if_point_between(houses_degree_ut_list[11], houses_degree_ut_list[0], planet_position_degree) == True: 286 house = "Twelfth_House" 287 else: 288 raise ValueError("Error in house calculation, planet: ", planet_position_degree, "houses: ", houses_degree_ut_list) 289 290 return house 291 292def get_moon_emoji_from_phase_int(phase: int) -> LunarPhaseEmoji: 293 """ 294 Returns the emoji of the moon phase. 295 296 Args: 297 - phase: The phase of the moon (0-28) 298 299 Returns: 300 - The emoji of the moon phase 301 """ 302 303 if phase == 1: 304 result = "🌑" 305 elif phase < 7: 306 result = "🌒" 307 elif 7 <= phase <= 9: 308 result = "🌓" 309 elif phase < 14: 310 result = "🌔" 311 elif phase == 14: 312 result = "🌕" 313 elif phase < 20: 314 result = "🌖" 315 elif 20 <= phase <= 22: 316 result = "🌗" 317 elif phase <= 28: 318 result = "🌘" 319 320 else: 321 raise KerykeionException(f"Error in moon emoji calculation! Phase: {phase}") 322 323 return result 324 325def get_moon_phase_name_from_phase_int(phase: int) -> LunarPhaseName: 326 """ 327 Returns the name of the moon phase. 328 329 Args: 330 - phase: The phase of the moon (0-28) 331 332 Returns: 333 - The name of the moon phase 334 """ 335 336 if phase == 1: 337 result = "New Moon" 338 elif phase < 7: 339 result = "Waxing Crescent" 340 elif 7 <= phase <= 9: 341 result = "First Quarter" 342 elif phase < 14: 343 result = "Waxing Gibbous" 344 elif phase == 14: 345 result = "Full Moon" 346 elif phase < 20: 347 result = "Waning Gibbous" 348 elif 20 <= phase <= 22: 349 result = "Last Quarter" 350 elif phase <= 28: 351 result = "Waning Crescent" 352 353 else: 354 raise KerykeionException(f"Error in moon name calculation! Phase: {phase}") 355 356 return result 357 358 359def check_and_adjust_polar_latitude(latitude: float, longitude: float) -> bool: 360 """ 361 Utility function to check if the location is in the polar circle. 362 If it is, it sets the latitude to 66 or -66 degrees. 363 """ 364 if latitude > 66.0: 365 latitude = 66.0 366 logging.info("Polar circle override for houses, using 66 degrees") 367 368 elif latitude < -66.0: 369 latitude = -66.0 370 logging.info("Polar circle override for houses, using -66 degrees")
10def get_number_from_name(name: Planet) -> int: 11 """Utility function, gets planet id from the name.""" 12 13 if name == "Sun": 14 return 0 15 elif name == "Moon": 16 return 1 17 elif name == "Mercury": 18 return 2 19 elif name == "Venus": 20 return 3 21 elif name == "Mars": 22 return 4 23 elif name == "Jupiter": 24 return 5 25 elif name == "Saturn": 26 return 6 27 elif name == "Uranus": 28 return 7 29 elif name == "Neptune": 30 return 8 31 elif name == "Pluto": 32 return 9 33 elif name == "Mean_Node": 34 return 10 35 elif name == "True_Node": 36 return 11 37 elif name == "Chiron": 38 return 15 39 else: 40 raise KerykeionException(f"Error in getting number from name! Name: {name}")
Utility function, gets planet id from the name.
43def calculate_position( 44 degree: Union[int, float], number_name: str, point_type: PointType 45) -> KerykeionPointModel: 46 """Utility function to create a dictionary dividing the houses or the planets list.""" 47 48 if degree < 30: 49 dictionary = { 50 "name": number_name, 51 "quality": "Cardinal", 52 "element": "Fire", 53 "sign": "Ari", 54 "sign_num": 0, 55 "position": degree, 56 "abs_pos": degree, 57 "emoji": "♈️", 58 "point_type": point_type, 59 } 60 61 elif degree < 60: 62 result = degree - 30 63 dictionary = { 64 "name": number_name, 65 "quality": "Fixed", 66 "element": "Earth", 67 "sign": "Tau", 68 "sign_num": 1, 69 "position": result, 70 "abs_pos": degree, 71 "emoji": "♉️", 72 "point_type": point_type, 73 } 74 elif degree < 90: 75 result = degree - 60 76 dictionary = { 77 "name": number_name, 78 "quality": "Mutable", 79 "element": "Air", 80 "sign": "Gem", 81 "sign_num": 2, 82 "position": result, 83 "abs_pos": degree, 84 "emoji": "♊️", 85 "point_type": point_type, 86 } 87 elif degree < 120: 88 result = degree - 90 89 dictionary = { 90 "name": number_name, 91 "quality": "Cardinal", 92 "element": "Water", 93 "sign": "Can", 94 "sign_num": 3, 95 "position": result, 96 "abs_pos": degree, 97 "emoji": "♋️", 98 "point_type": point_type, 99 } 100 elif degree < 150: 101 result = degree - 120 102 dictionary = { 103 "name": number_name, 104 "quality": "Fixed", 105 "element": "Fire", 106 "sign": "Leo", 107 "sign_num": 4, 108 "position": result, 109 "abs_pos": degree, 110 "emoji": "♌️", 111 "point_type": point_type, 112 } 113 elif degree < 180: 114 result = degree - 150 115 dictionary = { 116 "name": number_name, 117 "quality": "Mutable", 118 "element": "Earth", 119 "sign": "Vir", 120 "sign_num": 5, 121 "position": result, 122 "abs_pos": degree, 123 "emoji": "♍️", 124 "point_type": point_type, 125 } 126 elif degree < 210: 127 result = degree - 180 128 dictionary = { 129 "name": number_name, 130 "quality": "Cardinal", 131 "element": "Air", 132 "sign": "Lib", 133 "sign_num": 6, 134 "position": result, 135 "abs_pos": degree, 136 "emoji": "♎️", 137 "point_type": point_type, 138 } 139 elif degree < 240: 140 result = degree - 210 141 dictionary = { 142 "name": number_name, 143 "quality": "Fixed", 144 "element": "Water", 145 "sign": "Sco", 146 "sign_num": 7, 147 "position": result, 148 "abs_pos": degree, 149 "emoji": "♏️", 150 "point_type": point_type, 151 } 152 elif degree < 270: 153 result = degree - 240 154 dictionary = { 155 "name": number_name, 156 "quality": "Mutable", 157 "element": "Fire", 158 "sign": "Sag", 159 "sign_num": 8, 160 "position": result, 161 "abs_pos": degree, 162 "emoji": "♐️", 163 "point_type": point_type, 164 } 165 elif degree < 300: 166 result = degree - 270 167 dictionary = { 168 "name": number_name, 169 "quality": "Cardinal", 170 "element": "Earth", 171 "sign": "Cap", 172 "sign_num": 9, 173 "position": result, 174 "abs_pos": degree, 175 "emoji": "♑️", 176 "point_type": point_type, 177 } 178 elif degree < 330: 179 result = degree - 300 180 dictionary = { 181 "name": number_name, 182 "quality": "Fixed", 183 "element": "Air", 184 "sign": "Aqu", 185 "sign_num": 10, 186 "position": result, 187 "abs_pos": degree, 188 "emoji": "♒️", 189 "point_type": point_type, 190 } 191 elif degree < 360: 192 result = degree - 330 193 dictionary = { 194 "name": number_name, 195 "quality": "Mutable", 196 "element": "Water", 197 "sign": "Pis", 198 "sign_num": 11, 199 "position": result, 200 "abs_pos": degree, 201 "emoji": "♓️", 202 "point_type": point_type, 203 } 204 else: 205 raise KerykeionException(f"Error in calculating positions! Degrees: {degree}") 206 207 return KerykeionPointModel(**dictionary)
Utility function to create a dictionary dividing the houses or the planets list.
210def setup_logging(level: str) -> None: 211 """ 212 Setup logging for testing. 213 214 Args: 215 level: Log level as a string, options: debug, info, warning, error 216 """ 217 logging_options: dict[str, int] = { 218 "debug": logging.DEBUG, 219 "info": logging.INFO, 220 "warning": logging.WARNING, 221 "error": logging.ERROR, 222 } 223 format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" 224 loglevel: int = logging_options.get(level, logging.INFO) 225 logging.basicConfig(format=format, level=loglevel)
Setup logging for testing.
Args: level: Log level as a string, options: debug, info, warning, error
227def check_if_point_between( 228 start_point: Union[int, float], end_point: Union[int, float], evaluated_point: Union[int, float] 229) -> bool: 230 """ 231 Finds if a point is between two other in a circle. 232 233 Args: 234 - start_point: The first point 235 - end_point: The second point 236 - point: The point to check if it is between start_point and end_point 237 238 Returns: 239 - True if point is between start_point and end_point, False otherwise 240 """ 241 242 p1_p2 = math.fmod(end_point - start_point + 360, 360) 243 p1_p3 = math.fmod(evaluated_point - start_point + 360, 360) 244 245 if (p1_p2 <= 180) != (p1_p3 > p1_p2): 246 return True 247 else: 248 return False
Finds if a point is between two other in a circle.
Args: - start_point: The first point - end_point: The second point - point: The point to check if it is between start_point and end_point
Returns: - True if point is between start_point and end_point, False otherwise
251def get_planet_house(planet_position_degree: Union[int, float], houses_degree_ut_list: list) -> str: 252 """ 253 Returns the house in which a planet is located. 254 255 Args: 256 - planet_position_degree: The position of the planet in degrees 257 - houses_degree_ut_list: A list of the houses in degrees (0-360) 258 259 Returns: 260 - The house in which the planet is located 261 """ 262 263 house = None 264 if check_if_point_between(houses_degree_ut_list[0], houses_degree_ut_list[1], planet_position_degree) == True: 265 house = "First_House" 266 elif check_if_point_between(houses_degree_ut_list[1], houses_degree_ut_list[2], planet_position_degree) == True: 267 house = "Second_House" 268 elif check_if_point_between(houses_degree_ut_list[2], houses_degree_ut_list[3], planet_position_degree) == True: 269 house = "Third_House" 270 elif check_if_point_between(houses_degree_ut_list[3], houses_degree_ut_list[4], planet_position_degree) == True: 271 house = "Fourth_House" 272 elif check_if_point_between(houses_degree_ut_list[4], houses_degree_ut_list[5], planet_position_degree) == True: 273 house = "Fifth_House" 274 elif check_if_point_between(houses_degree_ut_list[5], houses_degree_ut_list[6], planet_position_degree) == True: 275 house = "Sixth_House" 276 elif check_if_point_between(houses_degree_ut_list[6], houses_degree_ut_list[7], planet_position_degree) == True: 277 house = "Seventh_House" 278 elif check_if_point_between(houses_degree_ut_list[7], houses_degree_ut_list[8], planet_position_degree) == True: 279 house = "Eighth_House" 280 elif check_if_point_between(houses_degree_ut_list[8], houses_degree_ut_list[9], planet_position_degree) == True: 281 house = "Ninth_House" 282 elif check_if_point_between(houses_degree_ut_list[9], houses_degree_ut_list[10], planet_position_degree) == True: 283 house = "Tenth_House" 284 elif check_if_point_between(houses_degree_ut_list[10], houses_degree_ut_list[11], planet_position_degree) == True: 285 house = "Eleventh_House" 286 elif check_if_point_between(houses_degree_ut_list[11], houses_degree_ut_list[0], planet_position_degree) == True: 287 house = "Twelfth_House" 288 else: 289 raise ValueError("Error in house calculation, planet: ", planet_position_degree, "houses: ", houses_degree_ut_list) 290 291 return house
Returns the house in which a planet is located.
Args: - planet_position_degree: The position of the planet in degrees - houses_degree_ut_list: A list of the houses in degrees (0-360)
Returns: - The house in which the planet is located
293def get_moon_emoji_from_phase_int(phase: int) -> LunarPhaseEmoji: 294 """ 295 Returns the emoji of the moon phase. 296 297 Args: 298 - phase: The phase of the moon (0-28) 299 300 Returns: 301 - The emoji of the moon phase 302 """ 303 304 if phase == 1: 305 result = "🌑" 306 elif phase < 7: 307 result = "🌒" 308 elif 7 <= phase <= 9: 309 result = "🌓" 310 elif phase < 14: 311 result = "🌔" 312 elif phase == 14: 313 result = "🌕" 314 elif phase < 20: 315 result = "🌖" 316 elif 20 <= phase <= 22: 317 result = "🌗" 318 elif phase <= 28: 319 result = "🌘" 320 321 else: 322 raise KerykeionException(f"Error in moon emoji calculation! Phase: {phase}") 323 324 return result
Returns the emoji of the moon phase.
Args: - phase: The phase of the moon (0-28)
Returns: - The emoji of the moon phase
326def get_moon_phase_name_from_phase_int(phase: int) -> LunarPhaseName: 327 """ 328 Returns the name of the moon phase. 329 330 Args: 331 - phase: The phase of the moon (0-28) 332 333 Returns: 334 - The name of the moon phase 335 """ 336 337 if phase == 1: 338 result = "New Moon" 339 elif phase < 7: 340 result = "Waxing Crescent" 341 elif 7 <= phase <= 9: 342 result = "First Quarter" 343 elif phase < 14: 344 result = "Waxing Gibbous" 345 elif phase == 14: 346 result = "Full Moon" 347 elif phase < 20: 348 result = "Waning Gibbous" 349 elif 20 <= phase <= 22: 350 result = "Last Quarter" 351 elif phase <= 28: 352 result = "Waning Crescent" 353 354 else: 355 raise KerykeionException(f"Error in moon name calculation! Phase: {phase}") 356 357 return result
Returns the name of the moon phase.
Args: - phase: The phase of the moon (0-28)
Returns: - The name of the moon phase
360def check_and_adjust_polar_latitude(latitude: float, longitude: float) -> bool: 361 """ 362 Utility function to check if the location is in the polar circle. 363 If it is, it sets the latitude to 66 or -66 degrees. 364 """ 365 if latitude > 66.0: 366 latitude = 66.0 367 logging.info("Polar circle override for houses, using 66 degrees") 368 369 elif latitude < -66.0: 370 latitude = -66.0 371 logging.info("Polar circle override for houses, using -66 degrees")
Utility function to check if the location is in the polar circle. If it is, it sets the latitude to 66 or -66 degrees.