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
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
kerykeion/__init__.py,sha256=gxAmthMletKqFDIFCSKNLKs5frs9JI2j9koiy2FIviE,1934
|
|
2
|
+
kerykeion/astrological_subject_factory.py,sha256=KaNuPSgVOgAva9z83fTuCpvIfEm3hsJro-z_mFPU1Q4,94604
|
|
3
|
+
kerykeion/backword.py,sha256=1meyJZXGy5eFKMQ0jiFDaUSkKCdzSHvew2Sy9cQ7AmE,29066
|
|
4
|
+
kerykeion/chart_data_factory.py,sha256=5JI5GW9ZqFyKc4gs53TiGffQFaEVwGS8yY9dmEKpsy8,21055
|
|
5
|
+
kerykeion/composite_subject_factory.py,sha256=eUtjThDlYr6SQsEi02_CgO1kEMUMYgQGzR5rX91GEwY,17120
|
|
6
|
+
kerykeion/ephemeris_data_factory.py,sha256=uwEhVqqkB56HbxKueMAvSAbEKkYTJ9GH3mVLDNxIQnc,20358
|
|
7
|
+
kerykeion/fetch_geonames.py,sha256=SPI4fSvD59C-IVpaoeOHuD7_kjGbTLo2fypO2x57-p4,5432
|
|
8
|
+
kerykeion/planetary_return_factory.py,sha256=bIVPqa2gs7hYHi8aaMfVr4U99xWZk3LmYqZI9KG6ACo,37572
|
|
9
|
+
kerykeion/relationship_score_factory.py,sha256=H05FHjW27r_hJeHWRhIBPvlmc264dMdOEibkgh__iU4,11098
|
|
10
|
+
kerykeion/report.py,sha256=Bv8OOl-HG87pm7RM_SzhblTfvdc_n2C91PkJi7iHAXo,31513
|
|
11
|
+
kerykeion/transits_time_range_factory.py,sha256=p76TxPTRlN9bzF1z_rroJVdpVpb52aM8Lp6jFScTCVg,13354
|
|
12
|
+
kerykeion/utilities.py,sha256=LKljXx0HSjlT5pspvG4VIY1po_xG1dLGNNfEWg0G5Fs,24391
|
|
13
|
+
kerykeion/aspects/__init__.py,sha256=csJmxvLdBu-bHuW676f3dpY__Qyc6LwRyrpWVTh3n1A,287
|
|
14
|
+
kerykeion/aspects/aspects_factory.py,sha256=kli4YUhAQtnidD4icrmD6EeGnZ_jylDqOsXVkIMvQB4,23487
|
|
15
|
+
kerykeion/aspects/aspects_utils.py,sha256=xIeu6cFsdX_Fbo_c2WPF4hga9YJLWGG5pwCqHX9Z4pU,5809
|
|
16
|
+
kerykeion/charts/__init__.py,sha256=i9NMZ7LdkllPlqQSi1or9gTobHbROGDKmJhBDO4R0mA,128
|
|
17
|
+
kerykeion/charts/chart_drawer.py,sha256=igzRogHJ3arKSa0EXiXhI03LnGnWsHLuM-gO0sdCHj4,108083
|
|
18
|
+
kerykeion/charts/charts_utils.py,sha256=4R2pAa47-TcM7eYxXGri98u5sPJhl6YmmgdQTUUXGi8,64847
|
|
19
|
+
kerykeion/charts/draw_planets.py,sha256=tIj3FeLLomVSbCaZUxfw_qBEB3pxi4EIEhqaeTgTyTY,29061
|
|
20
|
+
kerykeion/charts/templates/aspect_grid_only.xml,sha256=mSiSDnPmyysG7NzCQLhr1QxWafMNOGZ1R6_ABFaM7Jk,79706
|
|
21
|
+
kerykeion/charts/templates/chart.xml,sha256=Cp8ZBOBrQAafk-H2_HHuxD3Cz7EZ4_l-DJ6_Y5oGAjk,84792
|
|
22
|
+
kerykeion/charts/templates/wheel_only.xml,sha256=NjhkExEZTE_le7002k7ewcCS4FoQij6H07jb5D9HVac,81047
|
|
23
|
+
kerykeion/charts/themes/classic.css,sha256=xvBiI4DtY5fMaA7ilxGl26VEDY1VzkOTWm1XOs9n-ec,5158
|
|
24
|
+
kerykeion/charts/themes/dark-high-contrast.css,sha256=EbmK9sM_ksJ5Fx36cb91nSvSsqC6mzjkRXCpwNTHfCE,8260
|
|
25
|
+
kerykeion/charts/themes/dark.css,sha256=gub44WABpHseNNaWu4lVmtvDthgrRCvEVaobcd-UrMY,8335
|
|
26
|
+
kerykeion/charts/themes/light.css,sha256=WEX_uKPArTjignVwvuAHqqWIbNiCheQ9Y7MgK0HJjAM,8344
|
|
27
|
+
kerykeion/charts/themes/strawberry.css,sha256=pFrST9xDRiej-YXh7P_snOr46DUcKjw--5d2MrlashY,9001
|
|
28
|
+
kerykeion/house_comparison/__init__.py,sha256=dnSVpx_pKylYUeaTGxHsSlN15HqQS6eJHpDQOrIvrpY,107
|
|
29
|
+
kerykeion/house_comparison/house_comparison_factory.py,sha256=YkA7itvkyIcKEf8Ffi53on-gGhsHi_Oeu9Gm4N9aHQs,4588
|
|
30
|
+
kerykeion/house_comparison/house_comparison_utils.py,sha256=vzME6Aw5njCXu6BmPLuhgfEVDI00qfQI7MPH-YujO1g,5071
|
|
31
|
+
kerykeion/schemas/__init__.py,sha256=CU1I1JanyY-0-Uq7oCHQT6wmmkOgfP0zZwHtCvF0W0g,2215
|
|
32
|
+
kerykeion/schemas/chart_template_model.py,sha256=0JJ13jQ6UHvZPlg_6NH57GuL7Z0yXrd8VIWDBQvBnOE,8125
|
|
33
|
+
kerykeion/schemas/kerykeion_exception.py,sha256=vTYdwj_mL-Q-MqHJvEzzBXxQ5YI2kAwUC6ImoWxMKXc,454
|
|
34
|
+
kerykeion/schemas/kr_literals.py,sha256=_GrBO9s0lfNDAk4oE4pf7DF7HEgAGTgklvlAn0SePuo,5119
|
|
35
|
+
kerykeion/schemas/kr_models.py,sha256=C8Xo4uPxMfCUbKOBopKrbI8bSZzWVXImYsOJEZIlBjQ,22159
|
|
36
|
+
kerykeion/schemas/settings_models.py,sha256=NlOW9T7T5kD5Dzna1UOdb7XPQeQnzMOu0y4-ApERxPw,17619
|
|
37
|
+
kerykeion/settings/__init__.py,sha256=NYCwcvEfn9qJ498fv1H_Gix8e-crJ3CruV13A-e2CnI,134
|
|
38
|
+
kerykeion/settings/config_constants.py,sha256=mLpWtL46iXFp0pYDaVtKRBzGbl3rZKj3XxjIM88DYRQ,3790
|
|
39
|
+
kerykeion/settings/kerykeion_settings.py,sha256=jesmjfeDU6t-aNyXmzqfMGHBEATk7tenWkQT8cox-FY,2954
|
|
40
|
+
kerykeion/settings/kr.config.json,sha256=Ap_EE98RT957AXNmj2LWr1fmVMf9NO2_jCpAthHPmHs,62094
|
|
41
|
+
kerykeion/settings/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
|
+
kerykeion/settings/legacy/legacy_celestial_points_settings.py,sha256=RsGmX10cO1jw2W3IwK1OBnzzgaI3nUiFIYHeoYtjapw,6942
|
|
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/sweph/sefstars.txt,sha256=GLDcr75bckB3PauiwDijJfWz_EFj9h4Kf06Sq9T1F8Y,136618
|
|
48
|
+
kerykeion/sweph/ast136/s136108s.se1,sha256=eSDfBurMBVnawSnZZgwHUrwqeAZYlKPLH1NNtq0ep7I,19489
|
|
49
|
+
kerykeion/sweph/ast136/s136199s.se1,sha256=eNBaQGxAmnqeAgE_C-cpsX4BTgPYR4_H9HRkI9QHMPA,14514
|
|
50
|
+
kerykeion/sweph/ast136/s136472s.se1,sha256=TjBnDMtPWdBzbOHn9Mju5C2i-Kfg1dT7kQaeVuGOoi8,19454
|
|
51
|
+
kerykeion/sweph/ast28/se28978s.se1,sha256=nU2Qp-ELc_tzFnRc1QT6uVueWXEipvhYDgfQRX1TAC4,16227
|
|
52
|
+
kerykeion/sweph/ast50/se50000s.se1,sha256=9jTrPlIrZMOBWC9cNgwzcfz0KBHdXFZoY9-NZ_HtECo,15748
|
|
53
|
+
kerykeion/sweph/ast90/se90377s.se1,sha256=bto2x4LtBv8b1ej1XhVFYq-kfHO9cczbKV9U1f9UVu4,10288
|
|
54
|
+
kerykeion/sweph/ast90/se90482s.se1,sha256=uHxz6bP4K8zgtQFrlWFwxrYfmqm5kXxsg6OYhAIUbAA,16173
|
|
55
|
+
kerykeion-5.0.0b1.dist-info/METADATA,sha256=RNXJbBmkMbDOdmp3tlKu2KPy_b0iYzlJ_t3g9ZGJnck,40219
|
|
56
|
+
kerykeion-5.0.0b1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
57
|
+
kerykeion-5.0.0b1.dist-info/licenses/LICENSE,sha256=UTLH8EdbAsgQei4PA2PnBCPGLSZkq5J-dhkyJuXgWQU,34273
|
|
58
|
+
kerykeion-5.0.0b1.dist-info/RECORD,,
|
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
This is part of Kerykeion (C) 2025 Giacomo Battaglia
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import logging
|
|
7
|
-
from typing import Union, List, Optional
|
|
8
|
-
|
|
9
|
-
from kerykeion.astrological_subject_factory import AstrologicalSubjectFactory
|
|
10
|
-
from kerykeion.aspects.aspects_utils import get_aspect_from_two_points, get_active_points_list
|
|
11
|
-
from kerykeion.kr_types.kr_models import AstrologicalSubjectModel, AspectModel, ActiveAspect, CompositeSubjectModel, PlanetReturnModel, NatalAspectsModel
|
|
12
|
-
from kerykeion.kr_types.kr_literals import AstrologicalPoint
|
|
13
|
-
from kerykeion.settings.config_constants import DEFAULT_ACTIVE_ASPECTS, DEFAULT_AXIS_ORBIT
|
|
14
|
-
from kerykeion.settings.legacy.legacy_celestial_points_settings import DEFAULT_CELESTIAL_POINTS_SETTINGS
|
|
15
|
-
from kerykeion.settings.legacy.legacy_chart_aspects_settings import DEFAULT_CHART_ASPECTS_SETTINGS
|
|
16
|
-
from kerykeion.utilities import find_common_active_points
|
|
17
|
-
|
|
18
|
-
# Axes constants for orb filtering
|
|
19
|
-
AXES_LIST = [
|
|
20
|
-
"Ascendant",
|
|
21
|
-
"Medium_Coeli",
|
|
22
|
-
"Descendant",
|
|
23
|
-
"Imum_Coeli",
|
|
24
|
-
]
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class NatalAspectsFactory:
|
|
28
|
-
"""
|
|
29
|
-
Factory class for creating natal aspects analysis.
|
|
30
|
-
|
|
31
|
-
This factory calculates all aspects in a birth chart and provides both
|
|
32
|
-
comprehensive and filtered aspect lists based on orb settings and relevance.
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
@staticmethod
|
|
36
|
-
def from_subject(
|
|
37
|
-
user: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
|
|
38
|
-
*,
|
|
39
|
-
active_points: Optional[List[AstrologicalPoint]] = None,
|
|
40
|
-
active_aspects: Optional[List[ActiveAspect]] = None,
|
|
41
|
-
) -> NatalAspectsModel:
|
|
42
|
-
"""
|
|
43
|
-
Create natal aspects analysis from an existing astrological subject.
|
|
44
|
-
|
|
45
|
-
Args:
|
|
46
|
-
user: The astrological subject for aspect calculation
|
|
47
|
-
|
|
48
|
-
Kwargs:
|
|
49
|
-
active_points: List of points to include in calculations
|
|
50
|
-
active_aspects: List of aspects with their orb settings
|
|
51
|
-
|
|
52
|
-
Returns:
|
|
53
|
-
NatalAspectsModel containing all calculated aspects data
|
|
54
|
-
"""
|
|
55
|
-
# Initialize settings and configurations
|
|
56
|
-
celestial_points = DEFAULT_CELESTIAL_POINTS_SETTINGS
|
|
57
|
-
aspects_settings = DEFAULT_CHART_ASPECTS_SETTINGS
|
|
58
|
-
axes_orbit_settings = DEFAULT_AXIS_ORBIT
|
|
59
|
-
|
|
60
|
-
# Set active aspects with default fallback
|
|
61
|
-
active_aspects_resolved = active_aspects if active_aspects is not None else DEFAULT_ACTIVE_ASPECTS
|
|
62
|
-
|
|
63
|
-
# Determine active points to use
|
|
64
|
-
if active_points is None:
|
|
65
|
-
active_points_resolved = user.active_points
|
|
66
|
-
else:
|
|
67
|
-
active_points_resolved = find_common_active_points(
|
|
68
|
-
user.active_points,
|
|
69
|
-
active_points,
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
return NatalAspectsFactory._create_natal_aspects_model(
|
|
73
|
-
user, active_points_resolved, active_aspects_resolved,
|
|
74
|
-
aspects_settings, axes_orbit_settings, celestial_points
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
@staticmethod
|
|
78
|
-
def _create_natal_aspects_model(
|
|
79
|
-
user: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
|
|
80
|
-
active_points_resolved: List[AstrologicalPoint],
|
|
81
|
-
active_aspects_resolved: List[ActiveAspect],
|
|
82
|
-
aspects_settings: List[dict],
|
|
83
|
-
axes_orbit_settings: float,
|
|
84
|
-
celestial_points: List[dict]
|
|
85
|
-
) -> NatalAspectsModel:
|
|
86
|
-
"""
|
|
87
|
-
Create the complete natal aspects model with all calculations.
|
|
88
|
-
|
|
89
|
-
Returns:
|
|
90
|
-
NatalAspectsModel containing all aspects data
|
|
91
|
-
"""
|
|
92
|
-
all_aspects = NatalAspectsFactory._calculate_all_aspects(
|
|
93
|
-
user, active_points_resolved, active_aspects_resolved, aspects_settings, celestial_points
|
|
94
|
-
)
|
|
95
|
-
relevant_aspects = NatalAspectsFactory._filter_relevant_aspects(all_aspects, axes_orbit_settings)
|
|
96
|
-
|
|
97
|
-
return NatalAspectsModel(
|
|
98
|
-
subject=user,
|
|
99
|
-
all_aspects=all_aspects,
|
|
100
|
-
relevant_aspects=relevant_aspects,
|
|
101
|
-
active_points=active_points_resolved,
|
|
102
|
-
active_aspects=active_aspects_resolved,
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
@staticmethod
|
|
106
|
-
def _calculate_all_aspects(
|
|
107
|
-
user: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
|
|
108
|
-
active_points: List[AstrologicalPoint],
|
|
109
|
-
active_aspects: List[ActiveAspect],
|
|
110
|
-
aspects_settings: List[dict],
|
|
111
|
-
celestial_points: List[dict]
|
|
112
|
-
) -> List[AspectModel]:
|
|
113
|
-
"""
|
|
114
|
-
Calculate all aspects between active points in the natal chart.
|
|
115
|
-
|
|
116
|
-
This method handles all aspect calculations including settings updates,
|
|
117
|
-
opposite pair filtering, and planet ID resolution in a single comprehensive method.
|
|
118
|
-
|
|
119
|
-
Returns:
|
|
120
|
-
List of all calculated AspectModel instances
|
|
121
|
-
"""
|
|
122
|
-
active_points_list = get_active_points_list(user, active_points)
|
|
123
|
-
|
|
124
|
-
# Update aspects settings with active aspects orbs
|
|
125
|
-
filtered_settings = []
|
|
126
|
-
for aspect_setting in aspects_settings:
|
|
127
|
-
for active_aspect in active_aspects:
|
|
128
|
-
if aspect_setting["name"] == active_aspect["name"]:
|
|
129
|
-
aspect_setting = aspect_setting.copy() # Don't modify original
|
|
130
|
-
aspect_setting["orb"] = active_aspect["orb"]
|
|
131
|
-
filtered_settings.append(aspect_setting)
|
|
132
|
-
break
|
|
133
|
-
|
|
134
|
-
# Define opposite pairs that should be skipped
|
|
135
|
-
opposite_pairs = {
|
|
136
|
-
("Ascendant", "Descendant"),
|
|
137
|
-
("Descendant", "Ascendant"),
|
|
138
|
-
("Medium_Coeli", "Imum_Coeli"),
|
|
139
|
-
("Imum_Coeli", "Medium_Coeli"),
|
|
140
|
-
("True_Node", "True_South_Node"),
|
|
141
|
-
("Mean_Node", "Mean_South_Node"),
|
|
142
|
-
("True_South_Node", "True_Node"),
|
|
143
|
-
("Mean_South_Node", "Mean_Node"),
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
all_aspects_list = []
|
|
147
|
-
|
|
148
|
-
for first in range(len(active_points_list)):
|
|
149
|
-
# Generate aspects list without repetitions
|
|
150
|
-
for second in range(first + 1, len(active_points_list)):
|
|
151
|
-
# Skip predefined opposite pairs (AC/DC, MC/IC, North/South nodes)
|
|
152
|
-
first_name = active_points_list[first]["name"]
|
|
153
|
-
second_name = active_points_list[second]["name"]
|
|
154
|
-
|
|
155
|
-
if (first_name, second_name) in opposite_pairs:
|
|
156
|
-
continue
|
|
157
|
-
|
|
158
|
-
aspect = get_aspect_from_two_points(
|
|
159
|
-
filtered_settings,
|
|
160
|
-
active_points_list[first]["abs_pos"],
|
|
161
|
-
active_points_list[second]["abs_pos"]
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
if aspect["verdict"]:
|
|
165
|
-
# Get planet IDs directly from celestial points settings
|
|
166
|
-
first_planet_id = 0
|
|
167
|
-
second_planet_id = 0
|
|
168
|
-
|
|
169
|
-
for planet in celestial_points:
|
|
170
|
-
if planet["name"] == first_name:
|
|
171
|
-
first_planet_id = planet["id"]
|
|
172
|
-
if planet["name"] == second_name:
|
|
173
|
-
second_planet_id = planet["id"]
|
|
174
|
-
|
|
175
|
-
aspect_model = AspectModel(
|
|
176
|
-
p1_name=first_name,
|
|
177
|
-
p1_owner=user.name,
|
|
178
|
-
p1_abs_pos=active_points_list[first]["abs_pos"],
|
|
179
|
-
p2_name=second_name,
|
|
180
|
-
p2_owner=user.name,
|
|
181
|
-
p2_abs_pos=active_points_list[second]["abs_pos"],
|
|
182
|
-
aspect=aspect["name"],
|
|
183
|
-
orbit=aspect["orbit"],
|
|
184
|
-
aspect_degrees=aspect["aspect_degrees"],
|
|
185
|
-
diff=aspect["diff"],
|
|
186
|
-
p1=first_planet_id,
|
|
187
|
-
p2=second_planet_id,
|
|
188
|
-
)
|
|
189
|
-
all_aspects_list.append(aspect_model)
|
|
190
|
-
|
|
191
|
-
return all_aspects_list
|
|
192
|
-
|
|
193
|
-
@staticmethod
|
|
194
|
-
def _filter_relevant_aspects(all_aspects: List[AspectModel], axes_orbit_settings: float) -> List[AspectModel]:
|
|
195
|
-
"""
|
|
196
|
-
Filter aspects based on orb thresholds for axes and other comprehensive criteria.
|
|
197
|
-
|
|
198
|
-
This method consolidates all filtering logic including axes checks and orb thresholds
|
|
199
|
-
into a single comprehensive filtering method.
|
|
200
|
-
|
|
201
|
-
Args:
|
|
202
|
-
all_aspects: Complete list of calculated aspects
|
|
203
|
-
axes_orbit_settings: Orb threshold for axes aspects
|
|
204
|
-
|
|
205
|
-
Returns:
|
|
206
|
-
Filtered list of relevant aspects
|
|
207
|
-
"""
|
|
208
|
-
logging.debug("Calculating relevant aspects by filtering orbs...")
|
|
209
|
-
|
|
210
|
-
relevant_aspects = []
|
|
211
|
-
|
|
212
|
-
for aspect in all_aspects:
|
|
213
|
-
# Check if aspect involves any of the chart axes and apply stricter orb limits
|
|
214
|
-
aspect_involves_axes = (aspect.p1_name in AXES_LIST or aspect.p2_name in AXES_LIST)
|
|
215
|
-
|
|
216
|
-
if aspect_involves_axes and abs(aspect.orbit) >= axes_orbit_settings:
|
|
217
|
-
continue
|
|
218
|
-
|
|
219
|
-
relevant_aspects.append(aspect)
|
|
220
|
-
|
|
221
|
-
return relevant_aspects
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if __name__ == "__main__":
|
|
225
|
-
from kerykeion.utilities import setup_logging
|
|
226
|
-
|
|
227
|
-
setup_logging(level="debug")
|
|
228
|
-
|
|
229
|
-
# Create subject using AstrologicalSubjectFactory
|
|
230
|
-
johnny = AstrologicalSubjectFactory.from_birth_data("Johnny Depp", 1963, 6, 9, 0, 0, city="Owensboro", nation="US")
|
|
231
|
-
|
|
232
|
-
# Create aspects analysis from subject
|
|
233
|
-
natal_aspects = NatalAspectsFactory.from_subject(johnny)
|
|
234
|
-
print(f"All aspects count: {len(natal_aspects.all_aspects)}")
|
|
235
|
-
print(f"Relevant aspects count: {len(natal_aspects.relevant_aspects)}")
|
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
This is part of Kerykeion (C) 2025 Giacomo Battaglia
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import logging
|
|
7
|
-
from typing import Union, List, Optional
|
|
8
|
-
|
|
9
|
-
from kerykeion.astrological_subject_factory import AstrologicalSubjectFactory
|
|
10
|
-
from kerykeion.aspects.aspects_utils import get_aspect_from_two_points, get_active_points_list
|
|
11
|
-
from kerykeion.kr_types.kr_models import AstrologicalSubjectModel, AspectModel, ActiveAspect, CompositeSubjectModel, PlanetReturnModel, SynastryAspectsModel
|
|
12
|
-
from kerykeion.settings.config_constants import DEFAULT_ACTIVE_ASPECTS, DEFAULT_AXIS_ORBIT
|
|
13
|
-
from kerykeion.settings.legacy.legacy_celestial_points_settings import DEFAULT_CELESTIAL_POINTS_SETTINGS
|
|
14
|
-
from kerykeion.settings.legacy.legacy_chart_aspects_settings import DEFAULT_CHART_ASPECTS_SETTINGS
|
|
15
|
-
from kerykeion.kr_types.kr_literals import AstrologicalPoint
|
|
16
|
-
from kerykeion.utilities import find_common_active_points
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
# Axes constants for orb filtering
|
|
20
|
-
AXES_LIST = [
|
|
21
|
-
"Ascendant",
|
|
22
|
-
"Medium_Coeli",
|
|
23
|
-
"Descendant",
|
|
24
|
-
"Imum_Coeli",
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class SynastryAspectsFactory:
|
|
29
|
-
"""
|
|
30
|
-
Factory class for creating synastry aspects analysis between two astrological subjects.
|
|
31
|
-
|
|
32
|
-
This factory calculates all astrological aspects (angular relationships) between
|
|
33
|
-
planets and points in two different charts. It's primarily used for relationship
|
|
34
|
-
compatibility analysis, transit calculations, and comparative astrology.
|
|
35
|
-
|
|
36
|
-
The factory provides both comprehensive aspect lists and filtered relevant aspects
|
|
37
|
-
based on orb settings and chart axes considerations.
|
|
38
|
-
|
|
39
|
-
Key Features:
|
|
40
|
-
- Calculates all aspects between two subjects
|
|
41
|
-
- Filters aspects based on orb thresholds
|
|
42
|
-
- Applies stricter orb limits for chart axes (ASC, MC, DSC, IC)
|
|
43
|
-
- Supports multiple subject types (natal, composite, planetary returns)
|
|
44
|
-
|
|
45
|
-
Example:
|
|
46
|
-
>>> john = AstrologicalSubjectFactory.from_birth_data("John", 1990, 1, 1, 12, 0, "London", "GB")
|
|
47
|
-
>>> jane = AstrologicalSubjectFactory.from_birth_data("Jane", 1992, 6, 15, 14, 30, "Paris", "FR")
|
|
48
|
-
>>> synastry = SynastryAspectsFactory.from_subjects(john, jane)
|
|
49
|
-
>>> print(f"Found {len(synastry.relevant_aspects)} relevant aspects")
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
@staticmethod
|
|
53
|
-
def from_subjects(
|
|
54
|
-
first_subject: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
|
|
55
|
-
second_subject: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
|
|
56
|
-
*,
|
|
57
|
-
active_points: Optional[List[AstrologicalPoint]] = None,
|
|
58
|
-
active_aspects: Optional[List[ActiveAspect]] = None,
|
|
59
|
-
) -> SynastryAspectsModel:
|
|
60
|
-
"""
|
|
61
|
-
Create synastry aspects analysis between two astrological subjects.
|
|
62
|
-
|
|
63
|
-
This method calculates all astrological aspects (angular relationships)
|
|
64
|
-
between planets and points in two different birth charts, commonly used
|
|
65
|
-
for relationship compatibility analysis.
|
|
66
|
-
|
|
67
|
-
Args:
|
|
68
|
-
first_subject: The first astrological subject (person, composite chart, or planetary return)
|
|
69
|
-
second_subject: The second astrological subject to compare with the first
|
|
70
|
-
active_points: Optional list of celestial points to include in calculations.
|
|
71
|
-
If None, uses common points between both subjects.
|
|
72
|
-
active_aspects: Optional list of aspect types with their orb settings.
|
|
73
|
-
If None, uses default aspect configuration.
|
|
74
|
-
|
|
75
|
-
Returns:
|
|
76
|
-
SynastryAspectsModel: Complete model containing all calculated aspects data,
|
|
77
|
-
including both comprehensive and filtered relevant aspects.
|
|
78
|
-
|
|
79
|
-
Example:
|
|
80
|
-
>>> john = AstrologicalSubjectFactory.from_birth_data("John", 1990, 1, 1, 12, 0, "London", "GB")
|
|
81
|
-
>>> jane = AstrologicalSubjectFactory.from_birth_data("Jane", 1992, 6, 15, 14, 30, "Paris", "FR")
|
|
82
|
-
>>> synastry = SynastryAspectsFactory.from_subjects(john, jane)
|
|
83
|
-
>>> print(f"Found {len(synastry.relevant_aspects)} relevant aspects")
|
|
84
|
-
"""
|
|
85
|
-
# Initialize settings and configurations
|
|
86
|
-
celestial_points = DEFAULT_CELESTIAL_POINTS_SETTINGS
|
|
87
|
-
aspects_settings = DEFAULT_CHART_ASPECTS_SETTINGS
|
|
88
|
-
axes_orbit_settings = DEFAULT_AXIS_ORBIT
|
|
89
|
-
|
|
90
|
-
# Set active aspects with default fallback
|
|
91
|
-
active_aspects_resolved = active_aspects if active_aspects is not None else DEFAULT_ACTIVE_ASPECTS
|
|
92
|
-
|
|
93
|
-
# Determine active points to use - find common points between both subjects
|
|
94
|
-
if active_points is None:
|
|
95
|
-
active_points_resolved = first_subject.active_points
|
|
96
|
-
else:
|
|
97
|
-
active_points_resolved = find_common_active_points(
|
|
98
|
-
first_subject.active_points,
|
|
99
|
-
active_points,
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
# Further filter with second subject's active points
|
|
103
|
-
active_points_resolved = find_common_active_points(
|
|
104
|
-
second_subject.active_points,
|
|
105
|
-
active_points_resolved,
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
return SynastryAspectsFactory._create_synastry_aspects_model(
|
|
109
|
-
first_subject, second_subject, active_points_resolved, active_aspects_resolved,
|
|
110
|
-
aspects_settings, axes_orbit_settings, celestial_points
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
@staticmethod
|
|
114
|
-
def _create_synastry_aspects_model(
|
|
115
|
-
first_subject: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
|
|
116
|
-
second_subject: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
|
|
117
|
-
active_points_resolved: List[AstrologicalPoint],
|
|
118
|
-
active_aspects_resolved: List[ActiveAspect],
|
|
119
|
-
aspects_settings: List[dict],
|
|
120
|
-
axes_orbit_settings: float,
|
|
121
|
-
celestial_points: List[dict]
|
|
122
|
-
) -> SynastryAspectsModel:
|
|
123
|
-
"""
|
|
124
|
-
Create the complete synastry aspects model with all calculations.
|
|
125
|
-
|
|
126
|
-
Args:
|
|
127
|
-
first_subject: First astrological subject
|
|
128
|
-
second_subject: Second astrological subject
|
|
129
|
-
active_points_resolved: Resolved list of active celestial points
|
|
130
|
-
active_aspects_resolved: Resolved list of active aspects with orbs
|
|
131
|
-
aspects_settings: Chart aspect configuration settings
|
|
132
|
-
axes_orbit_settings: Orb threshold for chart axes
|
|
133
|
-
celestial_points: Celestial points configuration
|
|
134
|
-
|
|
135
|
-
Returns:
|
|
136
|
-
SynastryAspectsModel: Complete model containing all aspects data
|
|
137
|
-
"""
|
|
138
|
-
all_aspects = SynastryAspectsFactory._calculate_all_aspects(
|
|
139
|
-
first_subject, second_subject, active_points_resolved, active_aspects_resolved,
|
|
140
|
-
aspects_settings, celestial_points
|
|
141
|
-
)
|
|
142
|
-
relevant_aspects = SynastryAspectsFactory._filter_relevant_aspects(all_aspects, axes_orbit_settings)
|
|
143
|
-
|
|
144
|
-
return SynastryAspectsModel(
|
|
145
|
-
first_subject=first_subject,
|
|
146
|
-
second_subject=second_subject,
|
|
147
|
-
all_aspects=all_aspects,
|
|
148
|
-
relevant_aspects=relevant_aspects,
|
|
149
|
-
active_points=active_points_resolved,
|
|
150
|
-
active_aspects=active_aspects_resolved,
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
@staticmethod
|
|
154
|
-
def _calculate_all_aspects(
|
|
155
|
-
first_subject: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
|
|
156
|
-
second_subject: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
|
|
157
|
-
active_points: List[AstrologicalPoint],
|
|
158
|
-
active_aspects: List[ActiveAspect],
|
|
159
|
-
aspects_settings: List[dict],
|
|
160
|
-
celestial_points: List[dict]
|
|
161
|
-
) -> List[AspectModel]:
|
|
162
|
-
"""
|
|
163
|
-
Calculate all synastry aspects between two subjects.
|
|
164
|
-
|
|
165
|
-
This method performs comprehensive aspect calculations between all active points
|
|
166
|
-
of both subjects, applying the specified orb settings and creating detailed
|
|
167
|
-
aspect models with planet IDs and positional information.
|
|
168
|
-
|
|
169
|
-
Args:
|
|
170
|
-
first_subject: First astrological subject
|
|
171
|
-
second_subject: Second astrological subject
|
|
172
|
-
active_points: List of celestial points to include in calculations
|
|
173
|
-
active_aspects: List of aspect types with their orb settings
|
|
174
|
-
aspects_settings: Base aspect configuration settings
|
|
175
|
-
celestial_points: Celestial points configuration with IDs
|
|
176
|
-
|
|
177
|
-
Returns:
|
|
178
|
-
List[AspectModel]: Complete list of all calculated aspect instances
|
|
179
|
-
"""
|
|
180
|
-
# Get active points lists for both subjects
|
|
181
|
-
first_active_points_list = get_active_points_list(first_subject, active_points)
|
|
182
|
-
second_active_points_list = get_active_points_list(second_subject, active_points)
|
|
183
|
-
|
|
184
|
-
# Create a lookup dictionary for planet IDs to optimize performance
|
|
185
|
-
planet_id_lookup = {planet["name"]: planet["id"] for planet in celestial_points}
|
|
186
|
-
|
|
187
|
-
# Update aspects settings with active aspects orbs
|
|
188
|
-
filtered_settings = []
|
|
189
|
-
for aspect_setting in aspects_settings:
|
|
190
|
-
for active_aspect in active_aspects:
|
|
191
|
-
if aspect_setting["name"] == active_aspect["name"]:
|
|
192
|
-
aspect_setting = aspect_setting.copy() # Don't modify original
|
|
193
|
-
aspect_setting["orb"] = active_aspect["orb"]
|
|
194
|
-
filtered_settings.append(aspect_setting)
|
|
195
|
-
break
|
|
196
|
-
|
|
197
|
-
all_aspects_list = []
|
|
198
|
-
for first in range(len(first_active_points_list)):
|
|
199
|
-
# Generate aspects list between all points of first and second subjects
|
|
200
|
-
for second in range(len(second_active_points_list)):
|
|
201
|
-
aspect = get_aspect_from_two_points(
|
|
202
|
-
filtered_settings,
|
|
203
|
-
first_active_points_list[first]["abs_pos"],
|
|
204
|
-
second_active_points_list[second]["abs_pos"],
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
if aspect["verdict"]:
|
|
208
|
-
first_name = first_active_points_list[first]["name"]
|
|
209
|
-
second_name = second_active_points_list[second]["name"]
|
|
210
|
-
|
|
211
|
-
# Get planet IDs using lookup dictionary for better performance
|
|
212
|
-
first_planet_id = planet_id_lookup.get(first_name, 0)
|
|
213
|
-
second_planet_id = planet_id_lookup.get(second_name, 0)
|
|
214
|
-
|
|
215
|
-
aspect_model = AspectModel(
|
|
216
|
-
p1_name=first_name,
|
|
217
|
-
p1_owner=first_subject.name,
|
|
218
|
-
p1_abs_pos=first_active_points_list[first]["abs_pos"],
|
|
219
|
-
p2_name=second_name,
|
|
220
|
-
p2_owner=second_subject.name,
|
|
221
|
-
p2_abs_pos=second_active_points_list[second]["abs_pos"],
|
|
222
|
-
aspect=aspect["name"],
|
|
223
|
-
orbit=aspect["orbit"],
|
|
224
|
-
aspect_degrees=aspect["aspect_degrees"],
|
|
225
|
-
diff=aspect["diff"],
|
|
226
|
-
p1=first_planet_id,
|
|
227
|
-
p2=second_planet_id,
|
|
228
|
-
)
|
|
229
|
-
all_aspects_list.append(aspect_model)
|
|
230
|
-
|
|
231
|
-
return all_aspects_list
|
|
232
|
-
|
|
233
|
-
@staticmethod
|
|
234
|
-
def _filter_relevant_aspects(all_aspects: List[AspectModel], axes_orbit_settings: float) -> List[AspectModel]:
|
|
235
|
-
"""
|
|
236
|
-
Filter aspects based on orb thresholds for axes and comprehensive criteria.
|
|
237
|
-
|
|
238
|
-
This method consolidates all filtering logic including axes checks and orb thresholds
|
|
239
|
-
for synastry aspects in a single comprehensive filtering method.
|
|
240
|
-
|
|
241
|
-
Args:
|
|
242
|
-
all_aspects: Complete list of calculated aspects
|
|
243
|
-
axes_orbit_settings: Orb threshold for axes aspects
|
|
244
|
-
|
|
245
|
-
Returns:
|
|
246
|
-
Filtered list of relevant aspects
|
|
247
|
-
"""
|
|
248
|
-
logging.debug("Calculating relevant synastry aspects by filtering orbs...")
|
|
249
|
-
|
|
250
|
-
relevant_aspects = []
|
|
251
|
-
|
|
252
|
-
for aspect in all_aspects:
|
|
253
|
-
# Check if aspect involves any of the chart axes and apply stricter orb limits
|
|
254
|
-
aspect_involves_axes = (aspect.p1_name in AXES_LIST or aspect.p2_name in AXES_LIST)
|
|
255
|
-
|
|
256
|
-
if aspect_involves_axes and abs(aspect.orbit) >= axes_orbit_settings:
|
|
257
|
-
continue
|
|
258
|
-
|
|
259
|
-
relevant_aspects.append(aspect)
|
|
260
|
-
|
|
261
|
-
return relevant_aspects
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if __name__ == "__main__":
|
|
265
|
-
from kerykeion.utilities import setup_logging
|
|
266
|
-
|
|
267
|
-
setup_logging(level="debug")
|
|
268
|
-
|
|
269
|
-
john = AstrologicalSubjectFactory.from_birth_data("John", 1940, 10, 9, 10, 30, "Liverpool", "GB")
|
|
270
|
-
yoko = AstrologicalSubjectFactory.from_birth_data("Yoko", 1933, 2, 18, 10, 30, "Tokyo", "JP")
|
|
271
|
-
|
|
272
|
-
# Create synastry aspects analysis using the factory
|
|
273
|
-
synastry_aspects_model = SynastryAspectsFactory.from_subjects(john, yoko)
|
|
274
|
-
print(f"All synastry aspects: {len(synastry_aspects_model.all_aspects)}")
|
|
275
|
-
print(f"Relevant synastry aspects: {len(synastry_aspects_model.relevant_aspects)}")
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
from kerykeion.kr_types import SubscriptableBaseModel
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class PointInHouseModel(SubscriptableBaseModel):
|
|
6
|
-
"""Represents a point from one chart positioned in a house from another chart"""
|
|
7
|
-
|
|
8
|
-
point_name: str
|
|
9
|
-
"""Name of the celestial point"""
|
|
10
|
-
point_degree: float
|
|
11
|
-
"""Degree of the celestial point"""
|
|
12
|
-
point_sign: str
|
|
13
|
-
"""Sign of the celestial point"""
|
|
14
|
-
point_owner_name: str
|
|
15
|
-
"""Name of the owner of the celestial point"""
|
|
16
|
-
point_owner_house_number: Optional[int]
|
|
17
|
-
"""House number of the point of the owner of the celestial point"""
|
|
18
|
-
point_owner_house_name: Optional[str]
|
|
19
|
-
"""House name of the point of the owner of the celestial point"""
|
|
20
|
-
projected_house_number: int
|
|
21
|
-
"""Number of the house where the point is projected"""
|
|
22
|
-
projected_house_name: str
|
|
23
|
-
"""Name of the house where the point is projected"""
|
|
24
|
-
projected_house_owner_name: str
|
|
25
|
-
"""Name of the owner of the house where the point is projected"""
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class HouseComparisonModel(SubscriptableBaseModel):
|
|
29
|
-
"""Pydantic model for comparing points in houses between two astrological subjects"""
|
|
30
|
-
|
|
31
|
-
first_subject_name: str
|
|
32
|
-
"""Name of the first subject"""
|
|
33
|
-
second_subject_name: str
|
|
34
|
-
"""Name of the second subject"""
|
|
35
|
-
first_points_in_second_houses: list[PointInHouseModel]
|
|
36
|
-
"""List of points from the first subject in the houses of the second subject"""
|
|
37
|
-
second_points_in_first_houses: list[PointInHouseModel]
|
|
38
|
-
"""List of points from the second subject in the houses of the first subject"""
|