kerykeion 5.0.0a9__py3-none-any.whl → 5.0.0a11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kerykeion might be problematic. Click here for more details.
- kerykeion/__init__.py +21 -4
- kerykeion/aspects/__init__.py +7 -2
- kerykeion/aspects/aspects_utils.py +1 -3
- kerykeion/aspects/natal_aspects_factory.py +235 -0
- kerykeion/aspects/synastry_aspects_factory.py +275 -0
- kerykeion/astrological_subject_factory.py +688 -86
- kerykeion/charts/charts_utils.py +12 -12
- kerykeion/charts/draw_planets.py +584 -344
- kerykeion/charts/kerykeion_chart_svg.py +11 -16
- kerykeion/charts/templates/wheel_only.xml +1 -1
- kerykeion/composite_subject_factory.py +229 -10
- kerykeion/ephemeris_data_factory.py +431 -0
- kerykeion/fetch_geonames.py +27 -8
- kerykeion/house_comparison/__init__.py +6 -0
- kerykeion/house_comparison/house_comparison_factory.py +1 -1
- kerykeion/house_comparison/house_comparison_utils.py +0 -1
- kerykeion/kr_types/__init__.py +49 -0
- kerykeion/kr_types/kerykeion_exception.py +6 -0
- kerykeion/kr_types/kr_models.py +84 -2
- kerykeion/kr_types/settings_models.py +9 -1
- kerykeion/planetary_return_factory.py +538 -37
- kerykeion/relationship_score_factory.py +123 -59
- kerykeion/report.py +7 -1
- kerykeion/settings/__init__.py +5 -0
- kerykeion/settings/config_constants.py +20 -6
- kerykeion/settings/kr.config.json +80 -0
- kerykeion/transits_time_range_factory.py +293 -0
- kerykeion/utilities.py +130 -68
- {kerykeion-5.0.0a9.dist-info → kerykeion-5.0.0a11.dist-info}/METADATA +9 -4
- kerykeion-5.0.0a11.dist-info/RECORD +50 -0
- kerykeion/aspects/natal_aspects.py +0 -181
- kerykeion/aspects/synastry_aspects.py +0 -141
- kerykeion/aspects/transits_time_range.py +0 -41
- kerykeion/charts/draw_planets_v2.py +0 -649
- kerykeion/charts/draw_planets_v3.py +0 -679
- kerykeion/enums.py +0 -57
- kerykeion/ephemeris_data.py +0 -238
- kerykeion/transits_time_range.py +0 -128
- kerykeion-5.0.0a9.dist-info/RECORD +0 -55
- kerykeion-5.0.0a9.dist-info/entry_points.txt +0 -2
- {kerykeion-5.0.0a9.dist-info → kerykeion-5.0.0a11.dist-info}/WHEEL +0 -0
- {kerykeion-5.0.0a9.dist-info → kerykeion-5.0.0a11.dist-info}/licenses/LICENSE +0 -0
kerykeion/utilities.py
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Giacomo Battaglia
|
|
3
|
+
Copyright: (C) 2025 Kerykeion Project
|
|
4
|
+
License: AGPL-3.0
|
|
5
|
+
"""
|
|
6
|
+
|
|
1
7
|
from kerykeion.kr_types import (
|
|
2
8
|
KerykeionPointModel,
|
|
3
9
|
KerykeionException,
|
|
@@ -15,11 +21,22 @@ import re
|
|
|
15
21
|
from datetime import datetime
|
|
16
22
|
|
|
17
23
|
if TYPE_CHECKING:
|
|
18
|
-
|
|
24
|
+
pass
|
|
19
25
|
|
|
20
26
|
|
|
21
27
|
def get_number_from_name(name: AstrologicalPoint) -> int:
|
|
22
|
-
"""
|
|
28
|
+
"""
|
|
29
|
+
Convert an astrological point name to its corresponding numerical identifier.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
name: The name of the astrological point
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
The numerical identifier used in Swiss Ephemeris calculations
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
KerykeionException: If the name is not recognized
|
|
39
|
+
"""
|
|
23
40
|
|
|
24
41
|
if name == "Sun":
|
|
25
42
|
return 0
|
|
@@ -70,18 +87,18 @@ def get_kerykeion_point_from_degree(
|
|
|
70
87
|
degree: Union[int, float], name: Union[AstrologicalPoint, Houses], point_type: PointType
|
|
71
88
|
) -> KerykeionPointModel:
|
|
72
89
|
"""
|
|
73
|
-
|
|
90
|
+
Create a KerykeionPointModel from a degree position.
|
|
74
91
|
|
|
75
92
|
Args:
|
|
76
|
-
degree (
|
|
77
|
-
name
|
|
78
|
-
point_type
|
|
79
|
-
|
|
80
|
-
Raises:
|
|
81
|
-
KerykeionException: If the degree is not within the valid range (0-360).
|
|
93
|
+
degree: The degree position (0-360, negative values are converted to positive)
|
|
94
|
+
name: The name of the celestial point or house
|
|
95
|
+
point_type: The type classification of the point
|
|
82
96
|
|
|
83
97
|
Returns:
|
|
84
|
-
KerykeionPointModel
|
|
98
|
+
A KerykeionPointModel with calculated zodiac sign, position, and properties
|
|
99
|
+
|
|
100
|
+
Raises:
|
|
101
|
+
KerykeionException: If the degree is >= 360 after normalization
|
|
85
102
|
"""
|
|
86
103
|
# If - single degree is given, convert it to a positive degree
|
|
87
104
|
if degree < 0:
|
|
@@ -124,10 +141,10 @@ def get_kerykeion_point_from_degree(
|
|
|
124
141
|
|
|
125
142
|
def setup_logging(level: str) -> None:
|
|
126
143
|
"""
|
|
127
|
-
|
|
144
|
+
Configure logging for the application.
|
|
128
145
|
|
|
129
146
|
Args:
|
|
130
|
-
level: Log level as
|
|
147
|
+
level: Log level as string (debug, info, warning, error, critical)
|
|
131
148
|
"""
|
|
132
149
|
logging_options: dict[str, int] = {
|
|
133
150
|
"debug": logging.DEBUG,
|
|
@@ -145,18 +162,23 @@ def is_point_between(
|
|
|
145
162
|
start_point: Union[int, float], end_point: Union[int, float], evaluated_point: Union[int, float]
|
|
146
163
|
) -> bool:
|
|
147
164
|
"""
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
-
|
|
165
|
+
Determine if a point lies between two other points on a circle.
|
|
166
|
+
|
|
167
|
+
Special rules:
|
|
168
|
+
- If evaluated_point equals start_point, returns True
|
|
169
|
+
- If evaluated_point equals end_point, returns False
|
|
170
|
+
- The arc between start_point and end_point must not exceed 180°
|
|
152
171
|
|
|
153
172
|
Args:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
173
|
+
start_point: The starting point on the circle
|
|
174
|
+
end_point: The ending point on the circle
|
|
175
|
+
evaluated_point: The point to evaluate
|
|
157
176
|
|
|
158
177
|
Returns:
|
|
159
|
-
|
|
178
|
+
True if evaluated_point is between start_point and end_point, False otherwise
|
|
179
|
+
|
|
180
|
+
Raises:
|
|
181
|
+
KerykeionException: If the angular difference exceeds 180°
|
|
160
182
|
"""
|
|
161
183
|
|
|
162
184
|
# Normalize angles to [0, 360)
|
|
@@ -193,17 +215,17 @@ def is_point_between(
|
|
|
193
215
|
|
|
194
216
|
def get_planet_house(planet_position_degree: Union[int, float], houses_degree_ut_list: list) -> Houses:
|
|
195
217
|
"""
|
|
196
|
-
|
|
218
|
+
Determine which house contains a planet based on its degree position.
|
|
197
219
|
|
|
198
220
|
Args:
|
|
199
|
-
planet_position_degree
|
|
200
|
-
houses_degree_ut_list
|
|
221
|
+
planet_position_degree: The planet's position in degrees (0-360)
|
|
222
|
+
houses_degree_ut_list: List of house cusp degrees
|
|
201
223
|
|
|
202
224
|
Returns:
|
|
203
|
-
|
|
225
|
+
The house name containing the planet
|
|
204
226
|
|
|
205
227
|
Raises:
|
|
206
|
-
ValueError: If the planet's position
|
|
228
|
+
ValueError: If the planet's position doesn't fall within any house range
|
|
207
229
|
"""
|
|
208
230
|
|
|
209
231
|
house_names = get_args(Houses)
|
|
@@ -222,13 +244,16 @@ def get_planet_house(planet_position_degree: Union[int, float], houses_degree_ut
|
|
|
222
244
|
|
|
223
245
|
def get_moon_emoji_from_phase_int(phase: int) -> LunarPhaseEmoji:
|
|
224
246
|
"""
|
|
225
|
-
|
|
247
|
+
Get the emoji representation of a lunar phase.
|
|
226
248
|
|
|
227
249
|
Args:
|
|
228
|
-
|
|
250
|
+
phase: The lunar phase number (0-28)
|
|
229
251
|
|
|
230
252
|
Returns:
|
|
231
|
-
|
|
253
|
+
The corresponding emoji for the lunar phase
|
|
254
|
+
|
|
255
|
+
Raises:
|
|
256
|
+
KerykeionException: If phase is outside valid range
|
|
232
257
|
"""
|
|
233
258
|
|
|
234
259
|
lunar_phase_emojis = get_args(LunarPhaseEmoji)
|
|
@@ -258,13 +283,16 @@ def get_moon_emoji_from_phase_int(phase: int) -> LunarPhaseEmoji:
|
|
|
258
283
|
|
|
259
284
|
def get_moon_phase_name_from_phase_int(phase: int) -> LunarPhaseName:
|
|
260
285
|
"""
|
|
261
|
-
|
|
286
|
+
Get the name of a lunar phase from its numerical value.
|
|
262
287
|
|
|
263
288
|
Args:
|
|
264
|
-
|
|
289
|
+
phase: The lunar phase number (0-28)
|
|
265
290
|
|
|
266
291
|
Returns:
|
|
267
|
-
|
|
292
|
+
The corresponding name for the lunar phase
|
|
293
|
+
|
|
294
|
+
Raises:
|
|
295
|
+
KerykeionException: If phase is outside valid range
|
|
268
296
|
"""
|
|
269
297
|
lunar_phase_names = get_args(LunarPhaseName)
|
|
270
298
|
|
|
@@ -293,8 +321,15 @@ def get_moon_phase_name_from_phase_int(phase: int) -> LunarPhaseName:
|
|
|
293
321
|
|
|
294
322
|
def check_and_adjust_polar_latitude(latitude: float) -> float:
|
|
295
323
|
"""
|
|
296
|
-
|
|
297
|
-
|
|
324
|
+
Adjust latitude values for polar regions to prevent calculation errors.
|
|
325
|
+
|
|
326
|
+
Latitudes beyond ±66° are clamped to ±66° for house calculations.
|
|
327
|
+
|
|
328
|
+
Args:
|
|
329
|
+
latitude: The original latitude value
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
The adjusted latitude value, clamped between -66° and 66°
|
|
298
333
|
"""
|
|
299
334
|
if latitude > 66.0:
|
|
300
335
|
latitude = 66.0
|
|
@@ -311,7 +346,13 @@ def get_houses_list(
|
|
|
311
346
|
subject: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel]
|
|
312
347
|
) -> list[KerykeionPointModel]:
|
|
313
348
|
"""
|
|
314
|
-
|
|
349
|
+
Get a list of house objects in order from the subject.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
subject: The astrological subject containing house data
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
List of KerykeionPointModel objects representing the houses
|
|
315
356
|
"""
|
|
316
357
|
houses_absolute_position_list = []
|
|
317
358
|
for house in subject.houses_names_list:
|
|
@@ -324,8 +365,13 @@ def get_available_astrological_points_list(
|
|
|
324
365
|
subject: AstrologicalSubjectModel
|
|
325
366
|
) -> list[KerykeionPointModel]:
|
|
326
367
|
"""
|
|
327
|
-
|
|
328
|
-
|
|
368
|
+
Get a list of active astrological point objects from the subject.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
subject: The astrological subject containing point data
|
|
372
|
+
|
|
373
|
+
Returns:
|
|
374
|
+
List of KerykeionPointModel objects for all active points
|
|
329
375
|
"""
|
|
330
376
|
planets_absolute_position_list = []
|
|
331
377
|
for planet in subject.active_points:
|
|
@@ -336,17 +382,17 @@ def get_available_astrological_points_list(
|
|
|
336
382
|
|
|
337
383
|
def circular_mean(first_position: Union[int, float], second_position: Union[int, float]) -> float:
|
|
338
384
|
"""
|
|
339
|
-
|
|
385
|
+
Calculate the circular mean of two angular positions.
|
|
340
386
|
|
|
341
|
-
This
|
|
342
|
-
avoiding errors that occur with simple
|
|
387
|
+
This method correctly handles positions that cross the 0°/360° boundary,
|
|
388
|
+
avoiding errors that occur with simple arithmetic means.
|
|
343
389
|
|
|
344
390
|
Args:
|
|
345
|
-
|
|
346
|
-
|
|
391
|
+
first_position: First angular position in degrees (0-360)
|
|
392
|
+
second_position: Second angular position in degrees (0-360)
|
|
347
393
|
|
|
348
394
|
Returns:
|
|
349
|
-
|
|
395
|
+
The circular mean position in degrees (0-360)
|
|
350
396
|
"""
|
|
351
397
|
x = (math.cos(math.radians(first_position)) + math.cos(math.radians(second_position))) / 2
|
|
352
398
|
y = (math.sin(math.radians(first_position)) + math.sin(math.radians(second_position))) / 2
|
|
@@ -361,14 +407,14 @@ def circular_mean(first_position: Union[int, float], second_position: Union[int,
|
|
|
361
407
|
|
|
362
408
|
def calculate_moon_phase(moon_abs_pos: float, sun_abs_pos: float) -> LunarPhaseModel:
|
|
363
409
|
"""
|
|
364
|
-
Calculate
|
|
410
|
+
Calculate lunar phase information from Sun and Moon positions.
|
|
365
411
|
|
|
366
412
|
Args:
|
|
367
|
-
|
|
368
|
-
|
|
413
|
+
moon_abs_pos: Absolute position of the Moon in degrees
|
|
414
|
+
sun_abs_pos: Absolute position of the Sun in degrees
|
|
369
415
|
|
|
370
416
|
Returns:
|
|
371
|
-
|
|
417
|
+
LunarPhaseModel containing phase data, emoji, and name
|
|
372
418
|
"""
|
|
373
419
|
# Initialize moon_phase and sun_phase to None in case of an error
|
|
374
420
|
moon_phase, sun_phase = None, None
|
|
@@ -408,14 +454,13 @@ def calculate_moon_phase(moon_abs_pos: float, sun_abs_pos: float) -> LunarPhaseM
|
|
|
408
454
|
|
|
409
455
|
def circular_sort(degrees: list[Union[int, float]]) -> list[Union[int, float]]:
|
|
410
456
|
"""
|
|
411
|
-
Sort
|
|
412
|
-
and progressing clockwise around the circle.
|
|
457
|
+
Sort degrees in circular clockwise progression starting from the first element.
|
|
413
458
|
|
|
414
459
|
Args:
|
|
415
|
-
degrees:
|
|
460
|
+
degrees: List of numeric degree values
|
|
416
461
|
|
|
417
462
|
Returns:
|
|
418
|
-
|
|
463
|
+
List sorted by clockwise distance from the first element
|
|
419
464
|
|
|
420
465
|
Raises:
|
|
421
466
|
ValueError: If the list is empty or contains non-numeric values
|
|
@@ -458,14 +503,16 @@ def circular_sort(degrees: list[Union[int, float]]) -> list[Union[int, float]]:
|
|
|
458
503
|
|
|
459
504
|
def inline_css_variables_in_svg(svg_content: str) -> str:
|
|
460
505
|
"""
|
|
461
|
-
|
|
506
|
+
Replace CSS custom properties (variables) with their values in SVG content.
|
|
507
|
+
|
|
508
|
+
Extracts CSS variables from style blocks, replaces var() references with actual values,
|
|
509
|
+
and removes all style blocks from the SVG.
|
|
462
510
|
|
|
463
511
|
Args:
|
|
464
|
-
svg_content
|
|
512
|
+
svg_content: The original SVG string with CSS variables
|
|
465
513
|
|
|
466
514
|
Returns:
|
|
467
|
-
|
|
468
|
-
and all style blocks removed
|
|
515
|
+
Modified SVG with CSS variables inlined and style blocks removed
|
|
469
516
|
"""
|
|
470
517
|
# Find and extract CSS custom properties from style tags
|
|
471
518
|
css_variable_map = {}
|
|
@@ -486,6 +533,15 @@ def inline_css_variables_in_svg(svg_content: str) -> str:
|
|
|
486
533
|
|
|
487
534
|
# Function to replace var() references with their actual values
|
|
488
535
|
def replace_css_variable_reference(match):
|
|
536
|
+
"""
|
|
537
|
+
Replace CSS variable references with their actual values.
|
|
538
|
+
|
|
539
|
+
Args:
|
|
540
|
+
match: Regular expression match object containing variable name and optional fallback.
|
|
541
|
+
|
|
542
|
+
Returns:
|
|
543
|
+
str: The resolved CSS variable value or fallback value.
|
|
544
|
+
"""
|
|
489
545
|
variable_name = match.group(1).strip()
|
|
490
546
|
fallback_value = match.group(2) if match.group(2) else None
|
|
491
547
|
|
|
@@ -510,13 +566,13 @@ def inline_css_variables_in_svg(svg_content: str) -> str:
|
|
|
510
566
|
|
|
511
567
|
def datetime_to_julian(dt: datetime) -> float:
|
|
512
568
|
"""
|
|
513
|
-
|
|
569
|
+
Convert a Python datetime object to Julian Day Number.
|
|
514
570
|
|
|
515
571
|
Args:
|
|
516
|
-
dt:
|
|
572
|
+
dt: The datetime object to convert
|
|
517
573
|
|
|
518
574
|
Returns:
|
|
519
|
-
|
|
575
|
+
The corresponding Julian Day Number (JD) as a float
|
|
520
576
|
"""
|
|
521
577
|
# Extract year, month and day
|
|
522
578
|
year = dt.year
|
|
@@ -548,13 +604,13 @@ def datetime_to_julian(dt: datetime) -> float:
|
|
|
548
604
|
|
|
549
605
|
def julian_to_datetime(jd):
|
|
550
606
|
"""
|
|
551
|
-
|
|
607
|
+
Convert a Julian Day Number to a Python datetime object.
|
|
552
608
|
|
|
553
609
|
Args:
|
|
554
|
-
jd: Julian
|
|
610
|
+
jd: Julian Day Number as a float
|
|
555
611
|
|
|
556
612
|
Returns:
|
|
557
|
-
|
|
613
|
+
The corresponding datetime object
|
|
558
614
|
"""
|
|
559
615
|
# Add 0.5 to the Julian day to adjust for noon-based Julian day
|
|
560
616
|
jd_plus = jd + 0.5
|
|
@@ -613,13 +669,16 @@ def julian_to_datetime(jd):
|
|
|
613
669
|
|
|
614
670
|
def get_house_name(house_number: int) -> Houses:
|
|
615
671
|
"""
|
|
616
|
-
|
|
672
|
+
Convert a house number to its corresponding house name.
|
|
617
673
|
|
|
618
674
|
Args:
|
|
619
675
|
house_number: House number (1-12)
|
|
620
676
|
|
|
621
677
|
Returns:
|
|
622
|
-
|
|
678
|
+
The house name
|
|
679
|
+
|
|
680
|
+
Raises:
|
|
681
|
+
ValueError: If house_number is not in range 1-12
|
|
623
682
|
"""
|
|
624
683
|
house_names: dict[int, Houses] = {
|
|
625
684
|
1: "First_House",
|
|
@@ -645,13 +704,16 @@ def get_house_name(house_number: int) -> Houses:
|
|
|
645
704
|
|
|
646
705
|
def get_house_number(house_name: Houses) -> int:
|
|
647
706
|
"""
|
|
648
|
-
|
|
707
|
+
Convert a house name to its corresponding house number.
|
|
649
708
|
|
|
650
709
|
Args:
|
|
651
|
-
house_name:
|
|
710
|
+
house_name: The house name
|
|
652
711
|
|
|
653
712
|
Returns:
|
|
654
713
|
House number (1-12)
|
|
714
|
+
|
|
715
|
+
Raises:
|
|
716
|
+
ValueError: If house_name is not recognized
|
|
655
717
|
"""
|
|
656
718
|
house_numbers: dict[Houses, int] = {
|
|
657
719
|
"First_House": 1,
|
|
@@ -677,14 +739,14 @@ def get_house_number(house_name: Houses) -> int:
|
|
|
677
739
|
|
|
678
740
|
def find_common_active_points(first_points: list[AstrologicalPoint], second_points: list[AstrologicalPoint]) -> list[AstrologicalPoint]:
|
|
679
741
|
"""
|
|
680
|
-
Find
|
|
742
|
+
Find astrological points that appear in both input lists.
|
|
681
743
|
|
|
682
744
|
Args:
|
|
683
|
-
first_points:
|
|
684
|
-
second_points:
|
|
745
|
+
first_points: First list of astrological points
|
|
746
|
+
second_points: Second list of astrological points
|
|
685
747
|
|
|
686
748
|
Returns:
|
|
687
|
-
List of
|
|
749
|
+
List of points common to both input lists (without duplicates)
|
|
688
750
|
"""
|
|
689
751
|
common_points = list(set(first_points) & set(second_points))
|
|
690
752
|
|
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kerykeion
|
|
3
|
-
Version: 5.0.
|
|
4
|
-
Summary: A
|
|
3
|
+
Version: 5.0.0a11
|
|
4
|
+
Summary: A Python library for astrological calculations, including natal charts, houses, planetary aspects, and SVG chart generation.
|
|
5
5
|
Project-URL: Homepage, https://www.kerykeion.net/
|
|
6
6
|
Project-URL: Repository, https://github.com/g-battaglia/kerykeion
|
|
7
7
|
Author-email: Giacomo Battaglia <kerykeion.astrology@gmail.com>
|
|
8
8
|
License: AGPL-3.0
|
|
9
9
|
License-File: LICENSE
|
|
10
|
-
Keywords: astrology,astrology
|
|
10
|
+
Keywords: astrology,astrology calculations,astrology calculator,astrology library,astrology transits,astronomical algorithms,birth chart,ephemeris,houses of astrology,natal chart,planetary aspects,svg charts,synastry,zodiac,zodiac signs
|
|
11
11
|
Classifier: Development Status :: 5 - Production/Stable
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Intended Audience :: Information Technology
|
|
14
|
-
Classifier:
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
15
16
|
Classifier: Operating System :: OS Independent
|
|
16
17
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
18
|
Classifier: Programming Language :: Python :: 3.9
|
|
18
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Religion
|
|
20
24
|
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
21
26
|
Classifier: Topic :: Software Development
|
|
22
27
|
Classifier: Topic :: Software Development :: Libraries
|
|
23
28
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
kerykeion/__init__.py,sha256=0nw7gz0b1fGUvRlNfIMOGognUd9y6cP1hXxHN2LQ_nM,1338
|
|
2
|
+
kerykeion/astrological_subject_factory.py,sha256=xyWbrThNuUnjKVrglJKCNdiKlnDmJU8GiRRu8QlIlL8,83659
|
|
3
|
+
kerykeion/composite_subject_factory.py,sha256=sqs7CiP_3lGI9-FeRFMFL7PIXTlSUaXA9pUDI_5zPZw,17124
|
|
4
|
+
kerykeion/ephemeris_data_factory.py,sha256=Iwd8KkBB-WmI8AEwrhe9ze8dicA5kvpflT_yQD9XkAY,20111
|
|
5
|
+
kerykeion/fetch_geonames.py,sha256=SPI4fSvD59C-IVpaoeOHuD7_kjGbTLo2fypO2x57-p4,5432
|
|
6
|
+
kerykeion/planetary_return_factory.py,sha256=7fwfjhJATFmUNJkIqgaz07sWtpwHPjHvF2oFyPGfga4,37246
|
|
7
|
+
kerykeion/relationship_score_factory.py,sha256=aYpWkkcZGNpmCW8Ul5FcXh3skVFSN07WPZroL1KXDoc,11135
|
|
8
|
+
kerykeion/report.py,sha256=dUtI70wUjOouqNE1pf0ZYFY4qme9pR7WQRbs_ExEkjM,3029
|
|
9
|
+
kerykeion/transits_time_range_factory.py,sha256=n25xQeqiKGYGhBvxUJKT6Dxc7L7lw46TGBy3L8RSb_g,13419
|
|
10
|
+
kerykeion/utilities.py,sha256=MtVyZ2dbHrJPuDoPKPrkx0MrB83fxcbGtPx87piHCtQ,23471
|
|
11
|
+
kerykeion/aspects/__init__.py,sha256=i1hg04VL15s-LVGOHuTWJsicv_HNwT3b2v6_-16s6A4,394
|
|
12
|
+
kerykeion/aspects/aspects_utils.py,sha256=mOj2AqVGnY2vsGsezPfxI_crPJsN54p8qjpmCk5iupM,3093
|
|
13
|
+
kerykeion/aspects/natal_aspects_factory.py,sha256=If-XV1_QLpQPKjka_dJjMOqhAyAIi7icwxhhOEhwzm4,9318
|
|
14
|
+
kerykeion/aspects/synastry_aspects_factory.py,sha256=NpOn-h6nqKbkVpDucn8i-3lW_tqNZyUOQGNXCJ36ULU,12690
|
|
15
|
+
kerykeion/charts/__init__.py,sha256=i9NMZ7LdkllPlqQSi1or9gTobHbROGDKmJhBDO4R0mA,128
|
|
16
|
+
kerykeion/charts/charts_utils.py,sha256=_z-lA7ibIQ5vhr1NxpzJFyPmMp-Sh1iyYxuO56DDO4w,62922
|
|
17
|
+
kerykeion/charts/draw_planets.py,sha256=6S0sCAktZJa7eckb-h1voYbe0H27vL9otcJzA0dqFH0,28167
|
|
18
|
+
kerykeion/charts/kerykeion_chart_svg.py,sha256=ILsSV8QDEgtraYIn60ZQVOYeNptX5IarbzZwwEitVc4,97414
|
|
19
|
+
kerykeion/charts/templates/aspect_grid_only.xml,sha256=lBHBj5bS5klGnv7QMuFxQjhlE6VZRaOgW93akLgRjX4,70055
|
|
20
|
+
kerykeion/charts/templates/chart.xml,sha256=r3a_csMqcoqeOnDA3YCD-iUxdqgRw5GV1GOf1Cp0e_E,79940
|
|
21
|
+
kerykeion/charts/templates/wheel_only.xml,sha256=X2-bwmEvQnZcM5Om7JXIWZSoSmFLAm4sY31heSq5u1k,71388
|
|
22
|
+
kerykeion/charts/themes/classic.css,sha256=LYYYWQHNG7-vuPCq8F2EPl3LauWXVrY3Q_tpwM0klgo,4660
|
|
23
|
+
kerykeion/charts/themes/dark-high-contrast.css,sha256=YW5X5-M0dz5Vy2oz-JyDNXJYHSmV83lYCodydC-KS1A,7506
|
|
24
|
+
kerykeion/charts/themes/dark.css,sha256=XVspznDRNMXsFzk7hY7IB7AI58alPAV_-CgV3gCKyzg,7581
|
|
25
|
+
kerykeion/charts/themes/light.css,sha256=5eyUzhVlRjG6lPHKnprLum0HuRtPIJhMBzpGfzoTjnQ,7590
|
|
26
|
+
kerykeion/charts/themes/strawberry.css,sha256=UtcfRsCT-M9OZs_SoclWGZ0jDJiWvQjHTeI4M1jf7pQ,8314
|
|
27
|
+
kerykeion/house_comparison/__init__.py,sha256=6FYHyQY3nUJifZ2kEVCHB8cN3TjFA1q2yhmeRwJlias,238
|
|
28
|
+
kerykeion/house_comparison/house_comparison_factory.py,sha256=Vn4_Hviy20_nsSf_vjEKZ9h-QsJDFtapM1Wydvwgx4w,3345
|
|
29
|
+
kerykeion/house_comparison/house_comparison_models.py,sha256=R9EW5F3fiIKIm8qrwTxtXhNOGDpf1-Lh9hbM1uK83oE,1549
|
|
30
|
+
kerykeion/house_comparison/house_comparison_utils.py,sha256=Q5pdP7hmUEB3cqE7QkOYNu_laQ1Nj83Fmn_F8YJkKik,3773
|
|
31
|
+
kerykeion/kr_types/__init__.py,sha256=dePcQY5rrgtUENhqnjcVx6j7iQJPo_1rmD0bLeIO3HA,1384
|
|
32
|
+
kerykeion/kr_types/chart_types.py,sha256=ofMYk7NRalSsdQcLVkpCbOb-dhdjYHEqIb_WPLtD0rM,2429
|
|
33
|
+
kerykeion/kr_types/kerykeion_exception.py,sha256=vTYdwj_mL-Q-MqHJvEzzBXxQ5YI2kAwUC6ImoWxMKXc,454
|
|
34
|
+
kerykeion/kr_types/kr_literals.py,sha256=4kJhzm_0LERiJEJks0KgDyThueMZj_F1OK2Far5SMZc,4870
|
|
35
|
+
kerykeion/kr_types/kr_models.py,sha256=cwpmP5CMM8Bi8aYfST6tVivFe3VuZh9S4jLoDWBAWM8,13601
|
|
36
|
+
kerykeion/kr_types/settings_models.py,sha256=Llosnvw-6NHJMbdKltPHQDLR-Ltn7ZpWkjEbLJ2C6AY,17488
|
|
37
|
+
kerykeion/settings/__init__.py,sha256=NYCwcvEfn9qJ498fv1H_Gix8e-crJ3CruV13A-e2CnI,134
|
|
38
|
+
kerykeion/settings/config_constants.py,sha256=hxDZnFKWFhGrYMejDISbYT-phUk1Qqfvt-4wBG79rGA,2233
|
|
39
|
+
kerykeion/settings/kerykeion_settings.py,sha256=umd8TZy-8ywowsd4TTkhwxSLLyX3xYj3A1zvNsTV_Y8,2955
|
|
40
|
+
kerykeion/settings/kr.config.json,sha256=bvvhi8W-u9YHTbg9O8UyfOwclhLd8Mh8oobI1qHIgp4,58497
|
|
41
|
+
kerykeion/settings/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
|
+
kerykeion/settings/legacy/legacy_celestial_points_settings.py,sha256=YMvHhY8IQ_nNHf1-9JCSgRzTMQJaxXZfROztEhlP4Ac,6870
|
|
43
|
+
kerykeion/settings/legacy/legacy_chart_aspects_settings.py,sha256=tO4tgPgPP07_wu9f8SXyJQ9WrTh3iWz4YvBS2axCGU8,1650
|
|
44
|
+
kerykeion/settings/legacy/legacy_color_settings.py,sha256=gBUmGSNvvLzRYbdVtzwTDnMwWoh4tOCyT_9Q6aQRv_s,2620
|
|
45
|
+
kerykeion/sweph/README.md,sha256=L7FtNAJTWtrZNGKa8MX87SjduFYPYxwWhaI5fmtzNZo,73
|
|
46
|
+
kerykeion/sweph/seas_18.se1,sha256=X9nCqhZU43wJpq61WAdueVQJt9xL2UjrwPqn1Kdoa1s,223002
|
|
47
|
+
kerykeion-5.0.0a11.dist-info/METADATA,sha256=bIW3d40hSJyDoA0KIacZoCko2_kd6TjNGvZ_DG82vPU,25544
|
|
48
|
+
kerykeion-5.0.0a11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
49
|
+
kerykeion-5.0.0a11.dist-info/licenses/LICENSE,sha256=UTLH8EdbAsgQei4PA2PnBCPGLSZkq5J-dhkyJuXgWQU,34273
|
|
50
|
+
kerykeion-5.0.0a11.dist-info/RECORD,,
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
This is part of Kerykeion (C) 2025 Giacomo Battaglia
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import logging
|
|
7
|
-
from dataclasses import dataclass, field
|
|
8
|
-
from functools import cached_property
|
|
9
|
-
from kerykeion.astrological_subject_factory import AstrologicalSubjectFactory
|
|
10
|
-
from kerykeion.settings.kerykeion_settings import get_settings
|
|
11
|
-
from kerykeion.aspects.aspects_utils import planet_id_decoder, get_aspect_from_two_points, get_active_points_list
|
|
12
|
-
from kerykeion.kr_types.kr_models import AstrologicalSubjectModel, AspectModel, ActiveAspect, CompositeSubjectModel, PlanetReturnModel
|
|
13
|
-
from kerykeion.kr_types.kr_literals import AstrologicalPoint
|
|
14
|
-
from kerykeion.kr_types.settings_models import KerykeionSettingsModel
|
|
15
|
-
from kerykeion.settings.config_constants import DEFAULT_ACTIVE_POINTS, DEFAULT_ACTIVE_ASPECTS, DEFAULT_AXIS_ORBIT
|
|
16
|
-
from kerykeion.settings.legacy.legacy_celestial_points_settings import DEFAULT_CELESTIAL_POINTS_SETTINGS
|
|
17
|
-
from kerykeion.settings.legacy.legacy_chart_aspects_settings import DEFAULT_CHART_ASPECTS_SETTINGS
|
|
18
|
-
from kerykeion.utilities import find_common_active_points
|
|
19
|
-
from pathlib import Path
|
|
20
|
-
from typing import Union, List, Optional
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
AXES_LIST = [
|
|
24
|
-
"Ascendant",
|
|
25
|
-
"Medium_Coeli",
|
|
26
|
-
"Descendant",
|
|
27
|
-
"Imum_Coeli",
|
|
28
|
-
]
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@dataclass
|
|
32
|
-
class NatalAspects:
|
|
33
|
-
"""
|
|
34
|
-
Generates an object with all the aspects of a birthcart.
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
user: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel]
|
|
38
|
-
new_settings_file: Union[Path, KerykeionSettingsModel, dict, None] = None
|
|
39
|
-
active_points: Optional[List[AstrologicalPoint]] = field(default_factory=lambda: None)
|
|
40
|
-
active_aspects: List[ActiveAspect] = field(default_factory=lambda: DEFAULT_ACTIVE_ASPECTS)
|
|
41
|
-
|
|
42
|
-
def __post_init__(self):
|
|
43
|
-
self.settings = get_settings(self.new_settings_file)
|
|
44
|
-
|
|
45
|
-
self.celestial_points = DEFAULT_CELESTIAL_POINTS_SETTINGS
|
|
46
|
-
self.aspects_settings = DEFAULT_CHART_ASPECTS_SETTINGS
|
|
47
|
-
self.axes_orbit_settings = DEFAULT_AXIS_ORBIT
|
|
48
|
-
|
|
49
|
-
if not self.active_points:
|
|
50
|
-
self.active_points = self.user.active_points
|
|
51
|
-
else:
|
|
52
|
-
self.active_points = find_common_active_points(
|
|
53
|
-
self.user.active_points,
|
|
54
|
-
self.active_points,
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@cached_property
|
|
59
|
-
def all_aspects(self):
|
|
60
|
-
"""
|
|
61
|
-
Return all the aspects of the points in the natal chart in a dictionary,
|
|
62
|
-
first all the individual aspects of each planet, second the aspects
|
|
63
|
-
without repetitions.
|
|
64
|
-
"""
|
|
65
|
-
|
|
66
|
-
active_points_list = get_active_points_list(self.user, 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
|
-
break # Exit the inner loop once a match is found
|
|
76
|
-
self.aspects_settings = filtered_settings
|
|
77
|
-
# <--- TODO: Clean this up
|
|
78
|
-
|
|
79
|
-
self.all_aspects_list = []
|
|
80
|
-
for first in range(len(active_points_list)):
|
|
81
|
-
# Generates the aspects list without repetitions
|
|
82
|
-
for second in range(first + 1, len(active_points_list)):
|
|
83
|
-
# AC/DC, MC/IC and North/South nodes are always in opposition
|
|
84
|
-
opposite_pairs = {
|
|
85
|
-
("Ascendant", "Descendant"),
|
|
86
|
-
("Descendant", "Ascendant"),
|
|
87
|
-
("Medium_Coeli", "Imum_Coeli"),
|
|
88
|
-
("Imum_Coeli", "Medium_Coeli"),
|
|
89
|
-
("True_Node", "True_South_Node"),
|
|
90
|
-
("Mean_Node", "Mean_South_Node"),
|
|
91
|
-
("True_South_Node", "True_Node"),
|
|
92
|
-
("Mean_South_Node", "Mean_Node"),
|
|
93
|
-
}
|
|
94
|
-
if (active_points_list[first]["name"], active_points_list[second]["name"]) in opposite_pairs:
|
|
95
|
-
continue
|
|
96
|
-
|
|
97
|
-
aspect = get_aspect_from_two_points(
|
|
98
|
-
self.aspects_settings,
|
|
99
|
-
active_points_list[first]["abs_pos"],
|
|
100
|
-
active_points_list[second]["abs_pos"]
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
verdict = aspect["verdict"]
|
|
104
|
-
name = aspect["name"]
|
|
105
|
-
orbit = aspect["orbit"]
|
|
106
|
-
aspect_degrees = aspect["aspect_degrees"]
|
|
107
|
-
diff = aspect["diff"]
|
|
108
|
-
|
|
109
|
-
if verdict == True:
|
|
110
|
-
aspect_model = AspectModel(
|
|
111
|
-
p1_name=active_points_list[first]["name"],
|
|
112
|
-
p1_owner=self.user.name,
|
|
113
|
-
p1_abs_pos=active_points_list[first]["abs_pos"],
|
|
114
|
-
p2_name=active_points_list[second]["name"],
|
|
115
|
-
p2_owner=self.user.name,
|
|
116
|
-
p2_abs_pos=active_points_list[second]["abs_pos"],
|
|
117
|
-
aspect=name,
|
|
118
|
-
orbit=orbit,
|
|
119
|
-
aspect_degrees=aspect_degrees,
|
|
120
|
-
diff=diff,
|
|
121
|
-
p1=planet_id_decoder(self.celestial_points, active_points_list[first]["name"]),
|
|
122
|
-
p2=planet_id_decoder(self.celestial_points, active_points_list[second]["name"]),
|
|
123
|
-
)
|
|
124
|
-
self.all_aspects_list.append(aspect_model)
|
|
125
|
-
|
|
126
|
-
return self.all_aspects_list
|
|
127
|
-
|
|
128
|
-
@cached_property
|
|
129
|
-
def relevant_aspects(self):
|
|
130
|
-
"""
|
|
131
|
-
Filters the aspects list with the desired points, in this case
|
|
132
|
-
the most important are hardcoded.
|
|
133
|
-
Set the list with set_points and creating a list with the names
|
|
134
|
-
or the numbers of the houses.
|
|
135
|
-
The relevant aspects are the ones that are set as looping in the available_aspects list.
|
|
136
|
-
"""
|
|
137
|
-
|
|
138
|
-
logging.debug("Relevant aspects not already calculated, calculating now...")
|
|
139
|
-
self.all_aspects
|
|
140
|
-
|
|
141
|
-
axes_list = AXES_LIST
|
|
142
|
-
counter = 0
|
|
143
|
-
|
|
144
|
-
# Remove aspects where the orbits exceed the maximum orb thresholds specified in the settings
|
|
145
|
-
# (specified usually in kr.config.json file)
|
|
146
|
-
aspects_filtered = self.all_aspects
|
|
147
|
-
aspects_list_subtract = []
|
|
148
|
-
for a in aspects_filtered:
|
|
149
|
-
counter += 1
|
|
150
|
-
name_p1 = str(a["p1_name"])
|
|
151
|
-
name_p2 = str(a["p2_name"])
|
|
152
|
-
|
|
153
|
-
if name_p1 in axes_list:
|
|
154
|
-
if abs(a["orbit"]) >= self.axes_orbit_settings:
|
|
155
|
-
aspects_list_subtract.append(a)
|
|
156
|
-
|
|
157
|
-
elif name_p2 in axes_list:
|
|
158
|
-
if abs(a["orbit"]) >= self.axes_orbit_settings:
|
|
159
|
-
aspects_list_subtract.append(a)
|
|
160
|
-
|
|
161
|
-
self.aspects = [item for item in aspects_filtered if item not in aspects_list_subtract]
|
|
162
|
-
|
|
163
|
-
return self.aspects
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if __name__ == "__main__":
|
|
167
|
-
from kerykeion.utilities import setup_logging
|
|
168
|
-
|
|
169
|
-
setup_logging(level="debug")
|
|
170
|
-
|
|
171
|
-
johnny = AstrologicalSubjectFactory.from_birth_data("Johnny Depp", 1963, 6, 9, 0, 0, 0, "Owensboro", "US")
|
|
172
|
-
|
|
173
|
-
# All aspects as a list of dictionaries
|
|
174
|
-
aspects = NatalAspects(johnny)
|
|
175
|
-
#print([a.model_dump() for a in aspects.all_aspects])
|
|
176
|
-
|
|
177
|
-
print("\n")
|
|
178
|
-
|
|
179
|
-
# Relevant aspects as a list of dictionaries
|
|
180
|
-
aspects = NatalAspects(johnny)
|
|
181
|
-
print([a.model_dump() for a in aspects.relevant_aspects])
|