kerykeion 3.1.1__py3-none-any.whl → 5.1.9__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 +58 -141
- kerykeion/aspects/__init__.py +14 -0
- kerykeion/aspects/aspects_factory.py +568 -0
- kerykeion/aspects/aspects_utils.py +164 -0
- kerykeion/astrological_subject_factory.py +1901 -0
- kerykeion/backword.py +820 -0
- kerykeion/chart_data_factory.py +552 -0
- kerykeion/charts/__init__.py +5 -0
- kerykeion/charts/chart_drawer.py +2794 -0
- kerykeion/charts/charts_utils.py +1840 -0
- kerykeion/charts/draw_planets.py +658 -0
- kerykeion/charts/templates/aspect_grid_only.xml +596 -0
- kerykeion/charts/templates/chart.xml +741 -0
- kerykeion/charts/templates/wheel_only.xml +653 -0
- kerykeion/charts/themes/black-and-white.css +148 -0
- kerykeion/charts/themes/classic.css +113 -0
- kerykeion/charts/themes/dark-high-contrast.css +159 -0
- kerykeion/charts/themes/dark.css +160 -0
- kerykeion/charts/themes/light.css +160 -0
- kerykeion/charts/themes/strawberry.css +158 -0
- kerykeion/composite_subject_factory.py +408 -0
- kerykeion/ephemeris_data_factory.py +443 -0
- kerykeion/fetch_geonames.py +105 -61
- kerykeion/house_comparison/__init__.py +6 -0
- kerykeion/house_comparison/house_comparison_factory.py +103 -0
- kerykeion/house_comparison/house_comparison_utils.py +126 -0
- kerykeion/kr_types/__init__.py +70 -0
- kerykeion/kr_types/chart_template_model.py +20 -0
- kerykeion/kr_types/kerykeion_exception.py +20 -0
- kerykeion/kr_types/kr_literals.py +20 -0
- kerykeion/kr_types/kr_models.py +20 -0
- kerykeion/kr_types/settings_models.py +20 -0
- kerykeion/planetary_return_factory.py +805 -0
- kerykeion/relationship_score_factory.py +301 -0
- kerykeion/report.py +779 -0
- kerykeion/schemas/__init__.py +106 -0
- kerykeion/schemas/chart_template_model.py +367 -0
- kerykeion/schemas/kerykeion_exception.py +20 -0
- kerykeion/schemas/kr_literals.py +181 -0
- kerykeion/schemas/kr_models.py +603 -0
- kerykeion/schemas/settings_models.py +188 -0
- kerykeion/settings/__init__.py +20 -0
- kerykeion/settings/chart_defaults.py +444 -0
- kerykeion/settings/config_constants.py +152 -0
- kerykeion/settings/kerykeion_settings.py +51 -0
- kerykeion/settings/translation_strings.py +1499 -0
- kerykeion/settings/translations.py +74 -0
- kerykeion/sweph/README.md +3 -0
- 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/seas_18.se1 +0 -0
- kerykeion/sweph/sefstars.txt +1602 -0
- kerykeion/transits_time_range_factory.py +302 -0
- kerykeion/utilities.py +762 -130
- kerykeion-5.1.9.dist-info/METADATA +1793 -0
- kerykeion-5.1.9.dist-info/RECORD +63 -0
- {kerykeion-3.1.1.dist-info → kerykeion-5.1.9.dist-info}/WHEEL +1 -2
- kerykeion-5.1.9.dist-info/licenses/LICENSE +661 -0
- kerykeion/aspects.py +0 -331
- kerykeion/charts/charts_svg.py +0 -1607
- kerykeion/charts/templates/basic.xml +0 -285
- kerykeion/charts/templates/extended.xml +0 -294
- kerykeion/kr.config.json +0 -464
- kerykeion/main.py +0 -595
- kerykeion/print_all_data.py +0 -44
- kerykeion/relationship_score.py +0 -219
- kerykeion/types.py +0 -190
- kerykeion-3.1.1.dist-info/METADATA +0 -204
- kerykeion-3.1.1.dist-info/RECORD +0 -17
- kerykeion-3.1.1.dist-info/top_level.txt +0 -1
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Relationship Score Factory Module
|
|
4
|
+
|
|
5
|
+
This module calculates relationship scores between two astrological subjects using the
|
|
6
|
+
Ciro Discepolo method. It analyzes synastry aspects to generate numerical compatibility
|
|
7
|
+
scores with descriptive categories.
|
|
8
|
+
|
|
9
|
+
Key Features:
|
|
10
|
+
- Point-based scoring system using synastry aspects
|
|
11
|
+
- Configurable major/minor aspect filtering
|
|
12
|
+
- Orbital precision weighting
|
|
13
|
+
- Categorical score descriptions
|
|
14
|
+
|
|
15
|
+
Score Categories:
|
|
16
|
+
- 0-5: Minimal relationship
|
|
17
|
+
- 5-10: Medium relationship
|
|
18
|
+
- 10-15: Important relationship
|
|
19
|
+
- 15-20: Very important relationship
|
|
20
|
+
- 20-30: Exceptional relationship
|
|
21
|
+
- 30+: Rare exceptional relationship
|
|
22
|
+
|
|
23
|
+
Classes:
|
|
24
|
+
RelationshipScoreFactory: Main factory for calculating relationship scores
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
>>> from kerykeion import AstrologicalSubjectFactory
|
|
28
|
+
>>> from kerykeion.relationship_score_factory import RelationshipScoreFactory
|
|
29
|
+
>>>
|
|
30
|
+
>>> person1 = AstrologicalSubjectFactory.from_birth_data("John", 1990, 5, 15, 12, 0, "New York", "US")
|
|
31
|
+
>>> person2 = AstrologicalSubjectFactory.from_birth_data("Jane", 1988, 8, 22, 14, 30, "London", "GB")
|
|
32
|
+
>>> factory = RelationshipScoreFactory(person1, person2)
|
|
33
|
+
>>> score = factory.get_relationship_score()
|
|
34
|
+
>>> print(f"Score: {score.score_value} ({score.score_description})")
|
|
35
|
+
|
|
36
|
+
Reference:
|
|
37
|
+
Ciro Discepolo Method: http://www.cirodiscepolo.it/Articoli/Discepoloele.htm
|
|
38
|
+
|
|
39
|
+
Author: Giacomo Battaglia
|
|
40
|
+
Copyright: (C) 2025 Kerykeion Project
|
|
41
|
+
License: AGPL-3.0
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
import logging
|
|
45
|
+
from typing import Optional
|
|
46
|
+
|
|
47
|
+
from kerykeion import AstrologicalSubjectFactory
|
|
48
|
+
from kerykeion.aspects import AspectsFactory
|
|
49
|
+
from kerykeion.schemas.kr_models import AstrologicalSubjectModel, RelationshipScoreAspectModel, RelationshipScoreModel
|
|
50
|
+
from kerykeion.schemas.kr_literals import RelationshipScoreDescription
|
|
51
|
+
|
|
52
|
+
# Scoring constants
|
|
53
|
+
DESTINY_SIGN_POINTS = 5
|
|
54
|
+
HIGH_PRECISION_ORBIT_THRESHOLD = 2
|
|
55
|
+
MAJOR_ASPECT_POINTS_HIGH_PRECISION = 11
|
|
56
|
+
MAJOR_ASPECT_POINTS_STANDARD = 8
|
|
57
|
+
MINOR_ASPECT_POINTS = 4
|
|
58
|
+
SUN_ASCENDANT_ASPECT_POINTS = 4
|
|
59
|
+
MOON_ASCENDANT_ASPECT_POINTS = 4
|
|
60
|
+
VENUS_MARS_ASPECT_POINTS = 4
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class RelationshipScoreFactory:
|
|
64
|
+
"""
|
|
65
|
+
Calculates relationship scores between two subjects using the Ciro Discepolo method.
|
|
66
|
+
|
|
67
|
+
The scoring system evaluates synastry aspects between planetary positions to generate
|
|
68
|
+
numerical compatibility scores with categorical descriptions.
|
|
69
|
+
|
|
70
|
+
Score Ranges:
|
|
71
|
+
- 0-5: Minimal relationship
|
|
72
|
+
- 5-10: Medium relationship
|
|
73
|
+
- 10-15: Important relationship
|
|
74
|
+
- 15-20: Very important relationship
|
|
75
|
+
- 20-30: Exceptional relationship
|
|
76
|
+
- 30+: Rare exceptional relationship
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
first_subject (AstrologicalSubjectModel): First astrological subject
|
|
80
|
+
second_subject (AstrologicalSubjectModel): Second astrological subject
|
|
81
|
+
use_only_major_aspects (bool, optional): Filter to major aspects only. Defaults to True.
|
|
82
|
+
axis_orb_limit (float | None, optional): Optional orb threshold for chart axes
|
|
83
|
+
filtering during aspect calculation.
|
|
84
|
+
|
|
85
|
+
Reference:
|
|
86
|
+
http://www.cirodiscepolo.it/Articoli/Discepoloele.htm
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
SCORE_MAPPING = [
|
|
90
|
+
("Minimal", 5),
|
|
91
|
+
("Medium", 10),
|
|
92
|
+
("Important", 15),
|
|
93
|
+
("Very Important", 20),
|
|
94
|
+
("Exceptional", 30),
|
|
95
|
+
("Rare Exceptional", float("inf")),
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
MAJOR_ASPECTS = {"conjunction", "opposition", "square", "trine", "sextile"}
|
|
99
|
+
|
|
100
|
+
def __init__(
|
|
101
|
+
self,
|
|
102
|
+
first_subject: AstrologicalSubjectModel,
|
|
103
|
+
second_subject: AstrologicalSubjectModel,
|
|
104
|
+
use_only_major_aspects: bool = True,
|
|
105
|
+
*,
|
|
106
|
+
axis_orb_limit: Optional[float] = None,
|
|
107
|
+
):
|
|
108
|
+
self.use_only_major_aspects = use_only_major_aspects
|
|
109
|
+
self.first_subject: AstrologicalSubjectModel = first_subject
|
|
110
|
+
self.second_subject: AstrologicalSubjectModel = second_subject
|
|
111
|
+
|
|
112
|
+
self.score_value = 0
|
|
113
|
+
self.relationship_score_description: RelationshipScoreDescription = "Minimal"
|
|
114
|
+
self.is_destiny_sign = False
|
|
115
|
+
self.relationship_score_aspects: list[RelationshipScoreAspectModel] = []
|
|
116
|
+
self._synastry_aspects = AspectsFactory.dual_chart_aspects(
|
|
117
|
+
self.first_subject,
|
|
118
|
+
self.second_subject,
|
|
119
|
+
axis_orb_limit=axis_orb_limit,
|
|
120
|
+
).aspects
|
|
121
|
+
|
|
122
|
+
def _evaluate_destiny_sign(self):
|
|
123
|
+
"""
|
|
124
|
+
Checks if subjects share the same sun sign quality and adds points.
|
|
125
|
+
|
|
126
|
+
Adds 5 points if both subjects have sun signs with matching quality
|
|
127
|
+
(cardinal, fixed, or mutable).
|
|
128
|
+
"""
|
|
129
|
+
if self.first_subject.sun["quality"] == self.second_subject.sun["quality"]: # type: ignore
|
|
130
|
+
self.is_destiny_sign = True
|
|
131
|
+
self.score_value += DESTINY_SIGN_POINTS
|
|
132
|
+
logging.debug(f"Destiny sign found, adding {DESTINY_SIGN_POINTS} points, total score: {self.score_value}")
|
|
133
|
+
|
|
134
|
+
def _evaluate_aspect(self, aspect, points):
|
|
135
|
+
"""
|
|
136
|
+
Processes an aspect and adds points to the total score.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
aspect (dict): Aspect data containing planetary positions and geometry
|
|
140
|
+
points (int): Points to add to the total score
|
|
141
|
+
"""
|
|
142
|
+
if self.use_only_major_aspects and aspect["aspect"] not in self.MAJOR_ASPECTS:
|
|
143
|
+
return
|
|
144
|
+
|
|
145
|
+
self.score_value += points
|
|
146
|
+
self.relationship_score_aspects.append(
|
|
147
|
+
RelationshipScoreAspectModel(
|
|
148
|
+
p1_name=aspect["p1_name"],
|
|
149
|
+
p2_name=aspect["p2_name"],
|
|
150
|
+
aspect=aspect["aspect"],
|
|
151
|
+
orbit=aspect["orbit"],
|
|
152
|
+
)
|
|
153
|
+
)
|
|
154
|
+
logging.debug(f"{aspect['p1_name']}-{aspect['p2_name']} aspect: {aspect['aspect']} with orbit {aspect['orbit']} degrees, adding {points} points, total score: {self.score_value}, total aspects: {len(self.relationship_score_aspects)}")
|
|
155
|
+
|
|
156
|
+
def _evaluate_sun_sun_main_aspect(self, aspect):
|
|
157
|
+
"""
|
|
158
|
+
Evaluates Sun-Sun conjunction, opposition, or square aspects.
|
|
159
|
+
|
|
160
|
+
Adds 8 points for standard orbs, 11 points for tight orbs (≤2°).
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
aspect (dict): Aspect data
|
|
164
|
+
"""
|
|
165
|
+
if aspect["p1_name"] == "Sun" and aspect["p2_name"] == "Sun" and aspect["aspect"] in {"conjunction", "opposition", "square"}:
|
|
166
|
+
points = MAJOR_ASPECT_POINTS_HIGH_PRECISION if aspect["orbit"] <= HIGH_PRECISION_ORBIT_THRESHOLD else MAJOR_ASPECT_POINTS_STANDARD
|
|
167
|
+
self._evaluate_aspect(aspect, points)
|
|
168
|
+
|
|
169
|
+
def _evaluate_sun_moon_conjunction(self, aspect):
|
|
170
|
+
"""
|
|
171
|
+
Evaluates Sun-Moon conjunction aspects.
|
|
172
|
+
|
|
173
|
+
Adds 8 points for standard orbs, 11 points for tight orbs (≤2°).
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
aspect (dict): Aspect data
|
|
177
|
+
"""
|
|
178
|
+
if {aspect["p1_name"], aspect["p2_name"]} == {"Moon", "Sun"} and aspect["aspect"] == "conjunction":
|
|
179
|
+
points = MAJOR_ASPECT_POINTS_HIGH_PRECISION if aspect["orbit"] <= HIGH_PRECISION_ORBIT_THRESHOLD else MAJOR_ASPECT_POINTS_STANDARD
|
|
180
|
+
self._evaluate_aspect(aspect, points)
|
|
181
|
+
|
|
182
|
+
def _evaluate_sun_sun_other_aspects(self, aspect):
|
|
183
|
+
"""
|
|
184
|
+
Evaluates Sun-Sun aspects other than conjunction, opposition, or square.
|
|
185
|
+
|
|
186
|
+
Adds 4 points for any qualifying aspect.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
aspect (dict): Aspect data
|
|
190
|
+
"""
|
|
191
|
+
if aspect["p1_name"] == "Sun" and aspect["p2_name"] == "Sun" and aspect["aspect"] not in {"conjunction", "opposition", "square"}:
|
|
192
|
+
points = MINOR_ASPECT_POINTS
|
|
193
|
+
self._evaluate_aspect(aspect, points)
|
|
194
|
+
|
|
195
|
+
def _evaluate_sun_moon_other_aspects(self, aspect):
|
|
196
|
+
"""
|
|
197
|
+
Evaluates Sun-Moon aspects other than conjunctions.
|
|
198
|
+
|
|
199
|
+
Adds 4 points for any qualifying aspect.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
aspect (dict): Aspect data
|
|
203
|
+
"""
|
|
204
|
+
if {aspect["p1_name"], aspect["p2_name"]} == {"Moon", "Sun"} and aspect["aspect"] != "conjunction":
|
|
205
|
+
points = MINOR_ASPECT_POINTS
|
|
206
|
+
self._evaluate_aspect(aspect, points)
|
|
207
|
+
|
|
208
|
+
def _evaluate_sun_ascendant_aspect(self, aspect):
|
|
209
|
+
"""
|
|
210
|
+
Evaluates Sun-Ascendant aspects.
|
|
211
|
+
|
|
212
|
+
Adds 4 points for any aspect between Sun and Ascendant.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
aspect (dict): Aspect data
|
|
216
|
+
"""
|
|
217
|
+
if {aspect["p1_name"], aspect["p2_name"]} == {"Sun", "Ascendant"}:
|
|
218
|
+
points = SUN_ASCENDANT_ASPECT_POINTS
|
|
219
|
+
self._evaluate_aspect(aspect, points)
|
|
220
|
+
|
|
221
|
+
def _evaluate_moon_ascendant_aspect(self, aspect):
|
|
222
|
+
"""
|
|
223
|
+
Evaluates Moon-Ascendant aspects.
|
|
224
|
+
|
|
225
|
+
Adds 4 points for any aspect between Moon and Ascendant.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
aspect (dict): Aspect data
|
|
229
|
+
"""
|
|
230
|
+
if {aspect["p1_name"], aspect["p2_name"]} == {"Moon", "Ascendant"}:
|
|
231
|
+
points = MOON_ASCENDANT_ASPECT_POINTS
|
|
232
|
+
self._evaluate_aspect(aspect, points)
|
|
233
|
+
|
|
234
|
+
def _evaluate_venus_mars_aspect(self, aspect):
|
|
235
|
+
"""
|
|
236
|
+
Evaluates Venus-Mars aspects.
|
|
237
|
+
|
|
238
|
+
Adds 4 points for any aspect between Venus and Mars.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
aspect (dict): Aspect data
|
|
242
|
+
"""
|
|
243
|
+
if {aspect["p1_name"], aspect["p2_name"]} == {"Venus", "Mars"}:
|
|
244
|
+
points = VENUS_MARS_ASPECT_POINTS
|
|
245
|
+
self._evaluate_aspect(aspect, points)
|
|
246
|
+
|
|
247
|
+
def _evaluate_relationship_score_description(self):
|
|
248
|
+
"""
|
|
249
|
+
Determines the categorical description based on the numerical score.
|
|
250
|
+
|
|
251
|
+
Maps the total score to predefined description ranges.
|
|
252
|
+
"""
|
|
253
|
+
for description, threshold in self.SCORE_MAPPING:
|
|
254
|
+
if self.score_value < threshold:
|
|
255
|
+
self.relationship_score_description = description
|
|
256
|
+
break
|
|
257
|
+
|
|
258
|
+
def get_relationship_score(self):
|
|
259
|
+
"""
|
|
260
|
+
Calculates the complete relationship score using all evaluation methods.
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
RelationshipScoreModel: Score object containing numerical value, description,
|
|
264
|
+
destiny sign status, contributing aspects, and subject data.
|
|
265
|
+
"""
|
|
266
|
+
self._evaluate_destiny_sign()
|
|
267
|
+
|
|
268
|
+
for aspect in self._synastry_aspects:
|
|
269
|
+
self._evaluate_sun_sun_main_aspect(aspect)
|
|
270
|
+
self._evaluate_sun_moon_conjunction(aspect)
|
|
271
|
+
self._evaluate_sun_moon_other_aspects(aspect)
|
|
272
|
+
self._evaluate_sun_sun_other_aspects(aspect)
|
|
273
|
+
self._evaluate_sun_ascendant_aspect(aspect)
|
|
274
|
+
self._evaluate_moon_ascendant_aspect(aspect)
|
|
275
|
+
self._evaluate_venus_mars_aspect(aspect)
|
|
276
|
+
|
|
277
|
+
self._evaluate_relationship_score_description()
|
|
278
|
+
|
|
279
|
+
return RelationshipScoreModel(
|
|
280
|
+
score_value=self.score_value,
|
|
281
|
+
score_description=self.relationship_score_description,
|
|
282
|
+
is_destiny_sign=self.is_destiny_sign,
|
|
283
|
+
aspects=self.relationship_score_aspects,
|
|
284
|
+
subjects=[self.first_subject, self.second_subject],
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
if __name__ == "__main__":
|
|
289
|
+
from kerykeion.utilities import setup_logging
|
|
290
|
+
|
|
291
|
+
setup_logging(level="critical")
|
|
292
|
+
|
|
293
|
+
john = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB", lng=53.416666, lat=-3, tz_str="Europe/London")
|
|
294
|
+
yoko = AstrologicalSubjectFactory.from_birth_data("Yoko Ono", 1933, 2, 18, 20, 30, "Tokyo", "JP", lng=35.68611, lat=139.7525, tz_str="Asia/Tokyo")
|
|
295
|
+
|
|
296
|
+
factory = RelationshipScoreFactory(john, yoko)
|
|
297
|
+
score = factory.get_relationship_score()
|
|
298
|
+
|
|
299
|
+
# Remove subjects key
|
|
300
|
+
score.subjects = []
|
|
301
|
+
print(score.model_dump_json(indent=4))
|