kerykeion 5.0.0a11__py3-none-any.whl → 5.0.0b1__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 +32 -9
- kerykeion/aspects/__init__.py +2 -4
- kerykeion/aspects/aspects_factory.py +530 -0
- kerykeion/aspects/aspects_utils.py +75 -6
- kerykeion/astrological_subject_factory.py +380 -229
- kerykeion/backword.py +680 -0
- kerykeion/chart_data_factory.py +484 -0
- kerykeion/charts/{kerykeion_chart_svg.py → chart_drawer.py} +612 -439
- kerykeion/charts/charts_utils.py +135 -94
- kerykeion/charts/draw_planets.py +38 -28
- kerykeion/charts/templates/aspect_grid_only.xml +188 -17
- kerykeion/charts/templates/chart.xml +104 -28
- kerykeion/charts/templates/wheel_only.xml +195 -24
- kerykeion/charts/themes/classic.css +11 -0
- kerykeion/charts/themes/dark-high-contrast.css +11 -0
- kerykeion/charts/themes/dark.css +11 -0
- kerykeion/charts/themes/light.css +11 -0
- kerykeion/charts/themes/strawberry.css +10 -0
- kerykeion/composite_subject_factory.py +4 -4
- kerykeion/ephemeris_data_factory.py +12 -9
- kerykeion/house_comparison/__init__.py +0 -3
- kerykeion/house_comparison/house_comparison_factory.py +51 -18
- kerykeion/house_comparison/house_comparison_utils.py +37 -8
- kerykeion/planetary_return_factory.py +8 -4
- kerykeion/relationship_score_factory.py +5 -5
- kerykeion/report.py +748 -67
- kerykeion/{kr_types → schemas}/__init__.py +44 -4
- kerykeion/schemas/chart_template_model.py +340 -0
- kerykeion/{kr_types → schemas}/kr_literals.py +7 -3
- kerykeion/{kr_types → schemas}/kr_models.py +247 -21
- kerykeion/{kr_types → schemas}/settings_models.py +7 -7
- kerykeion/settings/config_constants.py +75 -8
- kerykeion/settings/kerykeion_settings.py +1 -1
- kerykeion/settings/kr.config.json +130 -40
- kerykeion/settings/legacy/legacy_celestial_points_settings.py +8 -8
- kerykeion/sweph/ast136/s136108s.se1 +0 -0
- kerykeion/sweph/ast136/s136199s.se1 +0 -0
- kerykeion/sweph/ast136/s136472s.se1 +0 -0
- kerykeion/sweph/ast28/se28978s.se1 +0 -0
- kerykeion/sweph/ast50/se50000s.se1 +0 -0
- kerykeion/sweph/ast90/se90377s.se1 +0 -0
- kerykeion/sweph/ast90/se90482s.se1 +0 -0
- kerykeion/sweph/sefstars.txt +1602 -0
- kerykeion/transits_time_range_factory.py +11 -11
- kerykeion/utilities.py +61 -38
- kerykeion-5.0.0b1.dist-info/METADATA +1055 -0
- kerykeion-5.0.0b1.dist-info/RECORD +58 -0
- kerykeion/aspects/natal_aspects_factory.py +0 -235
- kerykeion/aspects/synastry_aspects_factory.py +0 -275
- kerykeion/house_comparison/house_comparison_models.py +0 -38
- kerykeion/kr_types/chart_types.py +0 -106
- kerykeion-5.0.0a11.dist-info/METADATA +0 -641
- kerykeion-5.0.0a11.dist-info/RECORD +0 -50
- /kerykeion/{kr_types → schemas}/kerykeion_exception.py +0 -0
- {kerykeion-5.0.0a11.dist-info → kerykeion-5.0.0b1.dist-info}/WHEEL +0 -0
- {kerykeion-5.0.0a11.dist-info → kerykeion-5.0.0b1.dist-info}/licenses/LICENSE +0 -0
|
@@ -22,9 +22,9 @@ Classes:
|
|
|
22
22
|
|
|
23
23
|
Dependencies:
|
|
24
24
|
- kerykeion.AstrologicalSubjectFactory: For creating astrological subjects
|
|
25
|
-
- kerykeion.aspects.
|
|
25
|
+
- kerykeion.aspects.AspectsFactory: For calculating angular relationships
|
|
26
26
|
- kerykeion.ephemeris_data_factory: For generating time-series planetary positions
|
|
27
|
-
- kerykeion.
|
|
27
|
+
- kerykeion.schemas: For type definitions and model structures
|
|
28
28
|
- datetime: For date/time handling
|
|
29
29
|
|
|
30
30
|
Example:
|
|
@@ -57,13 +57,13 @@ License: AGPL-3.0
|
|
|
57
57
|
|
|
58
58
|
from typing import Union, List
|
|
59
59
|
from datetime import datetime, timedelta
|
|
60
|
-
from kerykeion.
|
|
60
|
+
from kerykeion.schemas.kr_models import AstrologicalSubjectModel
|
|
61
61
|
from kerykeion.astrological_subject_factory import AstrologicalSubjectFactory
|
|
62
|
-
from kerykeion.aspects import
|
|
62
|
+
from kerykeion.aspects import AspectsFactory
|
|
63
63
|
from kerykeion.ephemeris_data_factory import EphemerisDataFactory
|
|
64
|
-
from kerykeion.
|
|
65
|
-
from kerykeion.
|
|
66
|
-
from kerykeion.
|
|
64
|
+
from kerykeion.schemas.kr_literals import AstrologicalPoint
|
|
65
|
+
from kerykeion.schemas.kr_models import ActiveAspect, TransitMomentModel, TransitsTimeRangeModel
|
|
66
|
+
from kerykeion.schemas.settings_models import KerykeionSettingsModel
|
|
67
67
|
from kerykeion.settings.config_constants import DEFAULT_ACTIVE_POINTS, DEFAULT_ACTIVE_ASPECTS
|
|
68
68
|
from pathlib import Path
|
|
69
69
|
|
|
@@ -115,8 +115,8 @@ class TransitsTimeRangeFactory:
|
|
|
115
115
|
|
|
116
116
|
Custom configuration:
|
|
117
117
|
|
|
118
|
-
>>> from kerykeion.
|
|
119
|
-
>>> custom_points = [
|
|
118
|
+
>>> from kerykeion.schemas import AstrologicalPoint, ActiveAspect
|
|
119
|
+
>>> custom_points = ["Sun", "Moon"]
|
|
120
120
|
>>> custom_aspects = [ActiveAspect.CONJUNCTION, ActiveAspect.OPPOSITION]
|
|
121
121
|
>>> factory = TransitsTimeRangeFactory(
|
|
122
122
|
... natal_chart, ephemeris_data,
|
|
@@ -227,13 +227,13 @@ class TransitsTimeRangeFactory:
|
|
|
227
227
|
See Also:
|
|
228
228
|
TransitMomentModel: Individual transit moment structure
|
|
229
229
|
TransitsTimeRangeModel: Complete transit dataset structure
|
|
230
|
-
|
|
230
|
+
AspectsFactory: Underlying aspect calculation engine
|
|
231
231
|
"""
|
|
232
232
|
transit_moments = []
|
|
233
233
|
|
|
234
234
|
for ephemeris_point in self.ephemeris_data_points:
|
|
235
235
|
# Calculate aspects between transit positions and natal chart
|
|
236
|
-
aspects =
|
|
236
|
+
aspects = AspectsFactory.dual_chart_aspects(
|
|
237
237
|
ephemeris_point,
|
|
238
238
|
self.natal_chart,
|
|
239
239
|
active_points=self.active_points,
|
kerykeion/utilities.py
CHANGED
|
@@ -4,7 +4,7 @@ Copyright: (C) 2025 Kerykeion Project
|
|
|
4
4
|
License: AGPL-3.0
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from kerykeion.
|
|
7
|
+
from kerykeion.schemas import (
|
|
8
8
|
KerykeionPointModel,
|
|
9
9
|
KerykeionException,
|
|
10
10
|
ZodiacSignModel,
|
|
@@ -13,16 +13,13 @@ from kerykeion.kr_types import (
|
|
|
13
13
|
CompositeSubjectModel,
|
|
14
14
|
PlanetReturnModel,
|
|
15
15
|
)
|
|
16
|
-
from kerykeion.
|
|
17
|
-
from typing import Union,
|
|
16
|
+
from kerykeion.schemas.kr_literals import LunarPhaseEmoji, LunarPhaseName, PointType, AstrologicalPoint, Houses
|
|
17
|
+
from typing import Union, Optional, get_args
|
|
18
18
|
import logging
|
|
19
19
|
import math
|
|
20
20
|
import re
|
|
21
21
|
from datetime import datetime
|
|
22
22
|
|
|
23
|
-
if TYPE_CHECKING:
|
|
24
|
-
pass
|
|
25
|
-
|
|
26
23
|
|
|
27
24
|
def get_number_from_name(name: AstrologicalPoint) -> int:
|
|
28
25
|
"""
|
|
@@ -58,14 +55,14 @@ def get_number_from_name(name: AstrologicalPoint) -> int:
|
|
|
58
55
|
return 8
|
|
59
56
|
elif name == "Pluto":
|
|
60
57
|
return 9
|
|
61
|
-
elif name == "
|
|
58
|
+
elif name == "Mean_North_Lunar_Node":
|
|
62
59
|
return 10
|
|
63
|
-
elif name == "
|
|
60
|
+
elif name == "True_North_Lunar_Node":
|
|
64
61
|
return 11
|
|
65
62
|
# Note: Swiss ephemeris library has no constants for south nodes. We're using integers >= 1000 for them.
|
|
66
|
-
elif name == "
|
|
63
|
+
elif name == "Mean_South_Lunar_Node":
|
|
67
64
|
return 1000
|
|
68
|
-
elif name == "
|
|
65
|
+
elif name == "True_South_Lunar_Node":
|
|
69
66
|
return 1100
|
|
70
67
|
elif name == "Chiron":
|
|
71
68
|
return 15
|
|
@@ -84,7 +81,7 @@ def get_number_from_name(name: AstrologicalPoint) -> int:
|
|
|
84
81
|
|
|
85
82
|
|
|
86
83
|
def get_kerykeion_point_from_degree(
|
|
87
|
-
degree: Union[int, float], name: Union[AstrologicalPoint, Houses], point_type: PointType
|
|
84
|
+
degree: Union[int, float], name: Union[AstrologicalPoint, Houses], point_type: PointType, speed: Optional[float] = None, declination: Optional[float] = None
|
|
88
85
|
) -> KerykeionPointModel:
|
|
89
86
|
"""
|
|
90
87
|
Create a KerykeionPointModel from a degree position.
|
|
@@ -93,6 +90,8 @@ def get_kerykeion_point_from_degree(
|
|
|
93
90
|
degree: The degree position (0-360, negative values are converted to positive)
|
|
94
91
|
name: The name of the celestial point or house
|
|
95
92
|
point_type: The type classification of the point
|
|
93
|
+
speed: The velocity/speed of the celestial point in degrees per day (optional)
|
|
94
|
+
declination: The declination of the celestial point in degrees (optional)
|
|
96
95
|
|
|
97
96
|
Returns:
|
|
98
97
|
A KerykeionPointModel with calculated zodiac sign, position, and properties
|
|
@@ -136,6 +135,8 @@ def get_kerykeion_point_from_degree(
|
|
|
136
135
|
abs_pos=degree,
|
|
137
136
|
emoji=zodiac_sign.emoji,
|
|
138
137
|
point_type=point_type,
|
|
138
|
+
speed=speed,
|
|
139
|
+
declination=declination,
|
|
139
140
|
)
|
|
140
141
|
|
|
141
142
|
|
|
@@ -416,9 +417,6 @@ def calculate_moon_phase(moon_abs_pos: float, sun_abs_pos: float) -> LunarPhaseM
|
|
|
416
417
|
Returns:
|
|
417
418
|
LunarPhaseModel containing phase data, emoji, and name
|
|
418
419
|
"""
|
|
419
|
-
# Initialize moon_phase and sun_phase to None in case of an error
|
|
420
|
-
moon_phase, sun_phase = None, None
|
|
421
|
-
|
|
422
420
|
# Calculate the anti-clockwise degrees between the sun and moon
|
|
423
421
|
degrees_between = (moon_abs_pos - sun_abs_pos) % 360
|
|
424
422
|
|
|
@@ -426,30 +424,12 @@ def calculate_moon_phase(moon_abs_pos: float, sun_abs_pos: float) -> LunarPhaseM
|
|
|
426
424
|
step = 360.0 / 28.0
|
|
427
425
|
moon_phase = int(degrees_between // step) + 1
|
|
428
426
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
# Calculate the sun phase (1-28) based on the degrees between the sun and moon
|
|
436
|
-
for x in range(len(sunstep)):
|
|
437
|
-
low = sunstep[x]
|
|
438
|
-
high = sunstep[x + 1] if x < len(sunstep) - 1 else 360
|
|
439
|
-
if low <= degrees_between < high:
|
|
440
|
-
sun_phase = x + 1
|
|
441
|
-
break
|
|
442
|
-
|
|
443
|
-
# Create a dictionary with the lunar phase information
|
|
444
|
-
lunar_phase_dictionary = {
|
|
445
|
-
"degrees_between_s_m": degrees_between,
|
|
446
|
-
"moon_phase": moon_phase,
|
|
447
|
-
"sun_phase": sun_phase,
|
|
448
|
-
"moon_emoji": get_moon_emoji_from_phase_int(moon_phase),
|
|
449
|
-
"moon_phase_name": get_moon_phase_name_from_phase_int(moon_phase),
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
return LunarPhaseModel(**lunar_phase_dictionary)
|
|
427
|
+
return LunarPhaseModel(
|
|
428
|
+
degrees_between_s_m=degrees_between,
|
|
429
|
+
moon_phase=moon_phase,
|
|
430
|
+
moon_emoji=get_moon_emoji_from_phase_int(moon_phase),
|
|
431
|
+
moon_phase_name=get_moon_phase_name_from_phase_int(moon_phase)
|
|
432
|
+
)
|
|
453
433
|
|
|
454
434
|
|
|
455
435
|
def circular_sort(degrees: list[Union[int, float]]) -> list[Union[int, float]]:
|
|
@@ -751,3 +731,46 @@ def find_common_active_points(first_points: list[AstrologicalPoint], second_poin
|
|
|
751
731
|
common_points = list(set(first_points) & set(second_points))
|
|
752
732
|
|
|
753
733
|
return common_points
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
def distribute_percentages_to_100(values: dict[str, float]) -> dict[str, int]:
|
|
737
|
+
"""
|
|
738
|
+
Distribute percentages so they sum to exactly 100.
|
|
739
|
+
|
|
740
|
+
This function uses a largest remainder method to ensure that
|
|
741
|
+
the percentage total equals 100 even after rounding.
|
|
742
|
+
|
|
743
|
+
Args:
|
|
744
|
+
values: Dictionary with keys and their raw percentage values
|
|
745
|
+
|
|
746
|
+
Returns:
|
|
747
|
+
Dictionary with the same keys and integer percentages that sum to 100
|
|
748
|
+
"""
|
|
749
|
+
if not values:
|
|
750
|
+
return {}
|
|
751
|
+
|
|
752
|
+
total = sum(values.values())
|
|
753
|
+
if total == 0:
|
|
754
|
+
return {key: 0 for key in values.keys()}
|
|
755
|
+
|
|
756
|
+
# Calculate base percentages
|
|
757
|
+
percentages = {key: value * 100 / total for key, value in values.items()}
|
|
758
|
+
|
|
759
|
+
# Get integer parts and remainders
|
|
760
|
+
integer_parts = {key: int(value) for key, value in percentages.items()}
|
|
761
|
+
remainders = {key: percentages[key] - integer_parts[key] for key in percentages.keys()}
|
|
762
|
+
|
|
763
|
+
# Calculate how many we need to add to reach 100
|
|
764
|
+
current_sum = sum(integer_parts.values())
|
|
765
|
+
needed = 100 - current_sum
|
|
766
|
+
|
|
767
|
+
# Sort by remainder (largest first) and add 1 to the largest remainders
|
|
768
|
+
sorted_by_remainder = sorted(remainders.items(), key=lambda x: x[1], reverse=True)
|
|
769
|
+
|
|
770
|
+
result = integer_parts.copy()
|
|
771
|
+
for i in range(needed):
|
|
772
|
+
if i < len(sorted_by_remainder):
|
|
773
|
+
key = sorted_by_remainder[i][0]
|
|
774
|
+
result[key] += 1
|
|
775
|
+
|
|
776
|
+
return result
|